mellos-mapping 0.22.1 → 0.23.0

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.
@@ -2,8 +2,8 @@
2
2
  import { PassThrough, Writable } from "node:stream";
3
3
 
4
4
  // src/watch/watch.ts
5
- import { realpathSync, statSync as statSync2 } from "node:fs";
6
- import { dirname as dirname7, join as join6 } from "node:path";
5
+ import { realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
6
+ import { dirname as dirname9, join as join8 } from "node:path";
7
7
 
8
8
  // src/domain/types.ts
9
9
  var ok = (value) => ({ ok: true, value });
@@ -234,6 +234,392 @@ function updateNode(map, input2) {
234
234
  return ok({ ...map, nodes: map.nodes.map((n) => n.id === input2.id ? updated : n) });
235
235
  }
236
236
 
237
+ // src/store/project.ts
238
+ import { existsSync, realpathSync } from "node:fs";
239
+ import { dirname, join, resolve } from "node:path";
240
+ import { homedir, tmpdir } from "node:os";
241
+ function resolveProjectDirectory(cwd, stopAt = [homedir(), tmpdir()]) {
242
+ let start = resolve(cwd);
243
+ try {
244
+ start = realpathSync(start);
245
+ } catch {
246
+ }
247
+ let dir = start;
248
+ const boundaries = new Set(stopAt.map((path) => {
249
+ try {
250
+ return realpathSync(path);
251
+ } catch {
252
+ return resolve(path);
253
+ }
254
+ }));
255
+ while (true) {
256
+ if (dir !== start && boundaries.has(dir)) return start;
257
+ if (existsSync(join(dir, ".git")) || existsSync(join(dir, ".mellos", "map.json")) || existsSync(join(dir, ".mellos", "pages"))) return dir;
258
+ const parent = dirname(dir);
259
+ if (parent === dir) return start;
260
+ dir = parent;
261
+ }
262
+ }
263
+
264
+ // src/store/transaction.ts
265
+ import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
266
+ import { dirname as dirname2, join as join2 } from "node:path";
267
+ import { randomUUID, createHash } from "node:crypto";
268
+
269
+ // src/domain/context.ts
270
+ function sourceError(raw) {
271
+ if (!Array.isArray(raw) || raw.length > 100) return "sources must be an array of at most 100 file references";
272
+ for (const item of raw) {
273
+ if (!item || typeof item !== "object" || Array.isArray(item)) return "source must be an object";
274
+ const s = item;
275
+ if (Object.keys(s).some((k) => k !== "path" && k !== "sha256")) return "unknown source field";
276
+ if (typeof s.path !== "string" || s.path.length > 1024 || !s.path || /[\u0000-\u001f\u007f-\u009f\\:]/.test(s.path) || s.path.startsWith("/") || s.path.split("/").some((p) => !p || p === "." || p === "..")) return "source path must be relative to the project, with forward slashes and no traversal";
277
+ if (s.sha256 !== void 0 && (typeof s.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(s.sha256))) return "source sha256 must be a lowercase SHA256 hash";
278
+ }
279
+ return void 0;
280
+ }
281
+ function contextError(raw) {
282
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return "context must be an object";
283
+ for (const [key, value] of Object.entries(raw)) {
284
+ if (key !== "summary" && key !== "next") return "unknown context field";
285
+ if (typeof value !== "string" || value.length > 2e3 || /[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/.test(value)) return "context fields must be text of at most 2000 characters";
286
+ }
287
+ return void 0;
288
+ }
289
+
290
+ // src/domain/text.ts
291
+ var NO_CONTROLS = /^[^\u0000-\u001f\u007f-\u009f]*$/;
292
+ var NO_CONTROLS_TEXT = "one line of text; control characters (ESC, newline, tab) are not allowed";
293
+ var NO_CONTROLS_BUT_BREAKS = /^[^\u0000-\u0008\u000b-\u001f\u007f-\u009f]*$/;
294
+ var NO_CONTROLS_BUT_BREAKS_TEXT = "text with optional newlines (\\n) and tabs; other control characters (ESC, BEL, CR) are not allowed";
295
+ function mapTextError(map) {
296
+ if (map.context !== void 0) {
297
+ const error2 = contextError(map.context);
298
+ if (error2) return error2;
299
+ }
300
+ const check = (field, value, multiline = false) => value === void 0 || (multiline ? NO_CONTROLS_BUT_BREAKS : NO_CONTROLS).test(value) ? void 0 : `${field}: ${multiline ? NO_CONTROLS_BUT_BREAKS_TEXT : NO_CONTROLS_TEXT}`;
301
+ let error = check("title", map.title);
302
+ if (error) return error;
303
+ for (const [i, layer] of map.layers.entries()) {
304
+ error = check(`layers[${i}].name`, layer.name);
305
+ if (error) return error;
306
+ }
307
+ for (const name of ["lanes", "groups"]) {
308
+ for (const [i, item] of map[name].entries()) {
309
+ error = check(`${name}[${i}].label`, item.label);
310
+ if (error) return error;
311
+ }
312
+ }
313
+ for (const [i, node] of map.nodes.entries()) {
314
+ if (node.sources !== void 0) {
315
+ const error2 = sourceError(node.sources);
316
+ if (error2) return `nodes[${i}]: ${error2}`;
317
+ }
318
+ for (const name of ["label", "evidence", "detail"]) {
319
+ error = check(`nodes[${i}].${name}`, node[name], name !== "label");
320
+ if (error) return error;
321
+ }
322
+ }
323
+ for (const [i, edge] of map.edges.entries()) {
324
+ error = check(`edges[${i}].label`, edge.label);
325
+ if (error) return error;
326
+ }
327
+ return void 0;
328
+ }
329
+ function terminalText(text, multiline = false) {
330
+ return text.replace(multiline ? /[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g : /[\u0000-\u001f\u007f-\u009f]/g, "?");
331
+ }
332
+
333
+ // src/store/format.ts
334
+ var STATE_FILE_VERSION = 1;
335
+ function makePageId(raw) {
336
+ return ID_RULE.test(raw) ? ok(raw) : err({ kind: "invalid-id", raw, rule: ID_RULE_TEXT });
337
+ }
338
+ function describeStoreError(e) {
339
+ switch (e.kind) {
340
+ case "not-found":
341
+ return `no map file at ${e.path}`;
342
+ case "malformed-json":
343
+ return `map file ${e.path} is not valid JSON: ${e.detail}`;
344
+ case "bad-shape":
345
+ return `map file ${e.path} has an unexpected shape: ${e.detail}`;
346
+ case "invariant-violation":
347
+ return `map file ${e.path} violates a structural invariant: ${describeMapError(e.violation)}`;
348
+ case "save-failed":
349
+ return `could not write ${e.path}: ${e.detail}`;
350
+ case "delete-failed":
351
+ return `could not delete ${e.path}: ${e.detail}`;
352
+ }
353
+ }
354
+ function isRecord(v) {
355
+ return typeof v === "object" && v !== null && !Array.isArray(v);
356
+ }
357
+ function describeValue(v) {
358
+ if (v === void 0) return "missing";
359
+ if (v === null) return "null";
360
+ if (Array.isArray(v)) return "an array";
361
+ return `a ${typeof v}`;
362
+ }
363
+ function badShape(path, where, expected, got) {
364
+ return err({ kind: "bad-shape", path, detail: `${where} is ${describeValue(got)}, expected ${expected}` });
365
+ }
366
+ function arrayField(raw, key, path, presence) {
367
+ const v = raw[key];
368
+ if (Array.isArray(v)) return ok(v);
369
+ if (v === void 0 && presence === "optional") return ok([]);
370
+ return badShape(path, `"${key}"`, "an array", v);
371
+ }
372
+ function requiredString(rec, key, where, path) {
373
+ const v = rec[key];
374
+ return typeof v === "string" ? ok(v) : badShape(path, `${where}.${key}`, "a string", v);
375
+ }
376
+ function optionalString(rec, key, where, path) {
377
+ const v = rec[key];
378
+ if (v === void 0) return ok(void 0);
379
+ return typeof v === "string" ? ok(v) : badShape(path, `${where}.${key}`, "a string", v);
380
+ }
381
+ function parseMap(raw, path) {
382
+ if (!isRecord(raw)) return err({ kind: "bad-shape", path, detail: "root is not an object" });
383
+ if (raw["version"] !== STATE_FILE_VERSION && raw["version"] !== 2) {
384
+ return err({ kind: "bad-shape", path, detail: `version is ${String(raw["version"])}, expected ${STATE_FILE_VERSION} or 2` });
385
+ }
386
+ const layers = arrayField(raw, "layers", path, "required");
387
+ if (!layers.ok) return layers;
388
+ const nodes = arrayField(raw, "nodes", path, "required");
389
+ if (!nodes.ok) return nodes;
390
+ const edges = arrayField(raw, "edges", path, "required");
391
+ if (!edges.ok) return edges;
392
+ const lanes = arrayField(raw, "lanes", path, "optional");
393
+ if (!lanes.ok) return lanes;
394
+ const groups = arrayField(raw, "groups", path, "optional");
395
+ if (!groups.ok) return groups;
396
+ let map = EMPTY_MAP;
397
+ if (raw["context"] !== void 0) {
398
+ const error = contextError(raw["context"]);
399
+ if (error) return err({ kind: "bad-shape", path, detail: error });
400
+ map = { ...map, context: raw["context"] };
401
+ }
402
+ const title = optionalString(raw, "title", "map", path);
403
+ if (!title.ok) return title;
404
+ if (title.value !== void 0) map = setTitle(map, title.value);
405
+ const rawKind = optionalString(raw, "kind", "map", path);
406
+ if (!rawKind.ok) return rawKind;
407
+ if (rawKind.value !== void 0) {
408
+ const kind = makeMapKind(rawKind.value);
409
+ if (!kind.ok) return err({ kind: "invariant-violation", path, violation: kind.error });
410
+ map = setKind(map, kind.value);
411
+ }
412
+ for (const [i, rawLayer] of layers.value.entries()) {
413
+ const where = `layers[${i}]`;
414
+ if (!isRecord(rawLayer)) return badShape(path, where, "an object", rawLayer);
415
+ const rawId = requiredString(rawLayer, "id", where, path);
416
+ if (!rawId.ok) return rawId;
417
+ const id = makeLayerId(rawId.value);
418
+ if (!id.ok) return err({ kind: "invariant-violation", path, violation: id.error });
419
+ const name = requiredString(rawLayer, "name", where, path);
420
+ if (!name.ok) return name;
421
+ const rawRank = rawLayer["rank"];
422
+ if (typeof rawRank !== "number") return badShape(path, `${where}.rank`, "a number", rawRank);
423
+ const rank = makeRank(rawRank);
424
+ if (!rank.ok) return err({ kind: "invariant-violation", path, violation: rank.error });
425
+ const next = declareLayer(map, { id: id.value, name: name.value, rank: rank.value });
426
+ if (!next.ok) return err({ kind: "invariant-violation", path, violation: next.error });
427
+ map = next.value;
428
+ }
429
+ for (const [i, rawLane] of lanes.value.entries()) {
430
+ const where = `lanes[${i}]`;
431
+ if (!isRecord(rawLane)) return badShape(path, where, "an object", rawLane);
432
+ const rawId = requiredString(rawLane, "id", where, path);
433
+ if (!rawId.ok) return rawId;
434
+ const id = makeLaneId(rawId.value);
435
+ if (!id.ok) return err({ kind: "invariant-violation", path, violation: id.error });
436
+ const label = requiredString(rawLane, "label", where, path);
437
+ if (!label.ok) return label;
438
+ const declared = declareLane(map, { id: id.value, label: label.value });
439
+ if (!declared.ok) return err({ kind: "invariant-violation", path, violation: declared.error });
440
+ map = declared.value;
441
+ }
442
+ for (const [i, rawGroup] of groups.value.entries()) {
443
+ const where = `groups[${i}]`;
444
+ if (!isRecord(rawGroup)) return badShape(path, where, "an object", rawGroup);
445
+ const rawId = requiredString(rawGroup, "id", where, path);
446
+ if (!rawId.ok) return rawId;
447
+ const id = makeGroupId(rawId.value);
448
+ if (!id.ok) return err({ kind: "invariant-violation", path, violation: id.error });
449
+ const rawLayer = requiredString(rawGroup, "layer", where, path);
450
+ if (!rawLayer.ok) return rawLayer;
451
+ const layer = makeLayerId(rawLayer.value);
452
+ if (!layer.ok) return err({ kind: "invariant-violation", path, violation: layer.error });
453
+ const label = requiredString(rawGroup, "label", where, path);
454
+ if (!label.ok) return label;
455
+ const declared = declareGroup(map, { id: id.value, label: label.value, layer: layer.value });
456
+ if (!declared.ok) return err({ kind: "invariant-violation", path, violation: declared.error });
457
+ map = declared.value;
458
+ }
459
+ for (const [i, rawNode] of nodes.value.entries()) {
460
+ const where = `nodes[${i}]`;
461
+ if (!isRecord(rawNode)) return badShape(path, where, "an object", rawNode);
462
+ const rawId = requiredString(rawNode, "id", where, path);
463
+ if (!rawId.ok) return rawId;
464
+ const id = makeNodeId(rawId.value);
465
+ if (!id.ok) return err({ kind: "invariant-violation", path, violation: id.error });
466
+ const rawLayer = requiredString(rawNode, "layer", where, path);
467
+ if (!rawLayer.ok) return rawLayer;
468
+ const layer = makeLayerId(rawLayer.value);
469
+ if (!layer.ok) return err({ kind: "invariant-violation", path, violation: layer.error });
470
+ const rawStatus = requiredString(rawNode, "status", where, path);
471
+ if (!rawStatus.ok) return rawStatus;
472
+ const status = makeNodeStatus(rawStatus.value);
473
+ if (!status.ok) return err({ kind: "invariant-violation", path, violation: status.error });
474
+ const label = requiredString(rawNode, "label", where, path);
475
+ if (!label.ok) return label;
476
+ const detail = optionalString(rawNode, "detail", where, path);
477
+ if (!detail.ok) return detail;
478
+ const rawGroup = optionalString(rawNode, "group", where, path);
479
+ if (!rawGroup.ok) return rawGroup;
480
+ let group;
481
+ if (rawGroup.value !== void 0) {
482
+ const made = makeGroupId(rawGroup.value);
483
+ if (!made.ok) return err({ kind: "invariant-violation", path, violation: made.error });
484
+ group = made.value;
485
+ }
486
+ const rawNodeKind = optionalString(rawNode, "kind", where, path);
487
+ if (!rawNodeKind.ok) return rawNodeKind;
488
+ let nodeKind;
489
+ if (rawNodeKind.value !== void 0) {
490
+ const made = makeNodeKind(rawNodeKind.value);
491
+ if (!made.ok) return err({ kind: "invariant-violation", path, violation: made.error });
492
+ nodeKind = made.value;
493
+ }
494
+ const rawLane = optionalString(rawNode, "lane", where, path);
495
+ if (!rawLane.ok) return rawLane;
496
+ let lane;
497
+ if (rawLane.value !== void 0) {
498
+ const made = makeLaneId(rawLane.value);
499
+ if (!made.ok) return err({ kind: "invariant-violation", path, violation: made.error });
500
+ lane = made.value;
501
+ }
502
+ const rawSubmap = optionalString(rawNode, "submap", where, path);
503
+ if (!rawSubmap.ok) return rawSubmap;
504
+ let submap;
505
+ if (rawSubmap.value !== void 0) {
506
+ const made = makeSubmapRef(rawSubmap.value);
507
+ if (!made.ok) return err({ kind: "invariant-violation", path, violation: made.error });
508
+ submap = made.value;
509
+ }
510
+ const declared = declareNode(map, {
511
+ id: id.value,
512
+ label: label.value,
513
+ layer: layer.value,
514
+ status: status.value,
515
+ ...detail.value !== void 0 ? { detail: detail.value } : {},
516
+ ...group !== void 0 ? { group } : {},
517
+ ...nodeKind !== void 0 ? { kind: nodeKind } : {},
518
+ ...lane !== void 0 ? { lane } : {},
519
+ ...submap !== void 0 ? { submap } : {}
520
+ });
521
+ if (!declared.ok) return err({ kind: "invariant-violation", path, violation: declared.error });
522
+ map = declared.value;
523
+ const evidence = optionalString(rawNode, "evidence", where, path);
524
+ if (!evidence.ok) return evidence;
525
+ if (evidence.value !== void 0) {
526
+ const updated = updateNode(map, { id: id.value, evidence: evidence.value });
527
+ if (!updated.ok) return err({ kind: "invariant-violation", path, violation: updated.error });
528
+ map = updated.value;
529
+ }
530
+ if (rawNode["sources"] !== void 0) {
531
+ const error = sourceError(rawNode["sources"]);
532
+ if (error) return err({ kind: "bad-shape", path, detail: `${where}: ${error}` });
533
+ map = { ...map, nodes: map.nodes.map((n) => n.id === id.value ? { ...n, sources: rawNode["sources"] } : n) };
534
+ }
535
+ }
536
+ for (const [i, rawEdge] of edges.value.entries()) {
537
+ const where = `edges[${i}]`;
538
+ if (!isRecord(rawEdge)) return badShape(path, where, "an object", rawEdge);
539
+ const rawFrom = requiredString(rawEdge, "from", where, path);
540
+ if (!rawFrom.ok) return rawFrom;
541
+ const from = makeNodeId(rawFrom.value);
542
+ if (!from.ok) return err({ kind: "invariant-violation", path, violation: from.error });
543
+ const rawTo = requiredString(rawEdge, "to", where, path);
544
+ if (!rawTo.ok) return rawTo;
545
+ const to = makeNodeId(rawTo.value);
546
+ if (!to.ok) return err({ kind: "invariant-violation", path, violation: to.error });
547
+ const label = optionalString(rawEdge, "label", where, path);
548
+ if (!label.ok) return label;
549
+ const linked = linkNodes(map, from.value, to.value, label.value);
550
+ if (!linked.ok) return err({ kind: "invariant-violation", path, violation: linked.error });
551
+ map = linked.value;
552
+ }
553
+ const textError = mapTextError(map);
554
+ return textError ? err({ kind: "bad-shape", path, detail: textError }) : ok(map);
555
+ }
556
+
557
+ // src/store/transaction.ts
558
+ var LedgerError = class extends Error {
559
+ constructor(code, message, details = {}) {
560
+ super(message);
561
+ this.code = code;
562
+ this.details = details;
563
+ }
564
+ };
565
+ function storeDirectory(file) {
566
+ const dir = dirname2(file);
567
+ return dir.endsWith("/pages") || dir.endsWith("\\pages") ? dirname2(dir) : dir;
568
+ }
569
+ function deadOwner(lock) {
570
+ try {
571
+ const owner = JSON.parse(readFileSync(join2(lock, "owner.json"), "utf8"));
572
+ if (!Number.isSafeInteger(owner.pid) || owner.pid <= 0) return false;
573
+ try {
574
+ process.kill(owner.pid, 0);
575
+ return false;
576
+ } catch (e) {
577
+ return e.code === "ESRCH";
578
+ }
579
+ } catch {
580
+ return false;
581
+ }
582
+ }
583
+ function withStoreLock(file, action) {
584
+ const dir = storeDirectory(file);
585
+ mkdirSync(dir, { recursive: true });
586
+ const lock = join2(dir, ".write-lock");
587
+ const owner = join2(lock, "owner.json");
588
+ const token = randomUUID();
589
+ try {
590
+ mkdirSync(lock);
591
+ } catch (error) {
592
+ if (error.code !== "EEXIST") throw error;
593
+ if (!deadOwner(lock)) throw new LedgerError("BUSY", `Another writer owns ${lock}; retry after it completes. An orphan without owner metadata needs manual inspection.`);
594
+ try {
595
+ mkdirSync(join2(lock, ".reap"));
596
+ } catch {
597
+ throw new LedgerError("BUSY", "Another process is recovering the writer lock.");
598
+ }
599
+ if (!deadOwner(lock)) {
600
+ rmSync(join2(lock, ".reap"), { recursive: true, force: true });
601
+ throw new LedgerError("BUSY", "Writer ownership changed.");
602
+ }
603
+ rmSync(lock, { recursive: true });
604
+ try {
605
+ mkdirSync(lock);
606
+ } catch {
607
+ throw new LedgerError("BUSY", "Another writer acquired the recovered lock.");
608
+ }
609
+ }
610
+ let initialized = false;
611
+ try {
612
+ writeFileSync(owner, JSON.stringify({ pid: process.pid, token }), { flag: "wx" });
613
+ initialized = true;
614
+ return action();
615
+ } finally {
616
+ try {
617
+ if (!initialized || JSON.parse(readFileSync(owner, "utf8")).token === token) rmSync(lock, { recursive: true });
618
+ } catch {
619
+ }
620
+ }
621
+ }
622
+
237
623
  // src/semantics/vocabulary.ts
238
624
  var STATUS_GLYPHS = {
239
625
  planned: ["\xB7", "."],
@@ -478,41 +864,6 @@ function flipForSequence(map) {
478
864
  };
479
865
  }
480
866
 
481
- // src/domain/text.ts
482
- var NO_CONTROLS = /^[^\u0000-\u001f\u007f-\u009f]*$/;
483
- var NO_CONTROLS_TEXT = "one line of text; control characters (ESC, newline, tab) are not allowed";
484
- var NO_CONTROLS_BUT_BREAKS = /^[^\u0000-\u0008\u000b-\u001f\u007f-\u009f]*$/;
485
- var NO_CONTROLS_BUT_BREAKS_TEXT = "text with optional newlines (\\n) and tabs; other control characters (ESC, BEL, CR) are not allowed";
486
- function mapTextError(map) {
487
- const check = (field, value, multiline = false) => value === void 0 || (multiline ? NO_CONTROLS_BUT_BREAKS : NO_CONTROLS).test(value) ? void 0 : `${field}: ${multiline ? NO_CONTROLS_BUT_BREAKS_TEXT : NO_CONTROLS_TEXT}`;
488
- let error = check("title", map.title);
489
- if (error) return error;
490
- for (const [i, layer] of map.layers.entries()) {
491
- error = check(`layers[${i}].name`, layer.name);
492
- if (error) return error;
493
- }
494
- for (const name of ["lanes", "groups"]) {
495
- for (const [i, item] of map[name].entries()) {
496
- error = check(`${name}[${i}].label`, item.label);
497
- if (error) return error;
498
- }
499
- }
500
- for (const [i, node] of map.nodes.entries()) {
501
- for (const name of ["label", "evidence", "detail"]) {
502
- error = check(`nodes[${i}].${name}`, node[name], name !== "label");
503
- if (error) return error;
504
- }
505
- }
506
- for (const [i, edge] of map.edges.entries()) {
507
- error = check(`edges[${i}].label`, edge.label);
508
- if (error) return error;
509
- }
510
- return void 0;
511
- }
512
- function terminalText(text, multiline = false) {
513
- return text.replace(multiline ? /[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g : /[\u0000-\u001f\u007f-\u009f]/g, "?");
514
- }
515
-
516
867
  // src/render/width.ts
517
868
  var WIDE_RANGES = [
518
869
  [4352, 4447],
@@ -1396,223 +1747,9 @@ function paint(scene, opts) {
1396
1747
  return { canvas, hits };
1397
1748
  }
1398
1749
 
1399
- // src/store/format.ts
1400
- var STATE_FILE_VERSION = 1;
1401
- function makePageId(raw) {
1402
- return ID_RULE.test(raw) ? ok(raw) : err({ kind: "invalid-id", raw, rule: ID_RULE_TEXT });
1403
- }
1404
- function describeStoreError(e) {
1405
- switch (e.kind) {
1406
- case "not-found":
1407
- return `no map file at ${e.path}`;
1408
- case "malformed-json":
1409
- return `map file ${e.path} is not valid JSON: ${e.detail}`;
1410
- case "bad-shape":
1411
- return `map file ${e.path} has an unexpected shape: ${e.detail}`;
1412
- case "invariant-violation":
1413
- return `map file ${e.path} violates a structural invariant: ${describeMapError(e.violation)}`;
1414
- case "save-failed":
1415
- return `could not write ${e.path}: ${e.detail}`;
1416
- case "delete-failed":
1417
- return `could not delete ${e.path}: ${e.detail}`;
1418
- }
1419
- }
1420
- function isRecord(v) {
1421
- return typeof v === "object" && v !== null && !Array.isArray(v);
1422
- }
1423
- function describeValue(v) {
1424
- if (v === void 0) return "missing";
1425
- if (v === null) return "null";
1426
- if (Array.isArray(v)) return "an array";
1427
- return `a ${typeof v}`;
1428
- }
1429
- function badShape(path, where, expected, got) {
1430
- return err({ kind: "bad-shape", path, detail: `${where} is ${describeValue(got)}, expected ${expected}` });
1431
- }
1432
- function arrayField(raw, key, path, presence) {
1433
- const v = raw[key];
1434
- if (Array.isArray(v)) return ok(v);
1435
- if (v === void 0 && presence === "optional") return ok([]);
1436
- return badShape(path, `"${key}"`, "an array", v);
1437
- }
1438
- function requiredString(rec, key, where, path) {
1439
- const v = rec[key];
1440
- return typeof v === "string" ? ok(v) : badShape(path, `${where}.${key}`, "a string", v);
1441
- }
1442
- function optionalString(rec, key, where, path) {
1443
- const v = rec[key];
1444
- if (v === void 0) return ok(void 0);
1445
- return typeof v === "string" ? ok(v) : badShape(path, `${where}.${key}`, "a string", v);
1446
- }
1447
- function parseMap(raw, path) {
1448
- if (!isRecord(raw)) return err({ kind: "bad-shape", path, detail: "root is not an object" });
1449
- if (raw["version"] !== STATE_FILE_VERSION) {
1450
- return err({ kind: "bad-shape", path, detail: `version is ${String(raw["version"])}, expected ${STATE_FILE_VERSION}` });
1451
- }
1452
- const layers = arrayField(raw, "layers", path, "required");
1453
- if (!layers.ok) return layers;
1454
- const nodes = arrayField(raw, "nodes", path, "required");
1455
- if (!nodes.ok) return nodes;
1456
- const edges = arrayField(raw, "edges", path, "required");
1457
- if (!edges.ok) return edges;
1458
- const lanes = arrayField(raw, "lanes", path, "optional");
1459
- if (!lanes.ok) return lanes;
1460
- const groups = arrayField(raw, "groups", path, "optional");
1461
- if (!groups.ok) return groups;
1462
- let map = EMPTY_MAP;
1463
- const title = optionalString(raw, "title", "map", path);
1464
- if (!title.ok) return title;
1465
- if (title.value !== void 0) map = setTitle(map, title.value);
1466
- const rawKind = optionalString(raw, "kind", "map", path);
1467
- if (!rawKind.ok) return rawKind;
1468
- if (rawKind.value !== void 0) {
1469
- const kind = makeMapKind(rawKind.value);
1470
- if (!kind.ok) return err({ kind: "invariant-violation", path, violation: kind.error });
1471
- map = setKind(map, kind.value);
1472
- }
1473
- for (const [i, rawLayer] of layers.value.entries()) {
1474
- const where = `layers[${i}]`;
1475
- if (!isRecord(rawLayer)) return badShape(path, where, "an object", rawLayer);
1476
- const rawId = requiredString(rawLayer, "id", where, path);
1477
- if (!rawId.ok) return rawId;
1478
- const id = makeLayerId(rawId.value);
1479
- if (!id.ok) return err({ kind: "invariant-violation", path, violation: id.error });
1480
- const name = requiredString(rawLayer, "name", where, path);
1481
- if (!name.ok) return name;
1482
- const rawRank = rawLayer["rank"];
1483
- if (typeof rawRank !== "number") return badShape(path, `${where}.rank`, "a number", rawRank);
1484
- const rank = makeRank(rawRank);
1485
- if (!rank.ok) return err({ kind: "invariant-violation", path, violation: rank.error });
1486
- const next = declareLayer(map, { id: id.value, name: name.value, rank: rank.value });
1487
- if (!next.ok) return err({ kind: "invariant-violation", path, violation: next.error });
1488
- map = next.value;
1489
- }
1490
- for (const [i, rawLane] of lanes.value.entries()) {
1491
- const where = `lanes[${i}]`;
1492
- if (!isRecord(rawLane)) return badShape(path, where, "an object", rawLane);
1493
- const rawId = requiredString(rawLane, "id", where, path);
1494
- if (!rawId.ok) return rawId;
1495
- const id = makeLaneId(rawId.value);
1496
- if (!id.ok) return err({ kind: "invariant-violation", path, violation: id.error });
1497
- const label = requiredString(rawLane, "label", where, path);
1498
- if (!label.ok) return label;
1499
- const declared = declareLane(map, { id: id.value, label: label.value });
1500
- if (!declared.ok) return err({ kind: "invariant-violation", path, violation: declared.error });
1501
- map = declared.value;
1502
- }
1503
- for (const [i, rawGroup] of groups.value.entries()) {
1504
- const where = `groups[${i}]`;
1505
- if (!isRecord(rawGroup)) return badShape(path, where, "an object", rawGroup);
1506
- const rawId = requiredString(rawGroup, "id", where, path);
1507
- if (!rawId.ok) return rawId;
1508
- const id = makeGroupId(rawId.value);
1509
- if (!id.ok) return err({ kind: "invariant-violation", path, violation: id.error });
1510
- const rawLayer = requiredString(rawGroup, "layer", where, path);
1511
- if (!rawLayer.ok) return rawLayer;
1512
- const layer = makeLayerId(rawLayer.value);
1513
- if (!layer.ok) return err({ kind: "invariant-violation", path, violation: layer.error });
1514
- const label = requiredString(rawGroup, "label", where, path);
1515
- if (!label.ok) return label;
1516
- const declared = declareGroup(map, { id: id.value, label: label.value, layer: layer.value });
1517
- if (!declared.ok) return err({ kind: "invariant-violation", path, violation: declared.error });
1518
- map = declared.value;
1519
- }
1520
- for (const [i, rawNode] of nodes.value.entries()) {
1521
- const where = `nodes[${i}]`;
1522
- if (!isRecord(rawNode)) return badShape(path, where, "an object", rawNode);
1523
- const rawId = requiredString(rawNode, "id", where, path);
1524
- if (!rawId.ok) return rawId;
1525
- const id = makeNodeId(rawId.value);
1526
- if (!id.ok) return err({ kind: "invariant-violation", path, violation: id.error });
1527
- const rawLayer = requiredString(rawNode, "layer", where, path);
1528
- if (!rawLayer.ok) return rawLayer;
1529
- const layer = makeLayerId(rawLayer.value);
1530
- if (!layer.ok) return err({ kind: "invariant-violation", path, violation: layer.error });
1531
- const rawStatus = requiredString(rawNode, "status", where, path);
1532
- if (!rawStatus.ok) return rawStatus;
1533
- const status = makeNodeStatus(rawStatus.value);
1534
- if (!status.ok) return err({ kind: "invariant-violation", path, violation: status.error });
1535
- const label = requiredString(rawNode, "label", where, path);
1536
- if (!label.ok) return label;
1537
- const detail = optionalString(rawNode, "detail", where, path);
1538
- if (!detail.ok) return detail;
1539
- const rawGroup = optionalString(rawNode, "group", where, path);
1540
- if (!rawGroup.ok) return rawGroup;
1541
- let group;
1542
- if (rawGroup.value !== void 0) {
1543
- const made = makeGroupId(rawGroup.value);
1544
- if (!made.ok) return err({ kind: "invariant-violation", path, violation: made.error });
1545
- group = made.value;
1546
- }
1547
- const rawNodeKind = optionalString(rawNode, "kind", where, path);
1548
- if (!rawNodeKind.ok) return rawNodeKind;
1549
- let nodeKind;
1550
- if (rawNodeKind.value !== void 0) {
1551
- const made = makeNodeKind(rawNodeKind.value);
1552
- if (!made.ok) return err({ kind: "invariant-violation", path, violation: made.error });
1553
- nodeKind = made.value;
1554
- }
1555
- const rawLane = optionalString(rawNode, "lane", where, path);
1556
- if (!rawLane.ok) return rawLane;
1557
- let lane;
1558
- if (rawLane.value !== void 0) {
1559
- const made = makeLaneId(rawLane.value);
1560
- if (!made.ok) return err({ kind: "invariant-violation", path, violation: made.error });
1561
- lane = made.value;
1562
- }
1563
- const rawSubmap = optionalString(rawNode, "submap", where, path);
1564
- if (!rawSubmap.ok) return rawSubmap;
1565
- let submap;
1566
- if (rawSubmap.value !== void 0) {
1567
- const made = makeSubmapRef(rawSubmap.value);
1568
- if (!made.ok) return err({ kind: "invariant-violation", path, violation: made.error });
1569
- submap = made.value;
1570
- }
1571
- const declared = declareNode(map, {
1572
- id: id.value,
1573
- label: label.value,
1574
- layer: layer.value,
1575
- status: status.value,
1576
- ...detail.value !== void 0 ? { detail: detail.value } : {},
1577
- ...group !== void 0 ? { group } : {},
1578
- ...nodeKind !== void 0 ? { kind: nodeKind } : {},
1579
- ...lane !== void 0 ? { lane } : {},
1580
- ...submap !== void 0 ? { submap } : {}
1581
- });
1582
- if (!declared.ok) return err({ kind: "invariant-violation", path, violation: declared.error });
1583
- map = declared.value;
1584
- const evidence = optionalString(rawNode, "evidence", where, path);
1585
- if (!evidence.ok) return evidence;
1586
- if (evidence.value !== void 0) {
1587
- const updated = updateNode(map, { id: id.value, evidence: evidence.value });
1588
- if (!updated.ok) return err({ kind: "invariant-violation", path, violation: updated.error });
1589
- map = updated.value;
1590
- }
1591
- }
1592
- for (const [i, rawEdge] of edges.value.entries()) {
1593
- const where = `edges[${i}]`;
1594
- if (!isRecord(rawEdge)) return badShape(path, where, "an object", rawEdge);
1595
- const rawFrom = requiredString(rawEdge, "from", where, path);
1596
- if (!rawFrom.ok) return rawFrom;
1597
- const from = makeNodeId(rawFrom.value);
1598
- if (!from.ok) return err({ kind: "invariant-violation", path, violation: from.error });
1599
- const rawTo = requiredString(rawEdge, "to", where, path);
1600
- if (!rawTo.ok) return rawTo;
1601
- const to = makeNodeId(rawTo.value);
1602
- if (!to.ok) return err({ kind: "invariant-violation", path, violation: to.error });
1603
- const label = optionalString(rawEdge, "label", where, path);
1604
- if (!label.ok) return label;
1605
- const linked = linkNodes(map, from.value, to.value, label.value);
1606
- if (!linked.ok) return err({ kind: "invariant-violation", path, violation: linked.error });
1607
- map = linked.value;
1608
- }
1609
- const textError = mapTextError(map);
1610
- return textError ? err({ kind: "bad-shape", path, detail: textError }) : ok(map);
1611
- }
1612
-
1613
1750
  // src/store/atomic.ts
1614
- import { mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
1615
- import { dirname } from "node:path";
1751
+ import { mkdirSync as mkdirSync2, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
1752
+ import { dirname as dirname3 } from "node:path";
1616
1753
  var RENAME_BACKOFF_STEP_MS = 10;
1617
1754
  var TRANSIENT_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES", "ENOENT"]);
1618
1755
  function sleepSync(ms) {
@@ -1620,7 +1757,7 @@ function sleepSync(ms) {
1620
1757
  }
1621
1758
  function discardTemp(tmp) {
1622
1759
  try {
1623
- rmSync(tmp, { force: true });
1760
+ rmSync2(tmp, { force: true });
1624
1761
  } catch {
1625
1762
  }
1626
1763
  }
@@ -1630,8 +1767,8 @@ function errnoOf(e) {
1630
1767
  function writeAtomic(path, contents, maxAttempts) {
1631
1768
  const tmp = `${path}.${process.pid}.${Math.random().toString(36).slice(2, 10)}.tmp`;
1632
1769
  try {
1633
- mkdirSync(dirname(path), { recursive: true });
1634
- writeFileSync(tmp, contents, "utf8");
1770
+ mkdirSync2(dirname3(path), { recursive: true });
1771
+ writeFileSync2(tmp, contents, "utf8");
1635
1772
  } catch (e) {
1636
1773
  discardTemp(tmp);
1637
1774
  return err({ kind: "save-failed", path, detail: `writing the temp file failed: ${errnoOf(e)}` });
@@ -1654,13 +1791,13 @@ function writeAtomic(path, contents, maxAttempts) {
1654
1791
  }
1655
1792
 
1656
1793
  // src/store/pages.ts
1657
- import { existsSync, readdirSync, rmSync as rmSync2 } from "node:fs";
1658
- import { basename, dirname as dirname2, join } from "node:path";
1794
+ import { existsSync as existsSync2, readdirSync, rmSync as rmSync3 } from "node:fs";
1795
+ import { basename, dirname as dirname4, join as join3 } from "node:path";
1659
1796
  var STORE_DIR_NAME = ".mellos";
1660
- var STATE_FILE_RELATIVE_PATH = join(STORE_DIR_NAME, "map.json");
1797
+ var STATE_FILE_RELATIVE_PATH = join3(STORE_DIR_NAME, "map.json");
1661
1798
  var PAGES_DIR_NAME = "pages";
1662
1799
  function pageFilePath(defaultFile, page) {
1663
- return page === void 0 ? defaultFile : join(dirname2(defaultFile), PAGES_DIR_NAME, `${page}.json`);
1800
+ return page === void 0 ? defaultFile : join3(dirname4(defaultFile), PAGES_DIR_NAME, `${page}.json`);
1664
1801
  }
1665
1802
  function pageIdOfFile(defaultFile, path) {
1666
1803
  if (path === defaultFile) return void 0;
@@ -1669,20 +1806,20 @@ function pageIdOfFile(defaultFile, path) {
1669
1806
  }
1670
1807
  function listPageFiles(defaultFile) {
1671
1808
  const out = [];
1672
- if (existsSync(defaultFile)) out.push(defaultFile);
1809
+ if (existsSync2(defaultFile)) out.push(defaultFile);
1673
1810
  let entries = [];
1674
1811
  try {
1675
- entries = readdirSync(join(dirname2(defaultFile), PAGES_DIR_NAME));
1812
+ entries = readdirSync(join3(dirname4(defaultFile), PAGES_DIR_NAME));
1676
1813
  } catch {
1677
1814
  }
1678
1815
  for (const e of entries.sort()) {
1679
- if (e.endsWith(".json")) out.push(join(dirname2(defaultFile), PAGES_DIR_NAME, e));
1816
+ if (e.endsWith(".json")) out.push(join3(dirname4(defaultFile), PAGES_DIR_NAME, e));
1680
1817
  }
1681
1818
  return out;
1682
1819
  }
1683
1820
  function deletePageFile(path) {
1684
1821
  try {
1685
- rmSync2(path, { force: true });
1822
+ rmSync3(path, { force: true });
1686
1823
  return ok(void 0);
1687
1824
  } catch (e) {
1688
1825
  return err({ kind: "delete-failed", path, detail: errnoOf(e) });
@@ -1690,8 +1827,8 @@ function deletePageFile(path) {
1690
1827
  }
1691
1828
 
1692
1829
  // src/store/channels.ts
1693
- import { existsSync as existsSync2, readFileSync as readFileSync2, rmSync as rmSync4 } from "node:fs";
1694
- import { dirname as dirname4, join as join3 } from "node:path";
1830
+ import { existsSync as existsSync3, readFileSync as readFileSync3, rmSync as rmSync5 } from "node:fs";
1831
+ import { dirname as dirname6, join as join5 } from "node:path";
1695
1832
 
1696
1833
  // src/store/json-text.ts
1697
1834
  function isRecord2(v) {
@@ -1702,16 +1839,16 @@ function stripBom(text) {
1702
1839
  }
1703
1840
 
1704
1841
  // src/store/viewers.ts
1705
- import { readdirSync as readdirSync2, readFileSync, statSync, rmSync as rmSync3 } from "node:fs";
1706
- import { dirname as dirname3, join as join2 } from "node:path";
1842
+ import { readdirSync as readdirSync2, readFileSync as readFileSync2, statSync, rmSync as rmSync4 } from "node:fs";
1843
+ import { dirname as dirname5, join as join4 } from "node:path";
1707
1844
  var VIEWERS_DIR_NAME = "viewers";
1708
1845
  var VIEWER_FILE_VERSION = 1;
1709
1846
  var VIEWER_HEARTBEAT_MS = 1e3;
1710
1847
  function viewersDirPath(defaultFile) {
1711
- return join2(dirname3(defaultFile), VIEWERS_DIR_NAME);
1848
+ return join4(dirname5(defaultFile), VIEWERS_DIR_NAME);
1712
1849
  }
1713
1850
  function viewerFilePath(defaultFile, pid) {
1714
- return join2(viewersDirPath(defaultFile), `${pid}.json`);
1851
+ return join4(viewersDirPath(defaultFile), `${pid}.json`);
1715
1852
  }
1716
1853
  function publishViewer(defaultFile, pid, report) {
1717
1854
  const body = { version: VIEWER_FILE_VERSION, page: report.page ?? null, follow: report.follow, owner: report.owner };
@@ -1720,7 +1857,7 @@ function publishViewer(defaultFile, pid, report) {
1720
1857
  }
1721
1858
  function retireViewer(defaultFile, pid) {
1722
1859
  try {
1723
- rmSync3(viewerFilePath(defaultFile, pid), { force: true });
1860
+ rmSync4(viewerFilePath(defaultFile, pid), { force: true });
1724
1861
  } catch {
1725
1862
  }
1726
1863
  }
@@ -1731,21 +1868,21 @@ function focusFilePath(defaultFile, pid) {
1731
1868
  return paneChannelPath(defaultFile, FOCUS_FILE_NAME, pid);
1732
1869
  }
1733
1870
  function paneChannelPath(defaultFile, channel, pid) {
1734
- if (pid === void 0) return join3(dirname4(defaultFile), channel);
1871
+ if (pid === void 0) return join5(dirname6(defaultFile), channel);
1735
1872
  if (!Number.isSafeInteger(pid) || pid <= 0) throw new Error("Invalid pane process id");
1736
- return join3(viewersDirPath(defaultFile), `${pid}.${channel}`);
1873
+ return join5(viewersDirPath(defaultFile), `${pid}.${channel}`);
1737
1874
  }
1738
1875
  function takeFocusRequest(defaultFile, pid) {
1739
1876
  const targeted = pid === void 0 ? void 0 : focusFilePath(defaultFile, pid);
1740
- const path = targeted !== void 0 && existsSync2(targeted) ? targeted : focusFilePath(defaultFile);
1877
+ const path = targeted !== void 0 && existsSync3(targeted) ? targeted : focusFilePath(defaultFile);
1741
1878
  let raw;
1742
1879
  try {
1743
- raw = readFileSync2(path, "utf8");
1880
+ raw = readFileSync3(path, "utf8");
1744
1881
  } catch {
1745
1882
  return void 0;
1746
1883
  }
1747
1884
  try {
1748
- rmSync4(path, { force: true });
1885
+ rmSync5(path, { force: true });
1749
1886
  } catch {
1750
1887
  }
1751
1888
  let parsed;
@@ -1767,10 +1904,10 @@ function quitFilePath(defaultFile, pid) {
1767
1904
  }
1768
1905
  function takeQuitRequest(defaultFile, pid) {
1769
1906
  const targeted = pid === void 0 ? void 0 : quitFilePath(defaultFile, pid);
1770
- const path = targeted !== void 0 && existsSync2(targeted) ? targeted : quitFilePath(defaultFile);
1907
+ const path = targeted !== void 0 && existsSync3(targeted) ? targeted : quitFilePath(defaultFile);
1771
1908
  let raw;
1772
1909
  try {
1773
- raw = readFileSync2(path, "utf8");
1910
+ raw = readFileSync3(path, "utf8");
1774
1911
  } catch {
1775
1912
  return false;
1776
1913
  }
@@ -1785,45 +1922,45 @@ function takeQuitRequest(defaultFile, pid) {
1785
1922
  }
1786
1923
  function sweepQuitRequest(defaultFile, pid) {
1787
1924
  try {
1788
- rmSync4(quitFilePath(defaultFile, pid), { force: true });
1925
+ rmSync5(quitFilePath(defaultFile, pid), { force: true });
1789
1926
  } catch {
1790
1927
  }
1791
1928
  }
1792
1929
 
1793
1930
  // src/store/policy.ts
1794
- import { dirname as dirname5, join as join4 } from "node:path";
1931
+ import { dirname as dirname7, join as join6 } from "node:path";
1795
1932
  var CONFIG_FILE_NAME = "config.json";
1796
1933
  function configFilePath(defaultFile) {
1797
- return join4(dirname5(defaultFile), CONFIG_FILE_NAME);
1934
+ return join6(dirname7(defaultFile), CONFIG_FILE_NAME);
1798
1935
  }
1799
1936
 
1800
1937
  // src/store/migration.ts
1801
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, renameSync as renameSync2 } from "node:fs";
1802
- import { dirname as dirname6, join as join5 } from "node:path";
1803
- var LEGACY_STATE_FILE_RELATIVE_PATH = join5(".claude", "mellos-mapping.json");
1938
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, renameSync as renameSync2 } from "node:fs";
1939
+ import { dirname as dirname8, join as join7 } from "node:path";
1940
+ var LEGACY_STATE_FILE_RELATIVE_PATH = join7(".claude", "mellos-mapping.json");
1804
1941
  var LEGACY_PAGES_DIR_NAME = "mellos-mapping.pages";
1805
1942
  var LEGACY_CONFIG_FILE_NAME = "mellos-mapping.config.json";
1806
1943
  function migrateLegacyStore(defaultFile) {
1807
- const projectRoot = dirname6(dirname6(defaultFile));
1808
- const legacyDefault = join5(projectRoot, LEGACY_STATE_FILE_RELATIVE_PATH);
1809
- const legacyPages = join5(dirname6(legacyDefault), LEGACY_PAGES_DIR_NAME);
1810
- const legacyConfig = join5(dirname6(legacyDefault), LEGACY_CONFIG_FILE_NAME);
1811
- const hasLegacy = existsSync3(legacyDefault) || existsSync3(legacyPages) || existsSync3(legacyConfig);
1812
- const hasCurrent = existsSync3(defaultFile) || existsSync3(join5(dirname6(defaultFile), PAGES_DIR_NAME)) || existsSync3(configFilePath(defaultFile));
1944
+ const projectRoot = dirname8(dirname8(defaultFile));
1945
+ const legacyDefault = join7(projectRoot, LEGACY_STATE_FILE_RELATIVE_PATH);
1946
+ const legacyPages = join7(dirname8(legacyDefault), LEGACY_PAGES_DIR_NAME);
1947
+ const legacyConfig = join7(dirname8(legacyDefault), LEGACY_CONFIG_FILE_NAME);
1948
+ const hasLegacy = existsSync4(legacyDefault) || existsSync4(legacyPages) || existsSync4(legacyConfig);
1949
+ const hasCurrent = existsSync4(defaultFile) || existsSync4(join7(dirname8(defaultFile), PAGES_DIR_NAME)) || existsSync4(configFilePath(defaultFile));
1813
1950
  if (!hasLegacy || hasCurrent) return false;
1814
- mkdirSync2(dirname6(defaultFile), { recursive: true });
1815
- if (existsSync3(legacyDefault)) renameSync2(legacyDefault, defaultFile);
1816
- if (existsSync3(legacyPages)) renameSync2(legacyPages, join5(dirname6(defaultFile), PAGES_DIR_NAME));
1817
- if (existsSync3(legacyConfig)) renameSync2(legacyConfig, configFilePath(defaultFile));
1951
+ mkdirSync3(dirname8(defaultFile), { recursive: true });
1952
+ if (existsSync4(legacyDefault)) renameSync2(legacyDefault, defaultFile);
1953
+ if (existsSync4(legacyPages)) renameSync2(legacyPages, join7(dirname8(defaultFile), PAGES_DIR_NAME));
1954
+ if (existsSync4(legacyConfig)) renameSync2(legacyConfig, configFilePath(defaultFile));
1818
1955
  return true;
1819
1956
  }
1820
1957
 
1821
1958
  // src/store/maps.ts
1822
- import { readFileSync as readFileSync3 } from "node:fs";
1959
+ import { readFileSync as readFileSync4 } from "node:fs";
1823
1960
  function loadMapFile(path) {
1824
1961
  let text;
1825
1962
  try {
1826
- text = readFileSync3(path, "utf8");
1963
+ text = readFileSync4(path, "utf8");
1827
1964
  } catch (e) {
1828
1965
  const code = e.code;
1829
1966
  if (code === "ENOENT") return err({ kind: "not-found", path });
@@ -2275,7 +2412,7 @@ function describeArgsError(e) {
2275
2412
  }
2276
2413
  }
2277
2414
  function parseArgs(argv, cwd) {
2278
- let file = join6(cwd, STATE_FILE_RELATIVE_PATH);
2415
+ let file = join8(resolveProjectDirectory(cwd), STATE_FILE_RELATIVE_PATH);
2279
2416
  let intervalMs = POLL_INTERVAL_DEFAULT_MS;
2280
2417
  let unicode = true;
2281
2418
  let color = true;
@@ -2557,7 +2694,7 @@ function waitingInfo(s, width) {
2557
2694
  const clock = s.elapsedMs !== void 0 ? ` \xB7 waiting ${elapsedLabel(s.elapsedMs)}` : "";
2558
2695
  const lines = [
2559
2696
  `watching ${s.defaultFile}`,
2560
- ` and ${join6(s.pagesDir, "*.json")}`,
2697
+ ` and ${join8(s.pagesDir, "*.json")}`,
2561
2698
  `polling every ${s.intervalMs} ms${clock}`
2562
2699
  ];
2563
2700
  for (const b of s.broken) lines.push(`! ${b}`);
@@ -2780,7 +2917,7 @@ the map pane stopped: ${e instanceof Error ? e.stack ?? e.message : String(e)}
2780
2917
  const info = waitingInfo(
2781
2918
  {
2782
2919
  defaultFile: cfg.file,
2783
- pagesDir: join6(dirname7(cfg.file), PAGES_DIR_NAME),
2920
+ pagesDir: join8(dirname9(cfg.file), PAGES_DIR_NAME),
2784
2921
  intervalMs: cfg.intervalMs,
2785
2922
  elapsedMs: interactive ? Date.now() - startedAt : void 0,
2786
2923
  broken: pane.pages.flatMap(
@@ -2928,7 +3065,13 @@ the map pane stopped: ${e instanceof Error ? e.stack ?? e.message : String(e)}
2928
3065
  return;
2929
3066
  }
2930
3067
  const file = asked.request.file;
2931
- const removed = deletePageFile(file);
3068
+ let removed;
3069
+ try {
3070
+ removed = withStoreLock(file, () => deletePageFile(file));
3071
+ } catch (error) {
3072
+ flash = { text: String(error), until: now + FLASH_NOTICE_MS };
3073
+ return;
3074
+ }
2932
3075
  flash = removed.ok ? { text: `deleted ${pageName(file)}`, until: now + FLASH_ACK_MS } : { text: describeStoreError(removed.error), until: now + FLASH_NOTICE_MS };
2933
3076
  tick();
2934
3077
  };