@plinth-music/cli 0.23.1 → 0.23.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/CHANGELOG.md +47 -0
- package/dist/build-stamp.json +2 -2
- package/dist/cli.js +687 -437
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7584,7 +7584,7 @@ function _getBuiltinFlags(long, short, userNames, userAliases) {
|
|
|
7584
7584
|
// package.json
|
|
7585
7585
|
var package_default = {
|
|
7586
7586
|
name: "@plinth-music/cli",
|
|
7587
|
-
version: "0.23.
|
|
7587
|
+
version: "0.23.2",
|
|
7588
7588
|
description: "Plinth capstone sync daemon and CLI",
|
|
7589
7589
|
type: "module",
|
|
7590
7590
|
private: false,
|
|
@@ -7843,8 +7843,48 @@ function emptyCorpusCounts() {
|
|
|
7843
7843
|
return { nonMarkdown: 0, unreadable: 0 };
|
|
7844
7844
|
}
|
|
7845
7845
|
|
|
7846
|
+
// src/lib/matter.ts
|
|
7847
|
+
var import_gray_matter = __toESM(require_gray_matter(), 1);
|
|
7848
|
+
var FRONTMATTER_IS_CODE = "it is marked as code, which Plinth never runs";
|
|
7849
|
+
var PATCHED = Symbol.for("plinth.matter.engines-before-patch");
|
|
7850
|
+
var marked = (table) => table[PATCHED];
|
|
7851
|
+
var refuse = {
|
|
7852
|
+
parse() {
|
|
7853
|
+
throw new Error(FRONTMATTER_IS_CODE);
|
|
7854
|
+
},
|
|
7855
|
+
stringify() {
|
|
7856
|
+
throw new Error(FRONTMATTER_IS_CODE);
|
|
7857
|
+
}
|
|
7858
|
+
};
|
|
7859
|
+
var engines = import_gray_matter.default.engines;
|
|
7860
|
+
if (marked(engines) === undefined) {
|
|
7861
|
+
const before = Object.keys(engines).sort();
|
|
7862
|
+
const safeLoad = engines.yaml.parse;
|
|
7863
|
+
Object.assign(engines, {
|
|
7864
|
+
javascript: refuse,
|
|
7865
|
+
coffee: refuse,
|
|
7866
|
+
yaml: { parse: (input) => safeLoad(input), stringify: engines.yaml.stringify }
|
|
7867
|
+
});
|
|
7868
|
+
Object.defineProperty(engines, PATCHED, { value: before });
|
|
7869
|
+
}
|
|
7870
|
+
var ENGINES_BEFORE_PATCH = marked(engines);
|
|
7871
|
+
function matter(input, read) {
|
|
7872
|
+
return read === undefined ? import_gray_matter.default(input) : import_gray_matter.default(input, { cache: false });
|
|
7873
|
+
}
|
|
7874
|
+
function stringifyFrontmatter(body, data) {
|
|
7875
|
+
const out = import_gray_matter.default.stringify({ content: body }, data);
|
|
7876
|
+
const bodyOnly = body.endsWith(`
|
|
7877
|
+
`) ? body : `${body}
|
|
7878
|
+
`;
|
|
7879
|
+
if (out === bodyOnly && import_gray_matter.default.test(body.replace(/^/, ""))) {
|
|
7880
|
+
return `---
|
|
7881
|
+
---
|
|
7882
|
+
${bodyOnly}`;
|
|
7883
|
+
}
|
|
7884
|
+
return out;
|
|
7885
|
+
}
|
|
7886
|
+
|
|
7846
7887
|
// src/lib/backlinks/scan.ts
|
|
7847
|
-
var import_gray_matter4 = __toESM(require_gray_matter(), 1);
|
|
7848
7888
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
7849
7889
|
import { relative, sep as sep2 } from "node:path";
|
|
7850
7890
|
|
|
@@ -7860,9 +7900,6 @@ import {
|
|
|
7860
7900
|
} from "node:fs";
|
|
7861
7901
|
import { dirname, join as join2, resolve, sep } from "node:path";
|
|
7862
7902
|
|
|
7863
|
-
// src/lib/entities/_helpers.ts
|
|
7864
|
-
var import_gray_matter = __toESM(require_gray_matter(), 1);
|
|
7865
|
-
|
|
7866
7903
|
// node_modules/zod/v4/classic/external.js
|
|
7867
7904
|
var exports_external = {};
|
|
7868
7905
|
__export(exports_external, {
|
|
@@ -22189,7 +22226,7 @@ function buildFrontmatter(doc2, projectionKeys) {
|
|
|
22189
22226
|
return { ...doc2.frontmatter, ...projection };
|
|
22190
22227
|
}
|
|
22191
22228
|
function serialiseRow(doc2, projectionKeys, bodyAccessor) {
|
|
22192
|
-
const out =
|
|
22229
|
+
const out = stringifyFrontmatter(bodyAccessor(doc2), buildFrontmatter(doc2, projectionKeys));
|
|
22193
22230
|
return out.endsWith(`
|
|
22194
22231
|
`) ? out : out + `
|
|
22195
22232
|
`;
|
|
@@ -22829,7 +22866,6 @@ var documentsStrategy = {
|
|
|
22829
22866
|
};
|
|
22830
22867
|
|
|
22831
22868
|
// src/lib/entities/meetings.ts
|
|
22832
|
-
var import_gray_matter2 = __toESM(require_gray_matter(), 1);
|
|
22833
22869
|
var MeetingLiveSchema = exports_external.object({
|
|
22834
22870
|
...BASE_ROW,
|
|
22835
22871
|
deleted_at: exports_external.null(),
|
|
@@ -22984,7 +23020,7 @@ function serialise(doc2) {
|
|
|
22984
23020
|
decisions: doc2.decisions,
|
|
22985
23021
|
follow_up_summary: doc2.follow_up_summary
|
|
22986
23022
|
});
|
|
22987
|
-
const out =
|
|
23023
|
+
const out = stringifyFrontmatter(body, fm);
|
|
22988
23024
|
return out.endsWith(`
|
|
22989
23025
|
`) ? out : out + `
|
|
22990
23026
|
`;
|
|
@@ -24475,7 +24511,6 @@ function readContextFile(workspaceSlug, relativePath) {
|
|
|
24475
24511
|
}
|
|
24476
24512
|
|
|
24477
24513
|
// src/lib/backlinks/parse.ts
|
|
24478
|
-
var import_gray_matter3 = __toESM(require_gray_matter(), 1);
|
|
24479
24514
|
var RENDERED_BLOCKS = [
|
|
24480
24515
|
{ name: "tasks", begin: TASKS_BLOCK_BEGIN, end: TASKS_BLOCK_END },
|
|
24481
24516
|
{ name: "comments", begin: COMMENTS_BLOCK_BEGIN, end: COMMENTS_BLOCK_END },
|
|
@@ -24557,7 +24592,7 @@ function frontmatterLinks(body) {
|
|
|
24557
24592
|
return null;
|
|
24558
24593
|
let data;
|
|
24559
24594
|
try {
|
|
24560
|
-
data =
|
|
24595
|
+
data = matter(body).data;
|
|
24561
24596
|
} catch {
|
|
24562
24597
|
return null;
|
|
24563
24598
|
}
|
|
@@ -24825,7 +24860,7 @@ function buildArtistIndex(relPaths, root, readFile) {
|
|
|
24825
24860
|
const slug = m[1];
|
|
24826
24861
|
let name = null;
|
|
24827
24862
|
try {
|
|
24828
|
-
const raw =
|
|
24863
|
+
const raw = matter(readFile(`${root}${sep2}${rel}`)).data;
|
|
24829
24864
|
if (typeof raw.name === "string" && raw.name.trim().length > 0) {
|
|
24830
24865
|
name = raw.name.trim();
|
|
24831
24866
|
}
|
|
@@ -25634,7 +25669,8 @@ var TripReasonSchema = exports_external.object({
|
|
|
25634
25669
|
entityType: exports_external.string().optional(),
|
|
25635
25670
|
typeCount: exports_external.number().int().nonnegative().optional(),
|
|
25636
25671
|
typePopulation: exports_external.number().int().nonnegative().optional(),
|
|
25637
|
-
pct: exports_external.number().optional()
|
|
25672
|
+
pct: exports_external.number().optional(),
|
|
25673
|
+
loneRemoved: exports_external.number().int().nonnegative().optional()
|
|
25638
25674
|
});
|
|
25639
25675
|
var PendingBatchFileSchema = exports_external.object({
|
|
25640
25676
|
version: exports_external.literal(1),
|
|
@@ -25743,6 +25779,9 @@ function describeTrip(reason) {
|
|
|
25743
25779
|
const pct = reason.pct !== undefined ? ` (${Math.round(reason.pct * 100)}%)` : "";
|
|
25744
25780
|
return `${reason.typeCount}/${reason.typePopulation} ${reason.entityType}${pct} — proportion threshold`;
|
|
25745
25781
|
}
|
|
25782
|
+
if (reason.loneRemoved !== undefined) {
|
|
25783
|
+
return reason.count === 1 ? "1 large overwrite — size threshold" : `${reason.count} destructive ops, including a large overwrite — size threshold`;
|
|
25784
|
+
}
|
|
25746
25785
|
return `${reason.count} destructive ops — count threshold`;
|
|
25747
25786
|
}
|
|
25748
25787
|
function formatBytes(n) {
|
|
@@ -27630,7 +27669,6 @@ function decideRegen(input) {
|
|
|
27630
27669
|
}
|
|
27631
27670
|
|
|
27632
27671
|
// src/lib/context/roster.ts
|
|
27633
|
-
var import_gray_matter5 = __toESM(require_gray_matter(), 1);
|
|
27634
27672
|
import { readdirSync as readdirSync3, readFileSync as readFileSync8 } from "node:fs";
|
|
27635
27673
|
import { join as join7 } from "node:path";
|
|
27636
27674
|
function readRoster(workspaceSlug) {
|
|
@@ -27655,7 +27693,7 @@ function readRoster(workspaceSlug) {
|
|
|
27655
27693
|
continue;
|
|
27656
27694
|
}
|
|
27657
27695
|
try {
|
|
27658
|
-
const fm =
|
|
27696
|
+
const fm = matter(raw).data;
|
|
27659
27697
|
const name = typeof fm.name === "string" && fm.name.length > 0 ? fm.name : slug;
|
|
27660
27698
|
const status = typeof fm.status === "string" ? fm.status : null;
|
|
27661
27699
|
roster.push({ slug, name, status });
|
|
@@ -29045,7 +29083,6 @@ var SKILL_LOCATIONS = [
|
|
|
29045
29083
|
var SECURITY_NOTE = "Scoped to a single Plinth workspace: do not read or write across " + "workspace folders; each has its own token and isolation boundary.";
|
|
29046
29084
|
|
|
29047
29085
|
// src/lib/context/artist-data.ts
|
|
29048
|
-
var import_gray_matter6 = __toESM(require_gray_matter(), 1);
|
|
29049
29086
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
29050
29087
|
function artistUuidBySlug(state) {
|
|
29051
29088
|
const map2 = new Map;
|
|
@@ -29172,7 +29209,7 @@ function readEntityFrontmatter(workspaceSlug, entityType, slug) {
|
|
|
29172
29209
|
return null;
|
|
29173
29210
|
}
|
|
29174
29211
|
try {
|
|
29175
|
-
return
|
|
29212
|
+
return matter(raw).data;
|
|
29176
29213
|
} catch {
|
|
29177
29214
|
return null;
|
|
29178
29215
|
}
|
|
@@ -30545,6 +30582,9 @@ function fileDeleteSuppressedLine(f) {
|
|
|
30545
30582
|
function entityDeleteSuppressedLine(f) {
|
|
30546
30583
|
return `[ENTITY_DELETE_SUPPRESSED entityType=${f.entityType} slug=${f.slug} reason=${f.reason}]`;
|
|
30547
30584
|
}
|
|
30585
|
+
function entityPushHeldLine(f) {
|
|
30586
|
+
return `[PUSH_HELD entityType=${f.entityType} slug=${f.slug} reason=${f.reason}]`;
|
|
30587
|
+
}
|
|
30548
30588
|
function entityRestoreDeferredLine(f) {
|
|
30549
30589
|
return `[ENTITY_RESTORE_DEFERRED entityType=${f.entityType} slug=${f.slug} wait_s=${f.waitSeconds}]`;
|
|
30550
30590
|
}
|
|
@@ -30739,6 +30779,34 @@ function recordEntityRejected(args) {
|
|
|
30739
30779
|
rejected_at: args.now().toISOString()
|
|
30740
30780
|
}));
|
|
30741
30781
|
}
|
|
30782
|
+
var FRONTMATTER_UNREADABLE_REASON = "frontmatter_unreadable";
|
|
30783
|
+
function frontmatterUnreadableSentence(why) {
|
|
30784
|
+
const reason = why.replace(/[\u0000-\u001f\u007f-\u009f]/g, " ").replace(/\s+/g, " ").trim().slice(0, 120);
|
|
30785
|
+
return `not synced, because its frontmatter could not be read (${reason}). ` + `Fix the frontmatter and it syncs.`;
|
|
30786
|
+
}
|
|
30787
|
+
function recordEntityFrontmatterUnreadable(args) {
|
|
30788
|
+
let path;
|
|
30789
|
+
try {
|
|
30790
|
+
path = relative4(workspaceMirrorPath(args.workspaceSlug), args.absolutePath);
|
|
30791
|
+
} catch {
|
|
30792
|
+
path = args.absolutePath;
|
|
30793
|
+
}
|
|
30794
|
+
const message = frontmatterUnreadableSentence(args.why);
|
|
30795
|
+
const withoutStale = removeUnsynced(args.state, "entity", path);
|
|
30796
|
+
const existing = listRejected(args.state).find((o) => o.target === "entity" && o.path === path);
|
|
30797
|
+
if (!withoutStale.changed && existing?.reason === FRONTMATTER_UNREADABLE_REASON && existing.message === message) {
|
|
30798
|
+
return args.state;
|
|
30799
|
+
}
|
|
30800
|
+
return commitState(args.state, upsertRejected(withoutStale.state, {
|
|
30801
|
+
target: "entity",
|
|
30802
|
+
op: "upsert",
|
|
30803
|
+
path,
|
|
30804
|
+
status: 0,
|
|
30805
|
+
reason: FRONTMATTER_UNREADABLE_REASON,
|
|
30806
|
+
message,
|
|
30807
|
+
rejected_at: args.now().toISOString()
|
|
30808
|
+
}).state);
|
|
30809
|
+
}
|
|
30742
30810
|
function recordFileRejected(args) {
|
|
30743
30811
|
const cat = categorizeError(args.err);
|
|
30744
30812
|
const withoutStale = removeUnsynced(args.state, "file", args.relPath).state;
|
|
@@ -34319,8 +34387,7 @@ var sessionCommand = defineCommand({
|
|
|
34319
34387
|
});
|
|
34320
34388
|
|
|
34321
34389
|
// src/commands/start.ts
|
|
34322
|
-
|
|
34323
|
-
import { existsSync as existsSync10, readFileSync as readFileSync30, statSync as statSync18 } from "node:fs";
|
|
34390
|
+
import { existsSync as existsSync10, readFileSync as readFileSync31, statSync as statSync18 } from "node:fs";
|
|
34324
34391
|
|
|
34325
34392
|
// src/lib/daemon-log.ts
|
|
34326
34393
|
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync9, renameSync as renameSync7, statSync as statSync4 } from "node:fs";
|
|
@@ -34386,9 +34453,311 @@ class DaemonLog {
|
|
|
34386
34453
|
}
|
|
34387
34454
|
|
|
34388
34455
|
// src/lib/destructive-gate.ts
|
|
34389
|
-
|
|
34390
|
-
import { readFileSync as readFileSync14, statSync as statSync5 } from "node:fs";
|
|
34456
|
+
import { readFileSync as readFileSync16, statSync as statSync6 } from "node:fs";
|
|
34391
34457
|
import { basename as basename4 } from "node:path";
|
|
34458
|
+
|
|
34459
|
+
// src/lib/pull-write.ts
|
|
34460
|
+
import { readFileSync as readFileSync15 } from "node:fs";
|
|
34461
|
+
|
|
34462
|
+
// src/lib/conflicts.ts
|
|
34463
|
+
import { mkdirSync as mkdirSync10, readFileSync as readFileSync14, readdirSync as readdirSync6, statSync as statSync5, writeFileSync as writeFileSync7 } from "node:fs";
|
|
34464
|
+
import { dirname as dirname9, join as join12 } from "node:path";
|
|
34465
|
+
function conflictsRoot(workspaceSlug) {
|
|
34466
|
+
return join12(plinthHome(), "_conflicts", workspaceSlug);
|
|
34467
|
+
}
|
|
34468
|
+
function conflictFilePath(args) {
|
|
34469
|
+
const { workspaceSlug, entityType, entitySlug, timestamp, side } = args;
|
|
34470
|
+
const iso = timestamp.toISOString().replace(/[:.]/g, "-");
|
|
34471
|
+
return join12(conflictsRoot(workspaceSlug), `${entityType}.${entitySlug}.${iso}.${side}.md`);
|
|
34472
|
+
}
|
|
34473
|
+
function stashConflict(args) {
|
|
34474
|
+
const target = conflictFilePath(args);
|
|
34475
|
+
mkdirSync10(dirname9(target), { recursive: true, mode: 448 });
|
|
34476
|
+
writeFileSync7(target, args.contents, { mode: 384 });
|
|
34477
|
+
return target;
|
|
34478
|
+
}
|
|
34479
|
+
function stashEntityConflictOnce(args) {
|
|
34480
|
+
const dir = conflictsRoot(args.workspaceSlug);
|
|
34481
|
+
const head = `${args.entityType}.${args.entitySlug}.`;
|
|
34482
|
+
const tail = new RegExp(`^\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}-\\d{3}Z\\.${args.side}\\.md$`);
|
|
34483
|
+
let names = [];
|
|
34484
|
+
try {
|
|
34485
|
+
names = readdirSync6(dir);
|
|
34486
|
+
} catch {
|
|
34487
|
+
names = [];
|
|
34488
|
+
}
|
|
34489
|
+
const newest = names.filter((name) => name.startsWith(head) && tail.test(name.slice(head.length))).sort().pop();
|
|
34490
|
+
if (newest !== undefined) {
|
|
34491
|
+
const path5 = join12(dir, newest);
|
|
34492
|
+
try {
|
|
34493
|
+
if (readFileSync14(path5, "utf8") === args.contents)
|
|
34494
|
+
return { path: path5, reused: true };
|
|
34495
|
+
} catch {}
|
|
34496
|
+
}
|
|
34497
|
+
return { path: stashConflict(args), reused: false };
|
|
34498
|
+
}
|
|
34499
|
+
function fileConflictPath(args) {
|
|
34500
|
+
const { workspaceSlug, relPath, timestamp, side } = args;
|
|
34501
|
+
const iso = timestamp.toISOString().replace(/[:.]/g, "-");
|
|
34502
|
+
return join12(conflictsRoot(workspaceSlug), `${fileConflictStem(relPath)}.${iso}.${side}`);
|
|
34503
|
+
}
|
|
34504
|
+
function fileConflictStem(relPath) {
|
|
34505
|
+
return `files.${relPath.replace(/[/\\]/g, "__")}`;
|
|
34506
|
+
}
|
|
34507
|
+
function stashFileConflict(args) {
|
|
34508
|
+
const target = fileConflictPath(args);
|
|
34509
|
+
mkdirSync10(dirname9(target), { recursive: true, mode: 448 });
|
|
34510
|
+
writeFileSync7(target, args.bytes, { mode: 384 });
|
|
34511
|
+
return target;
|
|
34512
|
+
}
|
|
34513
|
+
function stashFileConflictOnce(args) {
|
|
34514
|
+
const dir = conflictsRoot(args.workspaceSlug);
|
|
34515
|
+
const head = `${fileConflictStem(args.relPath)}.`;
|
|
34516
|
+
const tail = new RegExp(`^\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}-\\d{3}Z\\.${args.side}$`);
|
|
34517
|
+
let names = [];
|
|
34518
|
+
try {
|
|
34519
|
+
names = readdirSync6(dir);
|
|
34520
|
+
} catch {
|
|
34521
|
+
names = [];
|
|
34522
|
+
}
|
|
34523
|
+
const newest = names.filter((n) => n.startsWith(head) && tail.test(n.slice(head.length))).sort().pop();
|
|
34524
|
+
if (newest !== undefined) {
|
|
34525
|
+
const path5 = join12(dir, newest);
|
|
34526
|
+
try {
|
|
34527
|
+
if (Buffer.compare(args.bytes, readFileSync14(path5)) === 0)
|
|
34528
|
+
return { path: path5, reused: true };
|
|
34529
|
+
} catch {}
|
|
34530
|
+
}
|
|
34531
|
+
return { path: stashFileConflict(args), reused: false };
|
|
34532
|
+
}
|
|
34533
|
+
var STAMP_RE2 = /\.(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z)(?:\.(local|cloud))?(?:\.md)?$/;
|
|
34534
|
+
function parseStamp(stamp) {
|
|
34535
|
+
const iso = stamp.replace(/T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z$/, "T$1:$2:$3.$4Z");
|
|
34536
|
+
const d = new Date(iso);
|
|
34537
|
+
return Number.isNaN(d.getTime()) ? null : d;
|
|
34538
|
+
}
|
|
34539
|
+
function labelFor(file2) {
|
|
34540
|
+
const m = STAMP_RE2.exec(file2);
|
|
34541
|
+
if (!m)
|
|
34542
|
+
return file2;
|
|
34543
|
+
const head = file2.slice(0, m.index);
|
|
34544
|
+
if (head.startsWith("files.")) {
|
|
34545
|
+
return `files/${head.slice("files.".length).replace(/__/g, "/")}`;
|
|
34546
|
+
}
|
|
34547
|
+
const dot = head.indexOf(".");
|
|
34548
|
+
if (dot === -1)
|
|
34549
|
+
return head;
|
|
34550
|
+
return `${head.slice(0, dot)}/${head.slice(dot + 1)}`;
|
|
34551
|
+
}
|
|
34552
|
+
function listConflictStashes(workspaceSlug) {
|
|
34553
|
+
const dir = conflictsRoot(workspaceSlug);
|
|
34554
|
+
let names;
|
|
34555
|
+
try {
|
|
34556
|
+
names = readdirSync6(dir);
|
|
34557
|
+
} catch {
|
|
34558
|
+
return [];
|
|
34559
|
+
}
|
|
34560
|
+
const out = [];
|
|
34561
|
+
for (const file2 of names) {
|
|
34562
|
+
const absPath = join12(dir, file2);
|
|
34563
|
+
let st;
|
|
34564
|
+
try {
|
|
34565
|
+
st = statSync5(absPath);
|
|
34566
|
+
} catch {
|
|
34567
|
+
continue;
|
|
34568
|
+
}
|
|
34569
|
+
if (!st.isFile())
|
|
34570
|
+
continue;
|
|
34571
|
+
if (file2.startsWith("."))
|
|
34572
|
+
continue;
|
|
34573
|
+
const m = STAMP_RE2.exec(file2);
|
|
34574
|
+
const side = m?.[2];
|
|
34575
|
+
out.push({
|
|
34576
|
+
file: file2,
|
|
34577
|
+
absPath,
|
|
34578
|
+
label: labelFor(file2),
|
|
34579
|
+
stashedAt: m ? parseStamp(m[1]) : null,
|
|
34580
|
+
side: side === "local" || side === "cloud" ? side : null,
|
|
34581
|
+
mtimeMs: st.mtimeMs
|
|
34582
|
+
});
|
|
34583
|
+
}
|
|
34584
|
+
return out.sort((a, b) => (b.stashedAt?.getTime() ?? b.mtimeMs) - (a.stashedAt?.getTime() ?? a.mtimeMs));
|
|
34585
|
+
}
|
|
34586
|
+
|
|
34587
|
+
// src/lib/pull-write.ts
|
|
34588
|
+
var UNCACHED = { cache: false };
|
|
34589
|
+
function parseUncached(raw) {
|
|
34590
|
+
return matter(raw, UNCACHED);
|
|
34591
|
+
}
|
|
34592
|
+
var NOT_A_MAPPING = "it is not a list of `key: value` lines";
|
|
34593
|
+
var SELF_REFERENCE = "an alias in it refers to itself";
|
|
34594
|
+
function readFrontmatter(raw) {
|
|
34595
|
+
let parsed;
|
|
34596
|
+
try {
|
|
34597
|
+
parsed = parseUncached(raw);
|
|
34598
|
+
} catch (err) {
|
|
34599
|
+
return { ok: false, why: yamlReason(err) };
|
|
34600
|
+
}
|
|
34601
|
+
if (Object.prototype.toString.call(parsed.data) !== "[object Object]") {
|
|
34602
|
+
return { ok: false, why: NOT_A_MAPPING };
|
|
34603
|
+
}
|
|
34604
|
+
try {
|
|
34605
|
+
JSON.stringify(parsed.data);
|
|
34606
|
+
} catch {
|
|
34607
|
+
return { ok: false, why: SELF_REFERENCE };
|
|
34608
|
+
}
|
|
34609
|
+
return { ok: true, parsed };
|
|
34610
|
+
}
|
|
34611
|
+
function yamlReason(err) {
|
|
34612
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
34613
|
+
return (message.split(`
|
|
34614
|
+
`)[0] ?? "").replace(/:\s*$/, "").trim();
|
|
34615
|
+
}
|
|
34616
|
+
function frontmatterParseError(raw) {
|
|
34617
|
+
const read = readFrontmatter(raw);
|
|
34618
|
+
return read.ok ? null : read.why;
|
|
34619
|
+
}
|
|
34620
|
+
function computeMirrorHashes(strategy, content) {
|
|
34621
|
+
const parsed = matter(content);
|
|
34622
|
+
const fm = parsed.data ?? {};
|
|
34623
|
+
const lifted = splitUserFrontmatter(strategy, fm);
|
|
34624
|
+
const userFm = userFrontmatter(strategy, lifted.frontmatter);
|
|
34625
|
+
const hashBody = hashableBody(strategy, parsed.content);
|
|
34626
|
+
return {
|
|
34627
|
+
bodyHash: stableHash(hashBody),
|
|
34628
|
+
frontmatterHash: stableHash({ ...userFm, ...lifted.topLevel }),
|
|
34629
|
+
bodyLen: hashBody.length,
|
|
34630
|
+
frontmatterId: fm["id"]
|
|
34631
|
+
};
|
|
34632
|
+
}
|
|
34633
|
+
function hashableBody(strategy, body) {
|
|
34634
|
+
return strategy.stripLocalBlocks?.(body) ?? body;
|
|
34635
|
+
}
|
|
34636
|
+
function relocateForSlugChange(args) {
|
|
34637
|
+
const { workspaceSlug, strategy, fromSlug, toSlug, acked, echo, now } = args;
|
|
34638
|
+
if (fromSlug === toSlug)
|
|
34639
|
+
return { kind: "not_needed", writeSlug: toSlug };
|
|
34640
|
+
if (!echo) {
|
|
34641
|
+
return { kind: "skipped", writeSlug: toSlug, fromSlug, reason: "unguarded" };
|
|
34642
|
+
}
|
|
34643
|
+
if (strategy.mirrorRelativePath(fromSlug).split("/").length !== 2) {
|
|
34644
|
+
return { kind: "skipped", writeSlug: toSlug, fromSlug, reason: "foldered" };
|
|
34645
|
+
}
|
|
34646
|
+
let fromPath;
|
|
34647
|
+
try {
|
|
34648
|
+
fromPath = entityFilePath(workspaceSlug, strategy.type, fromSlug);
|
|
34649
|
+
entityFilePath(workspaceSlug, strategy.type, toSlug);
|
|
34650
|
+
} catch (err) {
|
|
34651
|
+
if (err instanceof MirrorPathError) {
|
|
34652
|
+
return {
|
|
34653
|
+
kind: "skipped",
|
|
34654
|
+
writeSlug: toSlug,
|
|
34655
|
+
fromSlug,
|
|
34656
|
+
reason: "unresolvable"
|
|
34657
|
+
};
|
|
34658
|
+
}
|
|
34659
|
+
throw err;
|
|
34660
|
+
}
|
|
34661
|
+
let raw = null;
|
|
34662
|
+
try {
|
|
34663
|
+
raw = readFileSync15(fromPath, "utf8");
|
|
34664
|
+
} catch (err) {
|
|
34665
|
+
const code = err?.code;
|
|
34666
|
+
if (code === "ENOENT") {
|
|
34667
|
+
return { kind: "absent", writeSlug: toSlug, fromSlug };
|
|
34668
|
+
}
|
|
34669
|
+
return {
|
|
34670
|
+
kind: "refused",
|
|
34671
|
+
writeSlug: fromSlug,
|
|
34672
|
+
fromSlug,
|
|
34673
|
+
reason: "source_unreadable"
|
|
34674
|
+
};
|
|
34675
|
+
}
|
|
34676
|
+
let diverged = true;
|
|
34677
|
+
try {
|
|
34678
|
+
const hashes = computeMirrorHashes(strategy, raw);
|
|
34679
|
+
diverged = hashes.bodyHash !== acked.bodyHash || hashes.frontmatterHash !== acked.frontmatterHash;
|
|
34680
|
+
} catch {
|
|
34681
|
+
diverged = true;
|
|
34682
|
+
}
|
|
34683
|
+
const stashPath = diverged ? stashConflict({
|
|
34684
|
+
workspaceSlug,
|
|
34685
|
+
entityType: strategy.type,
|
|
34686
|
+
entitySlug: fromSlug,
|
|
34687
|
+
timestamp: now(),
|
|
34688
|
+
contents: raw,
|
|
34689
|
+
side: "local"
|
|
34690
|
+
}) : undefined;
|
|
34691
|
+
try {
|
|
34692
|
+
let registered = false;
|
|
34693
|
+
const result = moveEntityFile(workspaceSlug, strategy.type, fromSlug, toSlug, () => {
|
|
34694
|
+
if (echo.watcher === "live") {
|
|
34695
|
+
echo.suppressor.registerDelete(fromPath);
|
|
34696
|
+
registered = true;
|
|
34697
|
+
}
|
|
34698
|
+
});
|
|
34699
|
+
if (result === "moved") {
|
|
34700
|
+
return { kind: "moved", writeSlug: toSlug, fromSlug, stashPath };
|
|
34701
|
+
}
|
|
34702
|
+
if (registered && echo.watcher === "live") {
|
|
34703
|
+
echo.suppressor.cancelDelete(fromPath);
|
|
34704
|
+
}
|
|
34705
|
+
return { kind: "absent", writeSlug: toSlug, fromSlug };
|
|
34706
|
+
} catch (err) {
|
|
34707
|
+
if (err instanceof MirrorDestinationOccupiedError) {
|
|
34708
|
+
return {
|
|
34709
|
+
kind: "refused",
|
|
34710
|
+
writeSlug: fromSlug,
|
|
34711
|
+
fromSlug,
|
|
34712
|
+
reason: "destination_occupied",
|
|
34713
|
+
stashPath
|
|
34714
|
+
};
|
|
34715
|
+
}
|
|
34716
|
+
if (err instanceof MirrorPathError) {
|
|
34717
|
+
return {
|
|
34718
|
+
kind: "skipped",
|
|
34719
|
+
writeSlug: toSlug,
|
|
34720
|
+
fromSlug,
|
|
34721
|
+
reason: "unresolvable"
|
|
34722
|
+
};
|
|
34723
|
+
}
|
|
34724
|
+
throw err;
|
|
34725
|
+
}
|
|
34726
|
+
}
|
|
34727
|
+
function writeMirrorWithBodyPreserve(workspaceSlug, strategy, doc2, suppressor, pathSlug) {
|
|
34728
|
+
const targetSlug = pathSlug ?? doc2.slug;
|
|
34729
|
+
const content = renderMirrorWithBodyPreserve(workspaceSlug, strategy, doc2, targetSlug);
|
|
34730
|
+
if (suppressor) {
|
|
34731
|
+
const target = entityFilePath(workspaceSlug, strategy.type, targetSlug);
|
|
34732
|
+
suppressor.registerWrite(target, computeMirrorHashes(strategy, content));
|
|
34733
|
+
}
|
|
34734
|
+
writeMirrorFile(workspaceSlug, strategy.type, targetSlug, content);
|
|
34735
|
+
return content;
|
|
34736
|
+
}
|
|
34737
|
+
function renderMirrorWithBodyPreserve(workspaceSlug, strategy, doc2, targetSlug) {
|
|
34738
|
+
let content = strategy.serialise(doc2);
|
|
34739
|
+
if (strategy.preserveLocalBodyOnPull) {
|
|
34740
|
+
const target = entityFilePath(workspaceSlug, strategy.type, targetSlug);
|
|
34741
|
+
let existing = null;
|
|
34742
|
+
try {
|
|
34743
|
+
existing = readFileSync15(target, "utf8");
|
|
34744
|
+
} catch (err) {
|
|
34745
|
+
if (err?.code !== "ENOENT")
|
|
34746
|
+
throw err;
|
|
34747
|
+
}
|
|
34748
|
+
if (existing !== null) {
|
|
34749
|
+
const existingParsed = matter(existing);
|
|
34750
|
+
const cloudParsed = matter(content);
|
|
34751
|
+
const stitched = stringifyFrontmatter(existingParsed.content, cloudParsed.data);
|
|
34752
|
+
content = stitched.endsWith(`
|
|
34753
|
+
`) ? stitched : stitched + `
|
|
34754
|
+
`;
|
|
34755
|
+
}
|
|
34756
|
+
}
|
|
34757
|
+
return content;
|
|
34758
|
+
}
|
|
34759
|
+
|
|
34760
|
+
// src/lib/destructive-gate.ts
|
|
34392
34761
|
var GUTTING_RATIO_DEFAULT = 0.5;
|
|
34393
34762
|
var GUTTING_MIN_PRIOR_BYTES = 200;
|
|
34394
34763
|
function envFloat(name, def) {
|
|
@@ -34431,10 +34800,10 @@ function classifyDestructive(event, entityType, state, deps = {}) {
|
|
|
34431
34800
|
absolutePath: event.absolutePath
|
|
34432
34801
|
};
|
|
34433
34802
|
}
|
|
34434
|
-
const readFile = deps.readFile ?? ((p) =>
|
|
34803
|
+
const readFile = deps.readFile ?? ((p) => readFileSync16(p, "utf8"));
|
|
34435
34804
|
const statInode = deps.statInode ?? ((p) => {
|
|
34436
34805
|
try {
|
|
34437
|
-
return
|
|
34806
|
+
return statSync6(p).ino;
|
|
34438
34807
|
} catch {
|
|
34439
34808
|
return;
|
|
34440
34809
|
}
|
|
@@ -34445,13 +34814,11 @@ function classifyDestructive(event, entityType, state, deps = {}) {
|
|
|
34445
34814
|
} catch {
|
|
34446
34815
|
return null;
|
|
34447
34816
|
}
|
|
34448
|
-
|
|
34449
|
-
|
|
34450
|
-
const body = import_gray_matter7.default(raw).content;
|
|
34451
|
-
newLen = (getStrategy(entityType)?.stripLocalBlocks?.(body) ?? body).length;
|
|
34452
|
-
} catch {
|
|
34817
|
+
const read = readFrontmatter(raw);
|
|
34818
|
+
if (!read.ok)
|
|
34453
34819
|
return null;
|
|
34454
|
-
|
|
34820
|
+
const body = read.parsed.content;
|
|
34821
|
+
const newLen = (getStrategy(entityType)?.stripLocalBlocks?.(body) ?? body).length;
|
|
34455
34822
|
const liveInode = statInode(event.absolutePath);
|
|
34456
34823
|
const slug = basename4(event.absolutePath, ".md");
|
|
34457
34824
|
const entry2 = (liveInode !== undefined ? getEntryByInode(state, entityType, liveInode) : undefined) ?? getEntryBySlug(state, entityType, slug);
|
|
@@ -34470,13 +34837,26 @@ function classifyDestructive(event, entityType, state, deps = {}) {
|
|
|
34470
34837
|
newLen
|
|
34471
34838
|
};
|
|
34472
34839
|
}
|
|
34840
|
+
var LONE_MIN_REMOVED_DEFAULT = 5000;
|
|
34841
|
+
var LONE_MIN_REMOVED_BYTES_DEFAULT = 100 * 1024;
|
|
34473
34842
|
function defaultThresholds() {
|
|
34474
34843
|
return {
|
|
34475
34844
|
absCount: envInt("PLINTH_GATE_ABS_COUNT", 3),
|
|
34476
34845
|
propMinOps: envInt("PLINTH_GATE_PROP_MIN_OPS", 2),
|
|
34477
|
-
propPct: envFloat("PLINTH_GATE_PROP_PCT", 0.5)
|
|
34846
|
+
propPct: envFloat("PLINTH_GATE_PROP_PCT", 0.5),
|
|
34847
|
+
loneMinRemoved: envInt("PLINTH_GATE_LONE_MIN_REMOVED", LONE_MIN_REMOVED_DEFAULT),
|
|
34848
|
+
loneMinRemovedBytes: envInt("PLINTH_GATE_LONE_MIN_REMOVED_BYTES", LONE_MIN_REMOVED_BYTES_DEFAULT)
|
|
34478
34849
|
};
|
|
34479
34850
|
}
|
|
34851
|
+
function tripReasonToken(reason) {
|
|
34852
|
+
return reason.loneRemoved !== undefined ? "size" : reason.kind;
|
|
34853
|
+
}
|
|
34854
|
+
function evaluateLoneOverwrite(count, removed, floor) {
|
|
34855
|
+
const loneRemoved = Math.max(0, ...removed);
|
|
34856
|
+
if (loneRemoved < floor)
|
|
34857
|
+
return { tripped: false };
|
|
34858
|
+
return { tripped: true, reason: { kind: "count", count, loneRemoved } };
|
|
34859
|
+
}
|
|
34480
34860
|
function evaluateBatch(ops, typePopulations, thresholds = defaultThresholds()) {
|
|
34481
34861
|
const count = ops.length;
|
|
34482
34862
|
if (count === 0)
|
|
@@ -34504,7 +34884,7 @@ function evaluateBatch(ops, typePopulations, thresholds = defaultThresholds()) {
|
|
|
34504
34884
|
};
|
|
34505
34885
|
}
|
|
34506
34886
|
}
|
|
34507
|
-
return
|
|
34887
|
+
return evaluateLoneOverwrite(count, ops.map((op) => op.kind === "overwrite" ? op.priorLen - op.newLen : 0), thresholds.loneMinRemoved);
|
|
34508
34888
|
}
|
|
34509
34889
|
function dedupeOps(ops) {
|
|
34510
34890
|
const byKey = new Map;
|
|
@@ -34564,135 +34944,10 @@ class DestructiveGate {
|
|
|
34564
34944
|
}
|
|
34565
34945
|
|
|
34566
34946
|
// src/lib/resolve-pending.ts
|
|
34567
|
-
import { readFileSync as
|
|
34568
|
-
|
|
34569
|
-
// src/lib/conflicts.ts
|
|
34570
|
-
import { mkdirSync as mkdirSync10, readFileSync as readFileSync15, readdirSync as readdirSync6, statSync as statSync6, writeFileSync as writeFileSync7 } from "node:fs";
|
|
34571
|
-
import { dirname as dirname9, join as join12 } from "node:path";
|
|
34572
|
-
function conflictsRoot(workspaceSlug) {
|
|
34573
|
-
return join12(plinthHome(), "_conflicts", workspaceSlug);
|
|
34574
|
-
}
|
|
34575
|
-
function conflictFilePath(args) {
|
|
34576
|
-
const { workspaceSlug, entityType, entitySlug, timestamp, side } = args;
|
|
34577
|
-
const iso = timestamp.toISOString().replace(/[:.]/g, "-");
|
|
34578
|
-
return join12(conflictsRoot(workspaceSlug), `${entityType}.${entitySlug}.${iso}.${side}.md`);
|
|
34579
|
-
}
|
|
34580
|
-
function stashConflict(args) {
|
|
34581
|
-
const target = conflictFilePath(args);
|
|
34582
|
-
mkdirSync10(dirname9(target), { recursive: true, mode: 448 });
|
|
34583
|
-
writeFileSync7(target, args.contents, { mode: 384 });
|
|
34584
|
-
return target;
|
|
34585
|
-
}
|
|
34586
|
-
function stashEntityConflictOnce(args) {
|
|
34587
|
-
const dir = conflictsRoot(args.workspaceSlug);
|
|
34588
|
-
const head = `${args.entityType}.${args.entitySlug}.`;
|
|
34589
|
-
const tail = new RegExp(`^\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}-\\d{3}Z\\.${args.side}\\.md$`);
|
|
34590
|
-
let names = [];
|
|
34591
|
-
try {
|
|
34592
|
-
names = readdirSync6(dir);
|
|
34593
|
-
} catch {
|
|
34594
|
-
names = [];
|
|
34595
|
-
}
|
|
34596
|
-
const newest = names.filter((name) => name.startsWith(head) && tail.test(name.slice(head.length))).sort().pop();
|
|
34597
|
-
if (newest !== undefined) {
|
|
34598
|
-
const path5 = join12(dir, newest);
|
|
34599
|
-
try {
|
|
34600
|
-
if (readFileSync15(path5, "utf8") === args.contents)
|
|
34601
|
-
return { path: path5, reused: true };
|
|
34602
|
-
} catch {}
|
|
34603
|
-
}
|
|
34604
|
-
return { path: stashConflict(args), reused: false };
|
|
34605
|
-
}
|
|
34606
|
-
function fileConflictPath(args) {
|
|
34607
|
-
const { workspaceSlug, relPath, timestamp, side } = args;
|
|
34608
|
-
const iso = timestamp.toISOString().replace(/[:.]/g, "-");
|
|
34609
|
-
return join12(conflictsRoot(workspaceSlug), `${fileConflictStem(relPath)}.${iso}.${side}`);
|
|
34610
|
-
}
|
|
34611
|
-
function fileConflictStem(relPath) {
|
|
34612
|
-
return `files.${relPath.replace(/[/\\]/g, "__")}`;
|
|
34613
|
-
}
|
|
34614
|
-
function stashFileConflict(args) {
|
|
34615
|
-
const target = fileConflictPath(args);
|
|
34616
|
-
mkdirSync10(dirname9(target), { recursive: true, mode: 448 });
|
|
34617
|
-
writeFileSync7(target, args.bytes, { mode: 384 });
|
|
34618
|
-
return target;
|
|
34619
|
-
}
|
|
34620
|
-
function stashFileConflictOnce(args) {
|
|
34621
|
-
const dir = conflictsRoot(args.workspaceSlug);
|
|
34622
|
-
const head = `${fileConflictStem(args.relPath)}.`;
|
|
34623
|
-
const tail = new RegExp(`^\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}-\\d{3}Z\\.${args.side}$`);
|
|
34624
|
-
let names = [];
|
|
34625
|
-
try {
|
|
34626
|
-
names = readdirSync6(dir);
|
|
34627
|
-
} catch {
|
|
34628
|
-
names = [];
|
|
34629
|
-
}
|
|
34630
|
-
const newest = names.filter((n) => n.startsWith(head) && tail.test(n.slice(head.length))).sort().pop();
|
|
34631
|
-
if (newest !== undefined) {
|
|
34632
|
-
const path5 = join12(dir, newest);
|
|
34633
|
-
try {
|
|
34634
|
-
if (Buffer.compare(args.bytes, readFileSync15(path5)) === 0)
|
|
34635
|
-
return { path: path5, reused: true };
|
|
34636
|
-
} catch {}
|
|
34637
|
-
}
|
|
34638
|
-
return { path: stashFileConflict(args), reused: false };
|
|
34639
|
-
}
|
|
34640
|
-
var STAMP_RE2 = /\.(\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z)(?:\.(local|cloud))?(?:\.md)?$/;
|
|
34641
|
-
function parseStamp(stamp) {
|
|
34642
|
-
const iso = stamp.replace(/T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z$/, "T$1:$2:$3.$4Z");
|
|
34643
|
-
const d = new Date(iso);
|
|
34644
|
-
return Number.isNaN(d.getTime()) ? null : d;
|
|
34645
|
-
}
|
|
34646
|
-
function labelFor(file2) {
|
|
34647
|
-
const m = STAMP_RE2.exec(file2);
|
|
34648
|
-
if (!m)
|
|
34649
|
-
return file2;
|
|
34650
|
-
const head = file2.slice(0, m.index);
|
|
34651
|
-
if (head.startsWith("files.")) {
|
|
34652
|
-
return `files/${head.slice("files.".length).replace(/__/g, "/")}`;
|
|
34653
|
-
}
|
|
34654
|
-
const dot = head.indexOf(".");
|
|
34655
|
-
if (dot === -1)
|
|
34656
|
-
return head;
|
|
34657
|
-
return `${head.slice(0, dot)}/${head.slice(dot + 1)}`;
|
|
34658
|
-
}
|
|
34659
|
-
function listConflictStashes(workspaceSlug) {
|
|
34660
|
-
const dir = conflictsRoot(workspaceSlug);
|
|
34661
|
-
let names;
|
|
34662
|
-
try {
|
|
34663
|
-
names = readdirSync6(dir);
|
|
34664
|
-
} catch {
|
|
34665
|
-
return [];
|
|
34666
|
-
}
|
|
34667
|
-
const out = [];
|
|
34668
|
-
for (const file2 of names) {
|
|
34669
|
-
const absPath = join12(dir, file2);
|
|
34670
|
-
let st;
|
|
34671
|
-
try {
|
|
34672
|
-
st = statSync6(absPath);
|
|
34673
|
-
} catch {
|
|
34674
|
-
continue;
|
|
34675
|
-
}
|
|
34676
|
-
if (!st.isFile())
|
|
34677
|
-
continue;
|
|
34678
|
-
if (file2.startsWith("."))
|
|
34679
|
-
continue;
|
|
34680
|
-
const m = STAMP_RE2.exec(file2);
|
|
34681
|
-
const side = m?.[2];
|
|
34682
|
-
out.push({
|
|
34683
|
-
file: file2,
|
|
34684
|
-
absPath,
|
|
34685
|
-
label: labelFor(file2),
|
|
34686
|
-
stashedAt: m ? parseStamp(m[1]) : null,
|
|
34687
|
-
side: side === "local" || side === "cloud" ? side : null,
|
|
34688
|
-
mtimeMs: st.mtimeMs
|
|
34689
|
-
});
|
|
34690
|
-
}
|
|
34691
|
-
return out.sort((a, b) => (b.stashedAt?.getTime() ?? b.mtimeMs) - (a.stashedAt?.getTime() ?? a.mtimeMs));
|
|
34692
|
-
}
|
|
34947
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
34693
34948
|
|
|
34694
34949
|
// src/lib/files/push.ts
|
|
34695
|
-
import { readFileSync as
|
|
34950
|
+
import { readFileSync as readFileSync18, statSync as statSync7 } from "node:fs";
|
|
34696
34951
|
|
|
34697
34952
|
// src/lib/permanent-deletions.ts
|
|
34698
34953
|
import { createHash as createHash3, randomUUID } from "node:crypto";
|
|
@@ -34706,7 +34961,7 @@ import {
|
|
|
34706
34961
|
lstatSync as lstatSync4,
|
|
34707
34962
|
mkdirSync as mkdirSync11,
|
|
34708
34963
|
openSync as openSync4,
|
|
34709
|
-
readFileSync as
|
|
34964
|
+
readFileSync as readFileSync17,
|
|
34710
34965
|
renameSync as renameSync8,
|
|
34711
34966
|
unlinkSync as unlinkSync8,
|
|
34712
34967
|
writeSync as writeSync2
|
|
@@ -34897,7 +35152,7 @@ function loadPermanentDeletionJournal(workspaceSlug) {
|
|
|
34897
35152
|
return emptyJournal(workspaceSlug);
|
|
34898
35153
|
assertPrivateDirectory(dirname10(target));
|
|
34899
35154
|
assertOwnerOnlyFile(target);
|
|
34900
|
-
const journal = parseJournal(workspaceSlug,
|
|
35155
|
+
const journal = parseJournal(workspaceSlug, readFileSync17(target, "utf8"));
|
|
34901
35156
|
try {
|
|
34902
35157
|
fsyncDirectory(dirname10(target));
|
|
34903
35158
|
} catch (error52) {
|
|
@@ -34964,7 +35219,7 @@ function writePermanentDeletionJournal(prior, next) {
|
|
|
34964
35219
|
let installed2 = false;
|
|
34965
35220
|
try {
|
|
34966
35221
|
assertOwnerOnlyFile(target);
|
|
34967
|
-
const candidate = parseJournal(body.workspace_slug,
|
|
35222
|
+
const candidate = parseJournal(body.workspace_slug, readFileSync17(target, "utf8"));
|
|
34968
35223
|
installed2 = candidate.revision === body.revision && checksum(candidate) === checksum(body);
|
|
34969
35224
|
} catch {
|
|
34970
35225
|
installed2 = false;
|
|
@@ -34978,7 +35233,7 @@ function writePermanentDeletionJournal(prior, next) {
|
|
|
34978
35233
|
}
|
|
34979
35234
|
}
|
|
34980
35235
|
assertOwnerOnlyFile(target);
|
|
34981
|
-
const installed = parseJournal(body.workspace_slug,
|
|
35236
|
+
const installed = parseJournal(body.workspace_slug, readFileSync17(target, "utf8"));
|
|
34982
35237
|
if (installed.revision !== body.revision || checksum(installed) !== checksum(body)) {
|
|
34983
35238
|
throw new PermanentDeletionJournalError("renamed journal revision did not validate", "durability_indeterminate");
|
|
34984
35239
|
}
|
|
@@ -34986,7 +35241,7 @@ function writePermanentDeletionJournal(prior, next) {
|
|
|
34986
35241
|
fsyncDirectory(parent);
|
|
34987
35242
|
} catch (firstError) {
|
|
34988
35243
|
assertOwnerOnlyFile(target);
|
|
34989
|
-
const reopened = parseJournal(body.workspace_slug,
|
|
35244
|
+
const reopened = parseJournal(body.workspace_slug, readFileSync17(target, "utf8"));
|
|
34990
35245
|
if (reopened.revision !== body.revision || checksum(reopened) !== checksum(body)) {
|
|
34991
35246
|
throw new PermanentDeletionJournalError("journal changed after rename", "durability_indeterminate");
|
|
34992
35247
|
}
|
|
@@ -35485,7 +35740,7 @@ async function pushFilesUpsertLocked(args) {
|
|
|
35485
35740
|
state: next
|
|
35486
35741
|
};
|
|
35487
35742
|
}
|
|
35488
|
-
bytes =
|
|
35743
|
+
bytes = readFileSync18(absolutePath);
|
|
35489
35744
|
hash2 = sha256Bytes(bytes);
|
|
35490
35745
|
inode = st.ino;
|
|
35491
35746
|
}
|
|
@@ -35747,12 +36002,64 @@ async function pushFilesDelete(args) {
|
|
|
35747
36002
|
}
|
|
35748
36003
|
|
|
35749
36004
|
// src/lib/push.ts
|
|
35750
|
-
|
|
35751
|
-
import { existsSync as existsSync5, readFileSync as readFileSync19, statSync as statSync8 } from "node:fs";
|
|
36005
|
+
import { existsSync as existsSync5, readFileSync as readFileSync20, statSync as statSync8 } from "node:fs";
|
|
35752
36006
|
import { basename as basename5, relative as relative5 } from "node:path";
|
|
35753
36007
|
|
|
36008
|
+
// src/lib/frontmatter-held.ts
|
|
36009
|
+
import { lstatSync as lstatSync5, readFileSync as readFileSync19 } from "node:fs";
|
|
36010
|
+
import { resolve as resolve4, sep as sep5 } from "node:path";
|
|
36011
|
+
function holdUnreadableFrontmatter(args) {
|
|
36012
|
+
const next = recordEntityFrontmatterUnreadable(args);
|
|
36013
|
+
args.output?.log(entityPushHeldLine({
|
|
36014
|
+
entityType: args.entityType,
|
|
36015
|
+
slug: args.slug,
|
|
36016
|
+
reason: FRONTMATTER_UNREADABLE_REASON
|
|
36017
|
+
}));
|
|
36018
|
+
if (next !== args.state) {
|
|
36019
|
+
args.output?.warn(`${args.entityType}/${args.slug}: ${frontmatterUnreadableSentence(args.why)}`);
|
|
36020
|
+
}
|
|
36021
|
+
return next;
|
|
36022
|
+
}
|
|
36023
|
+
function settleFrontmatterHolds(state, workspaceSlug) {
|
|
36024
|
+
const held = listRejected(state).filter(isFrontmatterHold);
|
|
36025
|
+
if (held.length === 0)
|
|
36026
|
+
return state;
|
|
36027
|
+
let root;
|
|
36028
|
+
try {
|
|
36029
|
+
root = workspaceMirrorPath(workspaceSlug);
|
|
36030
|
+
} catch {
|
|
36031
|
+
return state;
|
|
36032
|
+
}
|
|
36033
|
+
const settled = new Set(held.map((record2) => record2.path).filter((path5) => !stillHeld(workspaceSlug, root, path5)));
|
|
36034
|
+
if (settled.size === 0)
|
|
36035
|
+
return state;
|
|
36036
|
+
return commitState(state, {
|
|
36037
|
+
...state,
|
|
36038
|
+
rejected: listRejected(state).filter((o) => !(isFrontmatterHold(o) && settled.has(o.path)))
|
|
36039
|
+
});
|
|
36040
|
+
}
|
|
36041
|
+
function isFrontmatterHold(record2) {
|
|
36042
|
+
return record2.target === "entity" && record2.reason === FRONTMATTER_UNREADABLE_REASON;
|
|
36043
|
+
}
|
|
36044
|
+
function stillHeld(workspaceSlug, root, recordPath) {
|
|
36045
|
+
const absolutePath = resolve4(root, recordPath);
|
|
36046
|
+
if (!absolutePath.startsWith(root + sep5))
|
|
36047
|
+
return true;
|
|
36048
|
+
if (hasSymlinkedComponent(workspaceSlug, absolutePath))
|
|
36049
|
+
return true;
|
|
36050
|
+
let raw;
|
|
36051
|
+
try {
|
|
36052
|
+
if (!lstatSync5(absolutePath).isFile())
|
|
36053
|
+
return true;
|
|
36054
|
+
raw = readFileSync19(absolutePath, "utf8");
|
|
36055
|
+
} catch (err) {
|
|
36056
|
+
const code = err.code;
|
|
36057
|
+
return code !== "ENOENT" && code !== "ENOTDIR";
|
|
36058
|
+
}
|
|
36059
|
+
return frontmatterParseError(raw) !== null;
|
|
36060
|
+
}
|
|
36061
|
+
|
|
35754
36062
|
// src/lib/frontmatter-id.ts
|
|
35755
|
-
var import_gray_matter8 = __toESM(require_gray_matter(), 1);
|
|
35756
36063
|
function eolOf(content) {
|
|
35757
36064
|
return /\r\n/.test(content) ? `\r
|
|
35758
36065
|
` : `
|
|
@@ -35789,158 +36096,16 @@ function withFrontmatterId(raw, parsed, id) {
|
|
|
35789
36096
|
}
|
|
35790
36097
|
function frontmatterIdWriteIsSound(next, id, expectedBody) {
|
|
35791
36098
|
try {
|
|
35792
|
-
const check2 =
|
|
36099
|
+
const check2 = matter(next);
|
|
35793
36100
|
return check2.data?.["id"] === id && check2.content === expectedBody;
|
|
35794
36101
|
} catch {
|
|
35795
36102
|
return false;
|
|
35796
36103
|
}
|
|
35797
36104
|
}
|
|
35798
36105
|
|
|
35799
|
-
// src/lib/pull-write.ts
|
|
35800
|
-
var import_gray_matter9 = __toESM(require_gray_matter(), 1);
|
|
35801
|
-
import { readFileSync as readFileSync18 } from "node:fs";
|
|
35802
|
-
function computeMirrorHashes(strategy, content) {
|
|
35803
|
-
const parsed = import_gray_matter9.default(content);
|
|
35804
|
-
const fm = parsed.data ?? {};
|
|
35805
|
-
const lifted = splitUserFrontmatter(strategy, fm);
|
|
35806
|
-
const userFm = userFrontmatter(strategy, lifted.frontmatter);
|
|
35807
|
-
const hashBody = hashableBody(strategy, parsed.content);
|
|
35808
|
-
return {
|
|
35809
|
-
bodyHash: stableHash(hashBody),
|
|
35810
|
-
frontmatterHash: stableHash({ ...userFm, ...lifted.topLevel }),
|
|
35811
|
-
bodyLen: hashBody.length,
|
|
35812
|
-
frontmatterId: fm["id"]
|
|
35813
|
-
};
|
|
35814
|
-
}
|
|
35815
|
-
function hashableBody(strategy, body) {
|
|
35816
|
-
return strategy.stripLocalBlocks?.(body) ?? body;
|
|
35817
|
-
}
|
|
35818
|
-
function relocateForSlugChange(args) {
|
|
35819
|
-
const { workspaceSlug, strategy, fromSlug, toSlug, acked, echo, now } = args;
|
|
35820
|
-
if (fromSlug === toSlug)
|
|
35821
|
-
return { kind: "not_needed", writeSlug: toSlug };
|
|
35822
|
-
if (!echo) {
|
|
35823
|
-
return { kind: "skipped", writeSlug: toSlug, fromSlug, reason: "unguarded" };
|
|
35824
|
-
}
|
|
35825
|
-
if (strategy.mirrorRelativePath(fromSlug).split("/").length !== 2) {
|
|
35826
|
-
return { kind: "skipped", writeSlug: toSlug, fromSlug, reason: "foldered" };
|
|
35827
|
-
}
|
|
35828
|
-
let fromPath;
|
|
35829
|
-
try {
|
|
35830
|
-
fromPath = entityFilePath(workspaceSlug, strategy.type, fromSlug);
|
|
35831
|
-
entityFilePath(workspaceSlug, strategy.type, toSlug);
|
|
35832
|
-
} catch (err) {
|
|
35833
|
-
if (err instanceof MirrorPathError) {
|
|
35834
|
-
return {
|
|
35835
|
-
kind: "skipped",
|
|
35836
|
-
writeSlug: toSlug,
|
|
35837
|
-
fromSlug,
|
|
35838
|
-
reason: "unresolvable"
|
|
35839
|
-
};
|
|
35840
|
-
}
|
|
35841
|
-
throw err;
|
|
35842
|
-
}
|
|
35843
|
-
let raw = null;
|
|
35844
|
-
try {
|
|
35845
|
-
raw = readFileSync18(fromPath, "utf8");
|
|
35846
|
-
} catch (err) {
|
|
35847
|
-
const code = err?.code;
|
|
35848
|
-
if (code === "ENOENT") {
|
|
35849
|
-
return { kind: "absent", writeSlug: toSlug, fromSlug };
|
|
35850
|
-
}
|
|
35851
|
-
return {
|
|
35852
|
-
kind: "refused",
|
|
35853
|
-
writeSlug: fromSlug,
|
|
35854
|
-
fromSlug,
|
|
35855
|
-
reason: "source_unreadable"
|
|
35856
|
-
};
|
|
35857
|
-
}
|
|
35858
|
-
let diverged = true;
|
|
35859
|
-
try {
|
|
35860
|
-
const hashes = computeMirrorHashes(strategy, raw);
|
|
35861
|
-
diverged = hashes.bodyHash !== acked.bodyHash || hashes.frontmatterHash !== acked.frontmatterHash;
|
|
35862
|
-
} catch {
|
|
35863
|
-
diverged = true;
|
|
35864
|
-
}
|
|
35865
|
-
const stashPath = diverged ? stashConflict({
|
|
35866
|
-
workspaceSlug,
|
|
35867
|
-
entityType: strategy.type,
|
|
35868
|
-
entitySlug: fromSlug,
|
|
35869
|
-
timestamp: now(),
|
|
35870
|
-
contents: raw,
|
|
35871
|
-
side: "local"
|
|
35872
|
-
}) : undefined;
|
|
35873
|
-
try {
|
|
35874
|
-
let registered = false;
|
|
35875
|
-
const result = moveEntityFile(workspaceSlug, strategy.type, fromSlug, toSlug, () => {
|
|
35876
|
-
if (echo.watcher === "live") {
|
|
35877
|
-
echo.suppressor.registerDelete(fromPath);
|
|
35878
|
-
registered = true;
|
|
35879
|
-
}
|
|
35880
|
-
});
|
|
35881
|
-
if (result === "moved") {
|
|
35882
|
-
return { kind: "moved", writeSlug: toSlug, fromSlug, stashPath };
|
|
35883
|
-
}
|
|
35884
|
-
if (registered && echo.watcher === "live") {
|
|
35885
|
-
echo.suppressor.cancelDelete(fromPath);
|
|
35886
|
-
}
|
|
35887
|
-
return { kind: "absent", writeSlug: toSlug, fromSlug };
|
|
35888
|
-
} catch (err) {
|
|
35889
|
-
if (err instanceof MirrorDestinationOccupiedError) {
|
|
35890
|
-
return {
|
|
35891
|
-
kind: "refused",
|
|
35892
|
-
writeSlug: fromSlug,
|
|
35893
|
-
fromSlug,
|
|
35894
|
-
reason: "destination_occupied",
|
|
35895
|
-
stashPath
|
|
35896
|
-
};
|
|
35897
|
-
}
|
|
35898
|
-
if (err instanceof MirrorPathError) {
|
|
35899
|
-
return {
|
|
35900
|
-
kind: "skipped",
|
|
35901
|
-
writeSlug: toSlug,
|
|
35902
|
-
fromSlug,
|
|
35903
|
-
reason: "unresolvable"
|
|
35904
|
-
};
|
|
35905
|
-
}
|
|
35906
|
-
throw err;
|
|
35907
|
-
}
|
|
35908
|
-
}
|
|
35909
|
-
function writeMirrorWithBodyPreserve(workspaceSlug, strategy, doc2, suppressor, pathSlug) {
|
|
35910
|
-
const targetSlug = pathSlug ?? doc2.slug;
|
|
35911
|
-
const content = renderMirrorWithBodyPreserve(workspaceSlug, strategy, doc2, targetSlug);
|
|
35912
|
-
if (suppressor) {
|
|
35913
|
-
const target = entityFilePath(workspaceSlug, strategy.type, targetSlug);
|
|
35914
|
-
suppressor.registerWrite(target, computeMirrorHashes(strategy, content));
|
|
35915
|
-
}
|
|
35916
|
-
writeMirrorFile(workspaceSlug, strategy.type, targetSlug, content);
|
|
35917
|
-
return content;
|
|
35918
|
-
}
|
|
35919
|
-
function renderMirrorWithBodyPreserve(workspaceSlug, strategy, doc2, targetSlug) {
|
|
35920
|
-
let content = strategy.serialise(doc2);
|
|
35921
|
-
if (strategy.preserveLocalBodyOnPull) {
|
|
35922
|
-
const target = entityFilePath(workspaceSlug, strategy.type, targetSlug);
|
|
35923
|
-
let existing = null;
|
|
35924
|
-
try {
|
|
35925
|
-
existing = readFileSync18(target, "utf8");
|
|
35926
|
-
} catch (err) {
|
|
35927
|
-
if (err?.code !== "ENOENT")
|
|
35928
|
-
throw err;
|
|
35929
|
-
}
|
|
35930
|
-
if (existing !== null) {
|
|
35931
|
-
const existingParsed = import_gray_matter9.default(existing);
|
|
35932
|
-
const cloudParsed = import_gray_matter9.default(content);
|
|
35933
|
-
const stitched = import_gray_matter9.default.stringify(existingParsed.content, cloudParsed.data);
|
|
35934
|
-
content = stitched.endsWith(`
|
|
35935
|
-
`) ? stitched : stitched + `
|
|
35936
|
-
`;
|
|
35937
|
-
}
|
|
35938
|
-
}
|
|
35939
|
-
return content;
|
|
35940
|
-
}
|
|
35941
|
-
|
|
35942
36106
|
// src/lib/push.ts
|
|
35943
36107
|
var DELETE_DECLINED_PATH_EXISTS = "the file is on disk again — a newer write owns this row";
|
|
36108
|
+
var FRONTMATTER_PARSE_ERROR = "frontmatter parse error";
|
|
35944
36109
|
function deleteDeclinedSentence(relPath) {
|
|
35945
36110
|
return `Not deleted: ${relPath} is on disk again, so the row was left alone. If you meant to delete it, remove the file and it will be retried.`;
|
|
35946
36111
|
}
|
|
@@ -36049,8 +36214,8 @@ function stampStateFromMirror(args) {
|
|
|
36049
36214
|
const { strategy, workspaceSlug, doc: doc2, state, priorMemoryHash } = args;
|
|
36050
36215
|
const targetSlug = args.pathSlug ?? doc2.slug;
|
|
36051
36216
|
const mirrorPath = entityFilePath(workspaceSlug, strategy.type, targetSlug);
|
|
36052
|
-
const mirrorRaw =
|
|
36053
|
-
const mirrorParsed =
|
|
36217
|
+
const mirrorRaw = readFileSync20(mirrorPath, "utf8");
|
|
36218
|
+
const mirrorParsed = matter(mirrorRaw);
|
|
36054
36219
|
const mirrorFm = mirrorParsed.data ?? {};
|
|
36055
36220
|
const mirrorLifted = splitUserFrontmatter(strategy, mirrorFm);
|
|
36056
36221
|
const mirrorUserFm = userFrontmatter(strategy, mirrorLifted.frontmatter);
|
|
@@ -36202,7 +36367,7 @@ async function pushFile(args) {
|
|
|
36202
36367
|
}
|
|
36203
36368
|
let raw;
|
|
36204
36369
|
try {
|
|
36205
|
-
raw =
|
|
36370
|
+
raw = readFileSync20(absolutePath, "utf8");
|
|
36206
36371
|
} catch (err) {
|
|
36207
36372
|
if (err?.code === "ENOENT") {
|
|
36208
36373
|
return runPushDelete({
|
|
@@ -36222,23 +36387,32 @@ async function pushFile(args) {
|
|
|
36222
36387
|
}
|
|
36223
36388
|
throw err;
|
|
36224
36389
|
}
|
|
36225
|
-
let parsed;
|
|
36226
|
-
try {
|
|
36227
|
-
parsed = import_gray_matter10.default(raw);
|
|
36228
|
-
} catch {
|
|
36229
|
-
return {
|
|
36230
|
-
outcome: { kind: "ignored", absolutePath, reason: "frontmatter parse error" },
|
|
36231
|
-
state
|
|
36232
|
-
};
|
|
36233
|
-
}
|
|
36234
|
-
const fm = parsed.data ?? {};
|
|
36235
|
-
const slugFromFm = typeof fm.slug === "string" && fm.slug.length > 0 ? fm.slug : null;
|
|
36236
36390
|
let parsedSlug = null;
|
|
36237
36391
|
try {
|
|
36238
36392
|
const rel = relative5(workspaceMirrorPath(workspaceSlug), absolutePath);
|
|
36239
36393
|
parsedSlug = strategy.parseMirrorPath(rel)?.slug ?? null;
|
|
36240
36394
|
} catch {}
|
|
36241
36395
|
const slugFromPath = parsedSlug ?? basename5(absolutePath, ".md");
|
|
36396
|
+
const read = readFrontmatter(raw);
|
|
36397
|
+
if (!read.ok) {
|
|
36398
|
+
return {
|
|
36399
|
+
outcome: { kind: "ignored", absolutePath, reason: FRONTMATTER_PARSE_ERROR },
|
|
36400
|
+
state: holdUnreadableFrontmatter({
|
|
36401
|
+
state,
|
|
36402
|
+
workspaceSlug,
|
|
36403
|
+
absolutePath,
|
|
36404
|
+
entityType,
|
|
36405
|
+
slug: slugFromPath,
|
|
36406
|
+
why: read.why,
|
|
36407
|
+
now,
|
|
36408
|
+
output
|
|
36409
|
+
}),
|
|
36410
|
+
base: state
|
|
36411
|
+
};
|
|
36412
|
+
}
|
|
36413
|
+
let parsed = read.parsed;
|
|
36414
|
+
const fm = parsed.data ?? {};
|
|
36415
|
+
const slugFromFm = typeof fm.slug === "string" && fm.slug.length > 0 ? fm.slug : null;
|
|
36242
36416
|
const slug = identity === "path" ? slugFromPath : slugFromFm ?? slugFromPath;
|
|
36243
36417
|
if (!slug) {
|
|
36244
36418
|
return {
|
|
@@ -36252,14 +36426,14 @@ async function pushFile(args) {
|
|
|
36252
36426
|
if (strategy.classifyFieldErrors) {
|
|
36253
36427
|
const desiredBody = spliceSyncErrorBlock(parsed.content, fieldErrors);
|
|
36254
36428
|
if (desiredBody.replace(/\s+$/, "") !== parsed.content.replace(/\s+$/, "")) {
|
|
36255
|
-
let rewritten =
|
|
36429
|
+
let rewritten = stringifyFrontmatter(desiredBody, parsed.data ?? {});
|
|
36256
36430
|
if (!rewritten.endsWith(`
|
|
36257
36431
|
`))
|
|
36258
36432
|
rewritten += `
|
|
36259
36433
|
`;
|
|
36260
36434
|
writeMirrorFile(workspaceSlug, entityType, slug, rewritten);
|
|
36261
36435
|
raw = rewritten;
|
|
36262
|
-
parsed =
|
|
36436
|
+
parsed = parseUncached(rewritten);
|
|
36263
36437
|
}
|
|
36264
36438
|
}
|
|
36265
36439
|
const liveInode = safeInode2(absolutePath);
|
|
@@ -36537,7 +36711,7 @@ async function runPushUpsert(args) {
|
|
|
36537
36711
|
}
|
|
36538
36712
|
const wireProjection = (md) => {
|
|
36539
36713
|
try {
|
|
36540
|
-
const p =
|
|
36714
|
+
const p = matter(md);
|
|
36541
36715
|
const f = p.data ?? {};
|
|
36542
36716
|
const l = splitUserFrontmatter(strategy, f);
|
|
36543
36717
|
const u = userFrontmatter(strategy, l.frontmatter);
|
|
@@ -36552,7 +36726,7 @@ async function runPushUpsert(args) {
|
|
|
36552
36726
|
if (liveEntry !== snapshotEntry) {
|
|
36553
36727
|
let onDisk = null;
|
|
36554
36728
|
try {
|
|
36555
|
-
onDisk =
|
|
36729
|
+
onDisk = readFileSync20(args.absolutePath, "utf8");
|
|
36556
36730
|
} catch {
|
|
36557
36731
|
onDisk = null;
|
|
36558
36732
|
}
|
|
@@ -37014,7 +37188,7 @@ function writeCreatedIdBack(args) {
|
|
|
37014
37188
|
if (entityFilePath(args.workspaceSlug, args.strategy.type, args.slug) !== args.absolutePath) {
|
|
37015
37189
|
return;
|
|
37016
37190
|
}
|
|
37017
|
-
const readBack = args.readBack ?? ((p) =>
|
|
37191
|
+
const readBack = args.readBack ?? ((p) => readFileSync20(p, "utf8"));
|
|
37018
37192
|
if (readBack(args.absolutePath) !== args.raw)
|
|
37019
37193
|
return;
|
|
37020
37194
|
args.suppressor?.registerWrite(args.absolutePath, computeMirrorHashes(args.strategy, write.content));
|
|
@@ -37486,8 +37660,8 @@ async function pushRename(args) {
|
|
|
37486
37660
|
};
|
|
37487
37661
|
if (!updated.body_hash || !updated.frontmatter_hash) {
|
|
37488
37662
|
try {
|
|
37489
|
-
const mirrorRaw =
|
|
37490
|
-
const mirrorParsed =
|
|
37663
|
+
const mirrorRaw = readFileSync20(toPath, "utf8");
|
|
37664
|
+
const mirrorParsed = matter(mirrorRaw);
|
|
37491
37665
|
const renameFm = mirrorParsed.data ?? {};
|
|
37492
37666
|
const renameLifted = splitUserFrontmatter(strategy, renameFm);
|
|
37493
37667
|
const renameUserFm = userFrontmatter(strategy, renameLifted.frontmatter);
|
|
@@ -37523,7 +37697,7 @@ async function pushRename(args) {
|
|
|
37523
37697
|
if (patchResult.reason === "slug_conflict") {
|
|
37524
37698
|
let contents2 = "";
|
|
37525
37699
|
try {
|
|
37526
|
-
contents2 =
|
|
37700
|
+
contents2 = readFileSync20(toPath, "utf8");
|
|
37527
37701
|
} catch {}
|
|
37528
37702
|
const stashPath2 = stashConflict({
|
|
37529
37703
|
workspaceSlug,
|
|
@@ -37571,7 +37745,7 @@ async function pushRename(args) {
|
|
|
37571
37745
|
}
|
|
37572
37746
|
let contents = "";
|
|
37573
37747
|
try {
|
|
37574
|
-
contents =
|
|
37748
|
+
contents = readFileSync20(toPath, "utf8");
|
|
37575
37749
|
} catch {}
|
|
37576
37750
|
const stashPath = stashConflict({
|
|
37577
37751
|
workspaceSlug,
|
|
@@ -37704,7 +37878,7 @@ async function discardBatchOps(batch, deps) {
|
|
|
37704
37878
|
const path5 = opPath(deps.workspaceSlug, op);
|
|
37705
37879
|
let local = null;
|
|
37706
37880
|
try {
|
|
37707
|
-
local =
|
|
37881
|
+
local = readFileSync21(path5, "utf8");
|
|
37708
37882
|
} catch {
|
|
37709
37883
|
local = null;
|
|
37710
37884
|
}
|
|
@@ -37743,7 +37917,7 @@ async function discardFileOp(op, deps) {
|
|
|
37743
37917
|
const abs = filesSubtreePath(deps.workspaceSlug, op.path);
|
|
37744
37918
|
let local = null;
|
|
37745
37919
|
try {
|
|
37746
|
-
local =
|
|
37920
|
+
local = readFileSync21(abs);
|
|
37747
37921
|
} catch {
|
|
37748
37922
|
local = null;
|
|
37749
37923
|
}
|
|
@@ -37780,7 +37954,7 @@ function opPath(workspaceSlug, op) {
|
|
|
37780
37954
|
}
|
|
37781
37955
|
|
|
37782
37956
|
// src/lib/files/classify.ts
|
|
37783
|
-
import { relative as relative6, sep as
|
|
37957
|
+
import { relative as relative6, sep as sep6 } from "node:path";
|
|
37784
37958
|
var FILES_SUBTREE = "files";
|
|
37785
37959
|
function classifyFilesPath(args) {
|
|
37786
37960
|
let root;
|
|
@@ -37790,20 +37964,20 @@ function classifyFilesPath(args) {
|
|
|
37790
37964
|
return null;
|
|
37791
37965
|
}
|
|
37792
37966
|
const rel = relative6(root, args.absolutePath);
|
|
37793
|
-
if (rel.startsWith("..") || rel.startsWith(
|
|
37967
|
+
if (rel.startsWith("..") || rel.startsWith(sep6))
|
|
37794
37968
|
return null;
|
|
37795
|
-
const prefix = FILES_SUBTREE +
|
|
37969
|
+
const prefix = FILES_SUBTREE + sep6;
|
|
37796
37970
|
if (!rel.startsWith(prefix))
|
|
37797
37971
|
return null;
|
|
37798
37972
|
const sub = rel.slice(prefix.length);
|
|
37799
37973
|
if (sub.length === 0)
|
|
37800
37974
|
return null;
|
|
37801
|
-
const posix =
|
|
37975
|
+
const posix = sep6 === "/" ? sub : sub.split(sep6).join("/");
|
|
37802
37976
|
return validateFilesRelPath(posix) ? { relPath: posix } : null;
|
|
37803
37977
|
}
|
|
37804
37978
|
|
|
37805
37979
|
// src/lib/memory-facts/sync.ts
|
|
37806
|
-
import { isAbsolute as isAbsolute2, relative as relative7, sep as
|
|
37980
|
+
import { isAbsolute as isAbsolute2, relative as relative7, sep as sep7 } from "node:path";
|
|
37807
37981
|
|
|
37808
37982
|
// src/lib/memory-facts/api.ts
|
|
37809
37983
|
var FactCommonSchema = exports_external.object({
|
|
@@ -38547,7 +38721,7 @@ function classifyMemoryFactPath(args) {
|
|
|
38547
38721
|
const rel = relative7(root, args.absolutePath);
|
|
38548
38722
|
if (rel === "" || rel.startsWith("..") || isAbsolute2(rel))
|
|
38549
38723
|
return null;
|
|
38550
|
-
const mirrorRel = `${MEMORY_FACTS_DIR}/${rel.split(
|
|
38724
|
+
const mirrorRel = `${MEMORY_FACTS_DIR}/${rel.split(sep7).join("/")}`;
|
|
38551
38725
|
return { relPath: mirrorRel, fact: parseMemoryFactRelPath(mirrorRel) };
|
|
38552
38726
|
}
|
|
38553
38727
|
function classifyMemoryFactEvent(args) {
|
|
@@ -38644,7 +38818,7 @@ function evaluateFileBatch(ops, population, thresholds = defaultThresholds()) {
|
|
|
38644
38818
|
}
|
|
38645
38819
|
};
|
|
38646
38820
|
}
|
|
38647
|
-
return
|
|
38821
|
+
return evaluateLoneOverwrite(count, ops.map((op) => op.kind === "overwrite" ? op.priorSize - op.newSize : 0), thresholds.loneMinRemovedBytes);
|
|
38648
38822
|
}
|
|
38649
38823
|
function dedupeFileOps(ops) {
|
|
38650
38824
|
const byKey = new Map;
|
|
@@ -38715,7 +38889,7 @@ class FileDestructiveGate {
|
|
|
38715
38889
|
}
|
|
38716
38890
|
|
|
38717
38891
|
// src/lib/files/reconcile.ts
|
|
38718
|
-
import { readFileSync as
|
|
38892
|
+
import { readFileSync as readFileSync22, statSync as statSync10 } from "node:fs";
|
|
38719
38893
|
|
|
38720
38894
|
// src/lib/unsynced.ts
|
|
38721
38895
|
import { join as join14, relative as relative8 } from "node:path";
|
|
@@ -39711,7 +39885,7 @@ class NodeFsHandler {
|
|
|
39711
39885
|
this._addToNodeFs(path5, initialAdd, wh, depth + 1);
|
|
39712
39886
|
}
|
|
39713
39887
|
}).on(EV.ERROR, this._boundHandleError);
|
|
39714
|
-
return new Promise((
|
|
39888
|
+
return new Promise((resolve6, reject) => {
|
|
39715
39889
|
if (!stream)
|
|
39716
39890
|
return reject();
|
|
39717
39891
|
stream.once(STR_END, () => {
|
|
@@ -39720,7 +39894,7 @@ class NodeFsHandler {
|
|
|
39720
39894
|
return;
|
|
39721
39895
|
}
|
|
39722
39896
|
const wasThrottled = throttler ? throttler.clear() : false;
|
|
39723
|
-
|
|
39897
|
+
resolve6(undefined);
|
|
39724
39898
|
previous.getChildren().filter((item) => {
|
|
39725
39899
|
return item !== directory && !current.has(item);
|
|
39726
39900
|
}).forEach((item) => {
|
|
@@ -40479,7 +40653,7 @@ var chokidar_default = { watch, FSWatcher };
|
|
|
40479
40653
|
|
|
40480
40654
|
// src/lib/watcher.ts
|
|
40481
40655
|
import { statSync as statSync9 } from "node:fs";
|
|
40482
|
-
import { sep as
|
|
40656
|
+
import { sep as sep8 } from "node:path";
|
|
40483
40657
|
|
|
40484
40658
|
// src/lib/rename-classifier.ts
|
|
40485
40659
|
class RenameClassifier {
|
|
@@ -40610,7 +40784,7 @@ function watcherIgnoreMatcher(workspaceRoot) {
|
|
|
40610
40784
|
return (absolutePath) => patterns.some((re) => re.test(absolutePath));
|
|
40611
40785
|
}
|
|
40612
40786
|
function escSep() {
|
|
40613
|
-
return
|
|
40787
|
+
return sep8 === "/" ? "/" : "\\\\";
|
|
40614
40788
|
}
|
|
40615
40789
|
|
|
40616
40790
|
class DebounceMap {
|
|
@@ -40754,7 +40928,7 @@ function readBlobForPush(args) {
|
|
|
40754
40928
|
}
|
|
40755
40929
|
let bytes;
|
|
40756
40930
|
try {
|
|
40757
|
-
bytes =
|
|
40931
|
+
bytes = readFileSync22(absolutePath);
|
|
40758
40932
|
} catch (err) {
|
|
40759
40933
|
if (err?.code === "ENOENT")
|
|
40760
40934
|
return { kind: "gone" };
|
|
@@ -40897,7 +41071,7 @@ async function reconcileFilesSubtree(args) {
|
|
|
40897
41071
|
ops: pendingOps
|
|
40898
41072
|
});
|
|
40899
41073
|
quarantined = ops.length;
|
|
40900
|
-
output?.log(`[DESTRUCTIVE_HELD batch=${batchId} ops=${ops.length} reason=${result.reason
|
|
41074
|
+
output?.log(`[DESTRUCTIVE_HELD batch=${batchId} ops=${ops.length} reason=${tripReasonToken(result.reason)} source=files-reconcile]`);
|
|
40901
41075
|
} else {
|
|
40902
41076
|
for (const c of guttingCandidates) {
|
|
40903
41077
|
await pushDivergedBlob(c.op.relPath, c.op.absolutePath, c.prepared);
|
|
@@ -41064,7 +41238,7 @@ function applyArtistMemoryOnPull(args) {
|
|
|
41064
41238
|
const cloudMemory = live.memory;
|
|
41065
41239
|
const generated = live.memory_generated === true;
|
|
41066
41240
|
const local = readArtistMemoryFile(workspaceSlug, slug);
|
|
41067
|
-
const
|
|
41241
|
+
const refuse2 = (localContent, canonical2) => {
|
|
41068
41242
|
const refused = refuseGeneratedMemoryEdit({
|
|
41069
41243
|
state,
|
|
41070
41244
|
workspaceSlug,
|
|
@@ -41093,7 +41267,7 @@ function applyArtistMemoryOnPull(args) {
|
|
|
41093
41267
|
const cloudHash = stableHash(cloudMemory);
|
|
41094
41268
|
if (cloudHash === ackedMemoryHash && local !== null) {
|
|
41095
41269
|
if (generated && stableHash(local) !== ackedMemoryHash) {
|
|
41096
|
-
|
|
41270
|
+
refuse2(local, cloudMemory);
|
|
41097
41271
|
return { memoryHash: cloudHash, state };
|
|
41098
41272
|
}
|
|
41099
41273
|
if (generated) {
|
|
@@ -41105,7 +41279,7 @@ function applyArtistMemoryOnPull(args) {
|
|
|
41105
41279
|
const localHash = stableHash(local);
|
|
41106
41280
|
if (localHash !== ackedMemoryHash && localHash !== cloudHash) {
|
|
41107
41281
|
if (generated) {
|
|
41108
|
-
|
|
41282
|
+
refuse2(local, cloudMemory);
|
|
41109
41283
|
return { memoryHash: cloudHash, state };
|
|
41110
41284
|
}
|
|
41111
41285
|
const stashPath = stashConflict({
|
|
@@ -41815,7 +41989,7 @@ function anyUnknown(state) {
|
|
|
41815
41989
|
}
|
|
41816
41990
|
|
|
41817
41991
|
// src/lib/memory/write.ts
|
|
41818
|
-
import { readFileSync as
|
|
41992
|
+
import { readFileSync as readFileSync23, statSync as statSync11 } from "node:fs";
|
|
41819
41993
|
|
|
41820
41994
|
// src/lib/files/extracted-text.ts
|
|
41821
41995
|
import { createHash as createHash5 } from "node:crypto";
|
|
@@ -41896,7 +42070,6 @@ function extractedTextHash(rendered) {
|
|
|
41896
42070
|
}
|
|
41897
42071
|
|
|
41898
42072
|
// src/lib/memory/splice.ts
|
|
41899
|
-
var import_gray_matter11 = __toESM(require_gray_matter(), 1);
|
|
41900
42073
|
var OPEN_RE = /^---\r?\n/;
|
|
41901
42074
|
function findFrontmatter(content) {
|
|
41902
42075
|
const open2 = OPEN_RE.exec(content);
|
|
@@ -41982,7 +42155,7 @@ function spliceAnnotation(content, lines) {
|
|
|
41982
42155
|
}
|
|
41983
42156
|
function parsesAsFrontmatter(content) {
|
|
41984
42157
|
try {
|
|
41985
|
-
|
|
42158
|
+
matter(content, { cache: false });
|
|
41986
42159
|
return true;
|
|
41987
42160
|
} catch {
|
|
41988
42161
|
return false;
|
|
@@ -42010,7 +42183,7 @@ function writeDocumentAnnotation(args) {
|
|
|
42010
42183
|
}
|
|
42011
42184
|
let current;
|
|
42012
42185
|
try {
|
|
42013
|
-
current =
|
|
42186
|
+
current = readFileSync23(target, "utf8");
|
|
42014
42187
|
} catch {
|
|
42015
42188
|
return { kind: "absent" };
|
|
42016
42189
|
}
|
|
@@ -42048,18 +42221,32 @@ function writeFileTextAnnotation(args) {
|
|
|
42048
42221
|
const current = readExtractedText(args.workspaceSlug, args.relPath);
|
|
42049
42222
|
if (current === null)
|
|
42050
42223
|
return { kind: "absent" };
|
|
42051
|
-
|
|
42224
|
+
const onDisk = extractedTextHash(current);
|
|
42225
|
+
const acked = args.textHash;
|
|
42226
|
+
const offAck = acked !== undefined && onDisk !== acked;
|
|
42227
|
+
if (acked !== undefined && offAck && !isOwnRender(current, acked, args.priorLines)) {
|
|
42052
42228
|
return { kind: "diverged", relPath: extractedTextRelPath(args.relPath) };
|
|
42053
42229
|
}
|
|
42054
42230
|
const spliced = spliceAnnotation(current, args.lines);
|
|
42055
|
-
if (!spliced.changed)
|
|
42056
|
-
return { kind: "unchanged" };
|
|
42231
|
+
if (!spliced.changed) {
|
|
42232
|
+
return offAck ? { kind: "unchanged", textHash: onDisk } : { kind: "unchanged" };
|
|
42233
|
+
}
|
|
42057
42234
|
writeExtractedText(args.workspaceSlug, args.relPath, spliced.content);
|
|
42058
42235
|
return { kind: "written", textHash: extractedTextHash(spliced.content) };
|
|
42059
42236
|
}
|
|
42237
|
+
function isOwnRender(current, ackedHash, priorLines) {
|
|
42238
|
+
if (extractedTextHash(spliceAnnotation(current, []).content) === ackedHash)
|
|
42239
|
+
return true;
|
|
42240
|
+
if (priorLines === undefined)
|
|
42241
|
+
return false;
|
|
42242
|
+
return extractedTextHash(spliceAnnotation(current, priorLines).content) === ackedHash;
|
|
42243
|
+
}
|
|
42060
42244
|
function divergedNotice(relPath, state) {
|
|
42061
42245
|
return `${relPath}: its memory context is now "${state}", but the file has local ` + `edits so the marker was not written into it. Your edits are untouched. ` + `Resolve the edit and the next sync writes the marker.`;
|
|
42062
42246
|
}
|
|
42247
|
+
function generatedDivergedNotice(relPath) {
|
|
42248
|
+
return `${relPath}: this generated file does not match Plinth's record of it, ` + `so its memory marker was not written. Plinth rewrites the file when its ` + `source next changes; changes made to it here are not synced.`;
|
|
42249
|
+
}
|
|
42063
42250
|
function unreadableNotice(relPath, why) {
|
|
42064
42251
|
const reason = why.replace(/\s+/g, " ").trim().slice(0, 120);
|
|
42065
42252
|
return `${relPath}: its memory context could not be written because the file's ` + `frontmatter could not be read (${reason}). The file is untouched. Fix the ` + `frontmatter and the next sync writes the marker.`;
|
|
@@ -42089,6 +42276,10 @@ function heldFileTexts(state) {
|
|
|
42089
42276
|
textHash: f.text_hash
|
|
42090
42277
|
}));
|
|
42091
42278
|
}
|
|
42279
|
+
function priorFileLines(state, id) {
|
|
42280
|
+
return getMemorySourceEntries(state, "workspace_files")[id]?.rendered.split(`
|
|
42281
|
+
`);
|
|
42282
|
+
}
|
|
42092
42283
|
async function writeChanged(args) {
|
|
42093
42284
|
const docs = new Map(heldDocuments(args.state).map((d) => [d.id, d.slug]));
|
|
42094
42285
|
const texts = new Map(heldFileTexts(args.state).map((f) => [f.id, f]));
|
|
@@ -42188,7 +42379,8 @@ async function writeChanged(args) {
|
|
|
42188
42379
|
workspaceSlug: args.workspaceSlug,
|
|
42189
42380
|
relPath: file2.relPath,
|
|
42190
42381
|
textHash: args.freshTextHashes?.get(answer2.id) ?? file2.textHash,
|
|
42191
|
-
lines: answer2.lines
|
|
42382
|
+
lines: answer2.lines,
|
|
42383
|
+
priorLines: priorFileLines(args.state, answer2.id)
|
|
42192
42384
|
});
|
|
42193
42385
|
if (res.kind !== "diverged" && res.kind !== "absent") {
|
|
42194
42386
|
args.onWritten?.("workspace_files", answer2.id, res.textHash);
|
|
@@ -42215,7 +42407,7 @@ async function writeChanged(args) {
|
|
|
42215
42407
|
}
|
|
42216
42408
|
const textPath = extractedTextRelPath(file2.relPath);
|
|
42217
42409
|
if (outcome.kind === "diverged") {
|
|
42218
|
-
report.push({ path: textPath, record:
|
|
42410
|
+
report.push({ path: textPath, record: generatedDivergedNotice(textPath) });
|
|
42219
42411
|
} else {
|
|
42220
42412
|
clear.push(textPath);
|
|
42221
42413
|
}
|
|
@@ -42224,9 +42416,11 @@ async function writeChanged(args) {
|
|
|
42224
42416
|
if (outcome.textHash !== undefined) {
|
|
42225
42417
|
textHashes.set(file2.relPath, { to: outcome.textHash });
|
|
42226
42418
|
}
|
|
42419
|
+
} else if (outcome.kind === "unchanged" && outcome.textHash !== undefined) {
|
|
42420
|
+
textHashes.set(file2.relPath, { to: outcome.textHash });
|
|
42227
42421
|
} else if (outcome.kind === "diverged") {
|
|
42228
42422
|
diverged++;
|
|
42229
|
-
notices.push(
|
|
42423
|
+
notices.push(generatedDivergedNotice(outcome.relPath));
|
|
42230
42424
|
}
|
|
42231
42425
|
}
|
|
42232
42426
|
if (args.abortIfStale?.() === true) {
|
|
@@ -43948,8 +44142,7 @@ class PullSuppressor {
|
|
|
43948
44142
|
}
|
|
43949
44143
|
|
|
43950
44144
|
// src/lib/discover-entities.ts
|
|
43951
|
-
|
|
43952
|
-
import { readFileSync as readFileSync23, statSync as statSync12 } from "node:fs";
|
|
44145
|
+
import { readFileSync as readFileSync24, statSync as statSync12 } from "node:fs";
|
|
43953
44146
|
var DISCOVERY_WRITE_CAP_DEFAULT = 10;
|
|
43954
44147
|
function discoveryWriteCap() {
|
|
43955
44148
|
const raw = process.env.PLINTH_DISCOVERY_WRITE_CAP;
|
|
@@ -43976,6 +44169,11 @@ function classifyUntrackedEntity(args) {
|
|
|
43976
44169
|
}
|
|
43977
44170
|
return { kind: "create" };
|
|
43978
44171
|
}
|
|
44172
|
+
function holdsUnreadableUntracked(args) {
|
|
44173
|
+
if (args.readable)
|
|
44174
|
+
return false;
|
|
44175
|
+
return classifyUntrackedEntity({ ...args, frontmatter: {} }).kind === "create";
|
|
44176
|
+
}
|
|
43979
44177
|
function classifyRenameDestination(args) {
|
|
43980
44178
|
const occupant = getEntryBySlug(args.state, args.entityType, args.entitySlug);
|
|
43981
44179
|
if (occupant && occupant.id !== args.movedEntryId) {
|
|
@@ -44046,13 +44244,20 @@ function planDiscoveryWrites(args) {
|
|
|
44046
44244
|
if (getEntryBySlug(state, entityType, entitySlug))
|
|
44047
44245
|
continue;
|
|
44048
44246
|
counts.discovered++;
|
|
44049
|
-
let
|
|
44247
|
+
let raw;
|
|
44050
44248
|
try {
|
|
44051
|
-
|
|
44249
|
+
raw = readFileSync24(absolutePath, "utf8");
|
|
44052
44250
|
} catch {
|
|
44053
44251
|
counts.discovered--;
|
|
44054
44252
|
continue;
|
|
44055
44253
|
}
|
|
44254
|
+
const read = readFrontmatter(raw);
|
|
44255
|
+
if (!read.ok && holdsUnreadableUntracked({ entityType, entitySlug, readable: false })) {
|
|
44256
|
+
counts.discovered--;
|
|
44257
|
+
planned.push({ kind: "unreadable", entityType, entitySlug, absolutePath, why: read.why });
|
|
44258
|
+
continue;
|
|
44259
|
+
}
|
|
44260
|
+
const frontmatter = read.ok ? read.parsed.data : {};
|
|
44056
44261
|
const verdict = classifyUntrackedEntity({ entityType, entitySlug, frontmatter });
|
|
44057
44262
|
if (verdict.kind === "hold") {
|
|
44058
44263
|
if (verdict.held === "artist")
|
|
@@ -44093,7 +44298,7 @@ async function discoverUntrackedEntities(args) {
|
|
|
44093
44298
|
}
|
|
44094
44299
|
const cap = discoveryWriteCap();
|
|
44095
44300
|
const creates = planned.filter((w) => w.kind === "create");
|
|
44096
|
-
const toRun = creates.length > cap ? planned.filter((w) => w.kind
|
|
44301
|
+
const toRun = creates.length > cap ? planned.filter((w) => w.kind !== "create") : planned;
|
|
44097
44302
|
if (creates.length > cap) {
|
|
44098
44303
|
counts.heldCap = creates.length;
|
|
44099
44304
|
output?.log(`[DISCOVERY_HELD reason=cap creates=${creates.length} cap=${cap} source=entity-discovery]`);
|
|
@@ -44116,6 +44321,19 @@ async function runPlannedWrites(args) {
|
|
|
44116
44321
|
let state = args.state;
|
|
44117
44322
|
for (const write of planned) {
|
|
44118
44323
|
try {
|
|
44324
|
+
if (write.kind === "unreadable") {
|
|
44325
|
+
state = holdUnreadableFrontmatter({
|
|
44326
|
+
state,
|
|
44327
|
+
workspaceSlug,
|
|
44328
|
+
absolutePath: write.absolutePath,
|
|
44329
|
+
entityType: write.entityType,
|
|
44330
|
+
slug: write.entitySlug,
|
|
44331
|
+
why: write.why,
|
|
44332
|
+
now,
|
|
44333
|
+
output
|
|
44334
|
+
});
|
|
44335
|
+
continue;
|
|
44336
|
+
}
|
|
44119
44337
|
if (write.kind === "rename") {
|
|
44120
44338
|
state = await runDiscoveredRename({
|
|
44121
44339
|
write,
|
|
@@ -44276,8 +44494,7 @@ function recordDiscoveryFailure(args) {
|
|
|
44276
44494
|
}
|
|
44277
44495
|
|
|
44278
44496
|
// src/lib/frontmatter-id-backfill.ts
|
|
44279
|
-
|
|
44280
|
-
import { readFileSync as readFileSync24, statSync as statSync13 } from "node:fs";
|
|
44497
|
+
import { readFileSync as readFileSync25, statSync as statSync13 } from "node:fs";
|
|
44281
44498
|
var FRONTMATTER_ID_BACKFILL_VERSION = 1;
|
|
44282
44499
|
function backfillWorthReporting(r) {
|
|
44283
44500
|
return r.written > 0 || r.failed > 0 || r.skipped.foreignId > 0 || r.skipped.unwritable > 0 || r.skipped.slugCollision > 0;
|
|
@@ -44320,7 +44537,7 @@ function safeInode3(path5) {
|
|
|
44320
44537
|
function backfillFrontmatterIds(args) {
|
|
44321
44538
|
const { workspaceSlug, state } = args;
|
|
44322
44539
|
const compose = args.compose ?? withFrontmatterId;
|
|
44323
|
-
const readRaw = args.readFile ?? ((p) =>
|
|
44540
|
+
const readRaw = args.readFile ?? ((p) => readFileSync25(p, "utf8"));
|
|
44324
44541
|
const result = emptyResult();
|
|
44325
44542
|
if (state.frontmatter_id_backfill_version === FRONTMATTER_ID_BACKFILL_VERSION) {
|
|
44326
44543
|
return result;
|
|
@@ -44369,7 +44586,7 @@ function backfillFrontmatterIds(args) {
|
|
|
44369
44586
|
let rawBody;
|
|
44370
44587
|
let parsedData;
|
|
44371
44588
|
try {
|
|
44372
|
-
const parsed =
|
|
44589
|
+
const parsed = parseUncached(raw);
|
|
44373
44590
|
parsedData = parsed.data ?? {};
|
|
44374
44591
|
existing = parsedData["id"];
|
|
44375
44592
|
rawBody = parsed.content;
|
|
@@ -44448,11 +44665,11 @@ function backfillFrontmatterIds(args) {
|
|
|
44448
44665
|
}
|
|
44449
44666
|
|
|
44450
44667
|
// src/lib/reconcile.ts
|
|
44451
|
-
import { readFileSync as
|
|
44668
|
+
import { readFileSync as readFileSync26, statSync as statSync14 } from "node:fs";
|
|
44452
44669
|
async function reconcileDivergedRows(args) {
|
|
44453
44670
|
const { workspaceSlug, baseUrl, pat, fetchImpl, output, isFrozen } = args;
|
|
44454
44671
|
const now = args.now ?? (() => new Date);
|
|
44455
|
-
let state = args.state;
|
|
44672
|
+
let state = settleFrontmatterHolds(args.state, workspaceSlug);
|
|
44456
44673
|
let scanned = 0;
|
|
44457
44674
|
let diverged = 0;
|
|
44458
44675
|
let pushed = 0;
|
|
@@ -44560,7 +44777,7 @@ async function reconcileDivergedRows(args) {
|
|
|
44560
44777
|
}
|
|
44561
44778
|
let content;
|
|
44562
44779
|
try {
|
|
44563
|
-
content =
|
|
44780
|
+
content = readFileSync26(absolutePath, "utf8");
|
|
44564
44781
|
} catch (err) {
|
|
44565
44782
|
if (err?.code === "ENOENT") {
|
|
44566
44783
|
state = clearEntityCloudRowDeleted(state, strategy.mirrorRelativePath(entry2.slug));
|
|
@@ -44568,6 +44785,20 @@ async function reconcileDivergedRows(args) {
|
|
|
44568
44785
|
}
|
|
44569
44786
|
throw err;
|
|
44570
44787
|
}
|
|
44788
|
+
const unreadable = frontmatterParseError(content);
|
|
44789
|
+
if (unreadable !== null) {
|
|
44790
|
+
state = holdUnreadableFrontmatter({
|
|
44791
|
+
state,
|
|
44792
|
+
workspaceSlug,
|
|
44793
|
+
absolutePath,
|
|
44794
|
+
entityType,
|
|
44795
|
+
slug: entry2.slug,
|
|
44796
|
+
why: unreadable,
|
|
44797
|
+
now,
|
|
44798
|
+
output
|
|
44799
|
+
});
|
|
44800
|
+
continue;
|
|
44801
|
+
}
|
|
44571
44802
|
const hashes = computeMirrorHashes(strategy, content);
|
|
44572
44803
|
if (hashes.frontmatterId === undefined)
|
|
44573
44804
|
sawTrackedFileWithoutId = true;
|
|
@@ -44618,7 +44849,7 @@ async function reconcileDivergedRows(args) {
|
|
|
44618
44849
|
ops: pendingOps
|
|
44619
44850
|
});
|
|
44620
44851
|
quarantined = ops.length;
|
|
44621
|
-
output?.log(`[DESTRUCTIVE_HELD batch=${batchId} ops=${ops.length} reason=${result.reason
|
|
44852
|
+
output?.log(`[DESTRUCTIVE_HELD batch=${batchId} ops=${ops.length} reason=${tripReasonToken(result.reason)} source=reconcile]`);
|
|
44622
44853
|
} else {
|
|
44623
44854
|
for (const c of guttingCandidates) {
|
|
44624
44855
|
const op = c.op;
|
|
@@ -45849,7 +46080,7 @@ class Semaphore {
|
|
|
45849
46080
|
this.active += 1;
|
|
45850
46081
|
return;
|
|
45851
46082
|
}
|
|
45852
|
-
await new Promise((
|
|
46083
|
+
await new Promise((resolve7) => this.waiters.push(resolve7));
|
|
45853
46084
|
}
|
|
45854
46085
|
release() {
|
|
45855
46086
|
const next = this.waiters.shift();
|
|
@@ -45911,9 +46142,9 @@ function createThrottledFetch(baseFetch, opts = {}) {
|
|
|
45911
46142
|
// src/commands/sync.ts
|
|
45912
46143
|
import {
|
|
45913
46144
|
existsSync as existsSync9,
|
|
45914
|
-
lstatSync as
|
|
46145
|
+
lstatSync as lstatSync7,
|
|
45915
46146
|
readdirSync as readdirSync7,
|
|
45916
|
-
readFileSync as
|
|
46147
|
+
readFileSync as readFileSync30,
|
|
45917
46148
|
statSync as statSync17,
|
|
45918
46149
|
unlinkSync as unlinkSync9
|
|
45919
46150
|
} from "node:fs";
|
|
@@ -46097,17 +46328,17 @@ function refreshConflictsView(workspaceSlug) {
|
|
|
46097
46328
|
}
|
|
46098
46329
|
|
|
46099
46330
|
// src/lib/files/pull.ts
|
|
46100
|
-
import { existsSync as existsSync8, lstatSync as
|
|
46331
|
+
import { existsSync as existsSync8, lstatSync as lstatSync6, readFileSync as readFileSync28, statSync as statSync15 } from "node:fs";
|
|
46101
46332
|
import { dirname as dirname13 } from "node:path";
|
|
46102
46333
|
|
|
46103
46334
|
// src/lib/permanent-disposition.ts
|
|
46104
46335
|
import { createHash as createHash6 } from "node:crypto";
|
|
46105
|
-
import { readFileSync as
|
|
46336
|
+
import { readFileSync as readFileSync27 } from "node:fs";
|
|
46106
46337
|
function sha256(value) {
|
|
46107
46338
|
return createHash6("sha256").update(value).digest("hex");
|
|
46108
46339
|
}
|
|
46109
46340
|
function verifyStash(path5, expectedHash) {
|
|
46110
|
-
const actual = sha256(
|
|
46341
|
+
const actual = sha256(readFileSync27(path5));
|
|
46111
46342
|
if (actual !== expectedHash) {
|
|
46112
46343
|
throw new Error(`permanent deletion stash verification failed for ${path5}`);
|
|
46113
46344
|
}
|
|
@@ -46151,7 +46382,7 @@ function disposePermanentDocumentLocked(args) {
|
|
|
46151
46382
|
const target = entityFilePath(args.workspaceSlug, args.strategy.type, retiredEntry?.slug ?? t.logicalKey);
|
|
46152
46383
|
let raw;
|
|
46153
46384
|
try {
|
|
46154
|
-
raw =
|
|
46385
|
+
raw = readFileSync27(target, "utf8");
|
|
46155
46386
|
} catch (error52) {
|
|
46156
46387
|
if (error52?.code !== "ENOENT")
|
|
46157
46388
|
throw error52;
|
|
@@ -46249,7 +46480,7 @@ function disposePermanentFileLocked(args) {
|
|
|
46249
46480
|
const target = filesSubtreePath(args.workspaceSlug, t.logicalKey);
|
|
46250
46481
|
let bytes;
|
|
46251
46482
|
try {
|
|
46252
|
-
bytes =
|
|
46483
|
+
bytes = readFileSync27(target);
|
|
46253
46484
|
} catch (error52) {
|
|
46254
46485
|
if (error52?.code !== "ENOENT")
|
|
46255
46486
|
throw error52;
|
|
@@ -46741,7 +46972,7 @@ async function applyFileRow(args) {
|
|
|
46741
46972
|
}
|
|
46742
46973
|
let localBytes;
|
|
46743
46974
|
try {
|
|
46744
|
-
localBytes =
|
|
46975
|
+
localBytes = readFileSync28(abs);
|
|
46745
46976
|
} catch {
|
|
46746
46977
|
localBytes = undefined;
|
|
46747
46978
|
}
|
|
@@ -46958,7 +47189,7 @@ function stashUnpushedLocalEdit(args) {
|
|
|
46958
47189
|
return { reason: "symlink" };
|
|
46959
47190
|
let st;
|
|
46960
47191
|
try {
|
|
46961
|
-
st =
|
|
47192
|
+
st = lstatSync6(abs);
|
|
46962
47193
|
} catch (err) {
|
|
46963
47194
|
if (err?.code === "ENOENT")
|
|
46964
47195
|
return null;
|
|
@@ -46968,7 +47199,7 @@ function stashUnpushedLocalEdit(args) {
|
|
|
46968
47199
|
return { reason: "not_a_file" };
|
|
46969
47200
|
let localBytes;
|
|
46970
47201
|
try {
|
|
46971
|
-
localBytes =
|
|
47202
|
+
localBytes = readFileSync28(abs);
|
|
46972
47203
|
} catch (err) {
|
|
46973
47204
|
return { reason: "unreadable", code: errCode(err) };
|
|
46974
47205
|
}
|
|
@@ -47018,7 +47249,7 @@ function textIsCurrent(existing, row, workspaceSlug, relPath) {
|
|
|
47018
47249
|
}
|
|
47019
47250
|
|
|
47020
47251
|
// src/lib/files/rejection-sync.ts
|
|
47021
|
-
import { readFileSync as
|
|
47252
|
+
import { readFileSync as readFileSync29, statSync as statSync16 } from "node:fs";
|
|
47022
47253
|
|
|
47023
47254
|
// src/lib/files/rejections-api.ts
|
|
47024
47255
|
var RejectionsFeedSchema = exports_external.object({
|
|
@@ -47151,7 +47382,7 @@ function settledDisposition(args) {
|
|
|
47151
47382
|
return null;
|
|
47152
47383
|
let bytes;
|
|
47153
47384
|
try {
|
|
47154
|
-
bytes =
|
|
47385
|
+
bytes = readFileSync29(absolute2);
|
|
47155
47386
|
} catch {
|
|
47156
47387
|
return null;
|
|
47157
47388
|
}
|
|
@@ -47267,7 +47498,7 @@ function unlinkIfProvablyOurs(workspaceSlug, strategy, entry2, suppressor) {
|
|
|
47267
47498
|
}
|
|
47268
47499
|
let raw;
|
|
47269
47500
|
try {
|
|
47270
|
-
raw =
|
|
47501
|
+
raw = readFileSync30(target, "utf8");
|
|
47271
47502
|
} catch (err) {
|
|
47272
47503
|
if (err?.code === "ENOENT") {
|
|
47273
47504
|
return { didUnlink: false };
|
|
@@ -48144,13 +48375,16 @@ function applyRow(workspaceSlug, strategy, row, state, out, suppressor, now = ()
|
|
|
48144
48375
|
if (!suppressor && existingEntry && existingEntry.updated_at !== live.updated_at && relocation.kind !== "moved") {
|
|
48145
48376
|
let localRaw = null;
|
|
48146
48377
|
try {
|
|
48147
|
-
localRaw =
|
|
48378
|
+
localRaw = readFileSync30(entityFilePath(workspaceSlug, strategy.type, writeSlug), "utf8");
|
|
48148
48379
|
} catch {
|
|
48149
48380
|
localRaw = null;
|
|
48150
48381
|
}
|
|
48151
48382
|
if (localRaw !== null) {
|
|
48152
|
-
|
|
48153
|
-
|
|
48383
|
+
let diverged = !strategy.preserveLocalBodyOnPull && frontmatterParseError(localRaw) !== null;
|
|
48384
|
+
if (!diverged) {
|
|
48385
|
+
const localHashes = computeMirrorHashes(strategy, localRaw);
|
|
48386
|
+
diverged = localHashes.bodyHash !== existingEntry.body_hash || localHashes.frontmatterHash !== existingEntry.frontmatter_hash;
|
|
48387
|
+
}
|
|
48154
48388
|
if (diverged) {
|
|
48155
48389
|
const stashPath = stashConflict({
|
|
48156
48390
|
workspaceSlug,
|
|
@@ -48168,7 +48402,7 @@ function applyRow(workspaceSlug, strategy, row, state, out, suppressor, now = ()
|
|
|
48168
48402
|
const target = entityFilePath(workspaceSlug, strategy.type, writeSlug);
|
|
48169
48403
|
let localRaw = null;
|
|
48170
48404
|
try {
|
|
48171
|
-
localRaw =
|
|
48405
|
+
localRaw = lstatSync7(target).isFile() ? readFileSync30(target, "utf8") : null;
|
|
48172
48406
|
} catch {
|
|
48173
48407
|
localRaw = null;
|
|
48174
48408
|
}
|
|
@@ -48334,7 +48568,7 @@ function backfillStateInodes(workspaceSlug, state, statFn = (p) => statSync18(p)
|
|
|
48334
48568
|
return { state, changed: false };
|
|
48335
48569
|
return { state: { ...state, entries: nextEntries }, changed: true };
|
|
48336
48570
|
}
|
|
48337
|
-
function backfillBodyLengths(workspaceSlug, state, readFn = (p) =>
|
|
48571
|
+
function backfillBodyLengths(workspaceSlug, state, readFn = (p) => readFileSync31(p, "utf8")) {
|
|
48338
48572
|
let changed = false;
|
|
48339
48573
|
const nextEntries = {};
|
|
48340
48574
|
for (const [entityType, bucket] of Object.entries(state.entries)) {
|
|
@@ -48346,7 +48580,7 @@ function backfillBodyLengths(workspaceSlug, state, readFn = (p) => readFileSync3
|
|
|
48346
48580
|
}
|
|
48347
48581
|
try {
|
|
48348
48582
|
const path5 = entityFilePath(workspaceSlug, entityType, entry2.slug);
|
|
48349
|
-
const bodyLen =
|
|
48583
|
+
const bodyLen = parseUncached(readFn(path5)).content.length;
|
|
48350
48584
|
nextBucket[id] = { ...entry2, body_len: bodyLen };
|
|
48351
48585
|
changed = true;
|
|
48352
48586
|
} catch {
|
|
@@ -48359,6 +48593,18 @@ function backfillBodyLengths(workspaceSlug, state, readFn = (p) => readFileSync3
|
|
|
48359
48593
|
return { state, changed: false };
|
|
48360
48594
|
return { state: { ...state, entries: nextEntries }, changed: true };
|
|
48361
48595
|
}
|
|
48596
|
+
function isOwnWriteEcho(suppressor, absolutePath, strategy, raw) {
|
|
48597
|
+
if (frontmatterParseError(raw) !== null)
|
|
48598
|
+
return false;
|
|
48599
|
+
return suppressor.shouldSuppressUpsert(absolutePath, computeMirrorHashes(strategy, raw));
|
|
48600
|
+
}
|
|
48601
|
+
function destinationIsUnreadable(absolutePath) {
|
|
48602
|
+
try {
|
|
48603
|
+
return frontmatterParseError(readFileSync31(absolutePath, "utf8")) !== null;
|
|
48604
|
+
} catch {
|
|
48605
|
+
return false;
|
|
48606
|
+
}
|
|
48607
|
+
}
|
|
48362
48608
|
function makeWatchHandler(deps) {
|
|
48363
48609
|
const {
|
|
48364
48610
|
workspaceSlug,
|
|
@@ -48475,7 +48721,7 @@ function makeWatchHandler(deps) {
|
|
|
48475
48721
|
spinner.update(`Watching ${workspaceSlug} · ${watchingSummary(getState())}`);
|
|
48476
48722
|
return;
|
|
48477
48723
|
}
|
|
48478
|
-
const bytes =
|
|
48724
|
+
const bytes = readFileSync31(absolutePath);
|
|
48479
48725
|
const hash2 = sha256Bytes(bytes);
|
|
48480
48726
|
if (suppressor?.shouldSuppressUpsert(absolutePath, {
|
|
48481
48727
|
bodyHash: hash2,
|
|
@@ -48539,7 +48785,7 @@ function makeWatchHandler(deps) {
|
|
|
48539
48785
|
if (suppressor) {
|
|
48540
48786
|
let raw = null;
|
|
48541
48787
|
try {
|
|
48542
|
-
raw =
|
|
48788
|
+
raw = readFileSync31(absolutePath, "utf8");
|
|
48543
48789
|
} catch {
|
|
48544
48790
|
raw = null;
|
|
48545
48791
|
}
|
|
@@ -48578,7 +48824,7 @@ function makeWatchHandler(deps) {
|
|
|
48578
48824
|
if (suppressor) {
|
|
48579
48825
|
let raw = null;
|
|
48580
48826
|
try {
|
|
48581
|
-
raw =
|
|
48827
|
+
raw = readFileSync31(absolutePath, "utf8");
|
|
48582
48828
|
} catch {
|
|
48583
48829
|
raw = null;
|
|
48584
48830
|
}
|
|
@@ -48617,7 +48863,7 @@ function makeWatchHandler(deps) {
|
|
|
48617
48863
|
if (suppressor) {
|
|
48618
48864
|
let raw = null;
|
|
48619
48865
|
try {
|
|
48620
|
-
raw =
|
|
48866
|
+
raw = readFileSync31(absolutePath, "utf8");
|
|
48621
48867
|
} catch {
|
|
48622
48868
|
raw = null;
|
|
48623
48869
|
}
|
|
@@ -48656,7 +48902,7 @@ function makeWatchHandler(deps) {
|
|
|
48656
48902
|
if (suppressor) {
|
|
48657
48903
|
let raw = null;
|
|
48658
48904
|
try {
|
|
48659
|
-
raw =
|
|
48905
|
+
raw = readFileSync31(absolutePath, "utf8");
|
|
48660
48906
|
} catch {
|
|
48661
48907
|
raw = null;
|
|
48662
48908
|
}
|
|
@@ -48695,7 +48941,7 @@ function makeWatchHandler(deps) {
|
|
|
48695
48941
|
if (suppressor) {
|
|
48696
48942
|
let raw = null;
|
|
48697
48943
|
try {
|
|
48698
|
-
raw =
|
|
48944
|
+
raw = readFileSync31(absolutePath, "utf8");
|
|
48699
48945
|
} catch {
|
|
48700
48946
|
raw = null;
|
|
48701
48947
|
}
|
|
@@ -48741,11 +48987,11 @@ function makeWatchHandler(deps) {
|
|
|
48741
48987
|
const strategy = getStrategy(classifiedFrom.entityType);
|
|
48742
48988
|
let toRaw = null;
|
|
48743
48989
|
try {
|
|
48744
|
-
toRaw =
|
|
48990
|
+
toRaw = readFileSync31(event.toPath, "utf8");
|
|
48745
48991
|
} catch {
|
|
48746
48992
|
toRaw = null;
|
|
48747
48993
|
}
|
|
48748
|
-
const isEcho = strategy !== undefined && toRaw !== null && suppressor
|
|
48994
|
+
const isEcho = strategy !== undefined && toRaw !== null && isOwnWriteEcho(suppressor, event.toPath, strategy, toRaw);
|
|
48749
48995
|
if (isEcho) {
|
|
48750
48996
|
output?.log(`[RENAME_SUPPRESSED entityType=${classifiedFrom.entityType} ` + `from=${event.fromSlug} id=${event.id} reason=pull_echo]`);
|
|
48751
48997
|
return;
|
|
@@ -48753,6 +48999,9 @@ function makeWatchHandler(deps) {
|
|
|
48753
48999
|
await handle({ kind: "upsert", absolutePath: event.toPath });
|
|
48754
49000
|
return;
|
|
48755
49001
|
}
|
|
49002
|
+
if (destinationIsUnreadable(event.toPath)) {
|
|
49003
|
+
await handle({ kind: "upsert", absolutePath: event.toPath });
|
|
49004
|
+
}
|
|
48756
49005
|
const base3 = getState();
|
|
48757
49006
|
const result2 = await pushRename({
|
|
48758
49007
|
workspaceSlug,
|
|
@@ -48810,7 +49059,7 @@ function makeWatchHandler(deps) {
|
|
|
48810
49059
|
if (event.kind === "upsert") {
|
|
48811
49060
|
try {
|
|
48812
49061
|
ownEcho = suppressor?.shouldSuppressUpsert(absolutePath, {
|
|
48813
|
-
bodyHash: stableHash(
|
|
49062
|
+
bodyHash: stableHash(readFileSync31(absolutePath, "utf8")),
|
|
48814
49063
|
frontmatterHash: ""
|
|
48815
49064
|
}) === true;
|
|
48816
49065
|
} catch {
|
|
@@ -48865,11 +49114,11 @@ function makeWatchHandler(deps) {
|
|
|
48865
49114
|
if (strategy) {
|
|
48866
49115
|
let raw = null;
|
|
48867
49116
|
try {
|
|
48868
|
-
raw =
|
|
49117
|
+
raw = readFileSync31(absolutePath, "utf8");
|
|
48869
49118
|
} catch {
|
|
48870
49119
|
raw = null;
|
|
48871
49120
|
}
|
|
48872
|
-
if (raw !== null && suppressor
|
|
49121
|
+
if (raw !== null && isOwnWriteEcho(suppressor, absolutePath, strategy, raw)) {
|
|
48873
49122
|
return;
|
|
48874
49123
|
}
|
|
48875
49124
|
}
|
|
@@ -48920,7 +49169,8 @@ function makeWatchHandler(deps) {
|
|
|
48920
49169
|
echo: suppressor ? { watcher: "live", suppressor } : undefined
|
|
48921
49170
|
}
|
|
48922
49171
|
});
|
|
48923
|
-
|
|
49172
|
+
const heldUnreadable = result.outcome.kind === "ignored" && result.outcome.reason === FRONTMATTER_PARSE_ERROR;
|
|
49173
|
+
applyState(result.base ?? base2, heldUnreadable ? result.state : clearEntityRejected(result.state, workspaceSlug, absolutePath));
|
|
48924
49174
|
reportOutcome(spinner, workspaceSlug, getState(), result.outcome);
|
|
48925
49175
|
} catch (err) {
|
|
48926
49176
|
const msg = err instanceof Error ? err.message : "unknown push error";
|
|
@@ -49468,7 +49718,7 @@ async function runStart(workspaceSlug, deps = {}) {
|
|
|
49468
49718
|
return;
|
|
49469
49719
|
}
|
|
49470
49720
|
refreshFrozen();
|
|
49471
|
-
out.log(`[DESTRUCTIVE_HELD batch=${batchId} ops=${batch.length} reason=${result.reason
|
|
49721
|
+
out.log(`[DESTRUCTIVE_HELD batch=${batchId} ops=${batch.length} reason=${tripReasonToken(result.reason)}]`);
|
|
49472
49722
|
spinner.warn(`Held ${batch.length} destructive op${batch.length === 1 ? "" : "s"} pending confirm → ${stashPath}. Run \`plinth confirm\` to review.`);
|
|
49473
49723
|
spinner.update(`Watching ${slug} · ${watchingSummary(state)}`);
|
|
49474
49724
|
}
|
|
@@ -49524,7 +49774,7 @@ async function runStart(workspaceSlug, deps = {}) {
|
|
|
49524
49774
|
return;
|
|
49525
49775
|
}
|
|
49526
49776
|
refreshFrozen();
|
|
49527
|
-
out.log(`[DESTRUCTIVE_HELD batch=${batchId} ops=${batch.length} reason=${result.reason
|
|
49777
|
+
out.log(`[DESTRUCTIVE_HELD batch=${batchId} ops=${batch.length} reason=${tripReasonToken(result.reason)} source=files-watch]`);
|
|
49528
49778
|
spinner.warn(`Held ${batch.length} destructive file op${batch.length === 1 ? "" : "s"} pending confirm → ${stashPath}. Run \`plinth confirm\` to review.`);
|
|
49529
49779
|
spinner.update(`Watching ${slug} · ${watchingSummary(state)}`);
|
|
49530
49780
|
}
|
|
@@ -49616,6 +49866,9 @@ async function runStart(workspaceSlug, deps = {}) {
|
|
|
49616
49866
|
afterPoll: () => {
|
|
49617
49867
|
(async () => {
|
|
49618
49868
|
state = loadState(slug);
|
|
49869
|
+
const unsettled = state;
|
|
49870
|
+
const settled = settleFrontmatterHolds(unsettled, slug);
|
|
49871
|
+
state = rebaseState(state, unsettled, settled);
|
|
49619
49872
|
if (draining)
|
|
49620
49873
|
return;
|
|
49621
49874
|
draining = true;
|
|
@@ -49837,12 +50090,12 @@ async function runStart(workspaceSlug, deps = {}) {
|
|
|
49837
50090
|
try {
|
|
49838
50091
|
await Promise.race([
|
|
49839
50092
|
watcher.drainPending().then(() => Promise.all([gate.drain(), fileGate.drain()])),
|
|
49840
|
-
new Promise((
|
|
50093
|
+
new Promise((resolve7) => setTimeout(() => resolve7(-1), SHUTDOWN_DRAIN_TIMEOUT_MS))
|
|
49841
50094
|
]);
|
|
49842
50095
|
} finally {
|
|
49843
50096
|
await Promise.race([
|
|
49844
50097
|
watcher.stop(),
|
|
49845
|
-
new Promise((
|
|
50098
|
+
new Promise((resolve7) => setTimeout(resolve7, SHUTDOWN_DRAIN_TIMEOUT_MS))
|
|
49846
50099
|
]);
|
|
49847
50100
|
clearDaemonPid(slug);
|
|
49848
50101
|
releaseDaemonLock(lockHandle);
|
|
@@ -50397,7 +50650,7 @@ function assessContextWalls(workspaceSlug, deps = {}) {
|
|
|
50397
50650
|
|
|
50398
50651
|
// src/lib/build-stamp.ts
|
|
50399
50652
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
50400
|
-
import { existsSync as existsSync11, mkdirSync as mkdirSync12, readFileSync as
|
|
50653
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync12, readFileSync as readFileSync32, writeFileSync as writeFileSync8 } from "node:fs";
|
|
50401
50654
|
import { dirname as dirname14, join as join19 } from "node:path";
|
|
50402
50655
|
import { fileURLToPath } from "node:url";
|
|
50403
50656
|
var BUILD_STAMP_FILENAME = "build-stamp.json";
|
|
@@ -50421,7 +50674,7 @@ function readHead(repoDir) {
|
|
|
50421
50674
|
}
|
|
50422
50675
|
function readBuildStamp(distDir) {
|
|
50423
50676
|
try {
|
|
50424
|
-
const parsed = JSON.parse(
|
|
50677
|
+
const parsed = JSON.parse(readFileSync32(stampPath(distDir), "utf8"));
|
|
50425
50678
|
if (parsed && typeof parsed.sha === "string" && parsed.sha.length > 0 && typeof parsed.dirty === "boolean" && typeof parsed.built_at === "string") {
|
|
50426
50679
|
return { sha: parsed.sha, dirty: parsed.dirty, built_at: parsed.built_at };
|
|
50427
50680
|
}
|
|
@@ -50482,12 +50735,12 @@ function checkBuildStaleness(deps = {}) {
|
|
|
50482
50735
|
}
|
|
50483
50736
|
|
|
50484
50737
|
// src/lib/memory-links.ts
|
|
50485
|
-
import { readFileSync as
|
|
50486
|
-
import { relative as relative15, sep as
|
|
50738
|
+
import { readFileSync as readFileSync33 } from "node:fs";
|
|
50739
|
+
import { relative as relative15, sep as sep9 } from "node:path";
|
|
50487
50740
|
var MEMORY_FILE_RE = /^(workspace-memory\.md|user-memory\.md|artists\/[^/]+\/memory\.md|memory\/[^/]+\.md|memory\/private\/[^/]+\.md)$/i;
|
|
50488
50741
|
function scanMemoryLinks(deps) {
|
|
50489
50742
|
const listFiles = deps.listFiles ?? ((r) => walkSubtreeFiles(r, isVcsInternal));
|
|
50490
|
-
const readFile = deps.readFile ?? ((p) =>
|
|
50743
|
+
const readFile = deps.readFile ?? ((p) => readFileSync33(p, "utf8"));
|
|
50491
50744
|
let root;
|
|
50492
50745
|
let absPaths;
|
|
50493
50746
|
try {
|
|
@@ -50496,7 +50749,7 @@ function scanMemoryLinks(deps) {
|
|
|
50496
50749
|
} catch {
|
|
50497
50750
|
return { scanned: 0, unreadable: [], dead: [] };
|
|
50498
50751
|
}
|
|
50499
|
-
const relPaths = absPaths.map((p) => relative15(root, p).split(
|
|
50752
|
+
const relPaths = absPaths.map((p) => relative15(root, p).split(sep9).join("/"));
|
|
50500
50753
|
const artists = buildArtistIndex(relPaths, root, (abs) => readFile(abs));
|
|
50501
50754
|
const dead = [];
|
|
50502
50755
|
const unreadable = [];
|
|
@@ -50531,9 +50784,8 @@ function scanMemoryLinks(deps) {
|
|
|
50531
50784
|
init_output();
|
|
50532
50785
|
|
|
50533
50786
|
// src/lib/pending-writes.ts
|
|
50534
|
-
import { readFileSync as
|
|
50787
|
+
import { readFileSync as readFileSync34, statSync as statSync19 } from "node:fs";
|
|
50535
50788
|
import { relative as relative16 } from "node:path";
|
|
50536
|
-
var import_gray_matter15 = __toESM(require_gray_matter(), 1);
|
|
50537
50789
|
var EMPTY3 = { writes: [], count: 0 };
|
|
50538
50790
|
function reportedElsewhere(state) {
|
|
50539
50791
|
const entities = new Set;
|
|
@@ -50579,7 +50831,7 @@ function scanPendingWrites(args) {
|
|
|
50579
50831
|
continue;
|
|
50580
50832
|
let hash2;
|
|
50581
50833
|
try {
|
|
50582
|
-
hash2 = sha256Bytes(
|
|
50834
|
+
hash2 = sha256Bytes(readFileSync34(absolutePath));
|
|
50583
50835
|
} catch {
|
|
50584
50836
|
continue;
|
|
50585
50837
|
}
|
|
@@ -50610,17 +50862,15 @@ function scanPendingWrites(args) {
|
|
|
50610
50862
|
continue;
|
|
50611
50863
|
let content;
|
|
50612
50864
|
try {
|
|
50613
|
-
content =
|
|
50865
|
+
content = readFileSync34(absolutePath, "utf8");
|
|
50614
50866
|
} catch {
|
|
50615
50867
|
continue;
|
|
50616
50868
|
}
|
|
50617
50869
|
if (!entry2) {
|
|
50618
|
-
|
|
50619
|
-
|
|
50620
|
-
frontmatter = import_gray_matter15.default(content).data ?? {};
|
|
50621
|
-
} catch {
|
|
50870
|
+
const read = readFrontmatter(content);
|
|
50871
|
+
if (holdsUnreadableUntracked({ entityType, entitySlug, readable: read.ok }))
|
|
50622
50872
|
continue;
|
|
50623
|
-
}
|
|
50873
|
+
const frontmatter = read.ok ? read.parsed.data : {};
|
|
50624
50874
|
const verdict = classifyUntrackedEntity({
|
|
50625
50875
|
entityType,
|
|
50626
50876
|
entitySlug,
|
|
@@ -51076,7 +51326,7 @@ async function runStatus(args, deps = {}) {
|
|
|
51076
51326
|
}
|
|
51077
51327
|
}
|
|
51078
51328
|
if (freshness.length > 0) {
|
|
51079
|
-
out.info(row("Memory context", `${freshness.length} file${freshness.length === 1 ? "" : "s"} could not be marked with ${freshness.length === 1 ? "its" : "their"} current memory state
|
|
51329
|
+
out.info(row("Memory context", `${freshness.length} file${freshness.length === 1 ? "" : "s"} could not be marked with ${freshness.length === 1 ? "its" : "their"} current memory state.`));
|
|
51080
51330
|
for (const r of freshness.slice(0, MAX_SHOWN)) {
|
|
51081
51331
|
out.info(cont(r.message));
|
|
51082
51332
|
}
|
|
@@ -51521,7 +51771,7 @@ var versionCommand = defineCommand({
|
|
|
51521
51771
|
});
|
|
51522
51772
|
|
|
51523
51773
|
// src/commands/voice-gate.ts
|
|
51524
|
-
import { readFileSync as
|
|
51774
|
+
import { readFileSync as readFileSync37 } from "node:fs";
|
|
51525
51775
|
|
|
51526
51776
|
// src/lib/voice-gate/api.ts
|
|
51527
51777
|
var VoiceGateSurfaces = [
|
|
@@ -51626,7 +51876,7 @@ async function callVoiceGate(req) {
|
|
|
51626
51876
|
import { createHash as createHash7 } from "node:crypto";
|
|
51627
51877
|
import {
|
|
51628
51878
|
mkdirSync as mkdirSync13,
|
|
51629
|
-
readFileSync as
|
|
51879
|
+
readFileSync as readFileSync35,
|
|
51630
51880
|
renameSync as renameSync9,
|
|
51631
51881
|
unlinkSync as unlinkSync10,
|
|
51632
51882
|
writeFileSync as writeFileSync9
|
|
@@ -51657,7 +51907,7 @@ function emptyFile() {
|
|
|
51657
51907
|
}
|
|
51658
51908
|
function load2(workspaceSlug) {
|
|
51659
51909
|
try {
|
|
51660
|
-
const raw =
|
|
51910
|
+
const raw = readFileSync35(attemptsPath(workspaceSlug), "utf8");
|
|
51661
51911
|
const parsed = AttemptsFileSchema.safeParse(JSON.parse(raw));
|
|
51662
51912
|
return parsed.success ? parsed.data : emptyFile();
|
|
51663
51913
|
} catch {
|
|
@@ -51820,9 +52070,9 @@ function denyUngated(detail) {
|
|
|
51820
52070
|
}
|
|
51821
52071
|
|
|
51822
52072
|
// src/lib/voice-gate/payload.ts
|
|
51823
|
-
import { readFileSync as
|
|
52073
|
+
import { readFileSync as readFileSync36, statSync as statSync21 } from "node:fs";
|
|
51824
52074
|
import { homedir as homedir2 } from "node:os";
|
|
51825
|
-
import { isAbsolute as isAbsolute4, resolve as
|
|
52075
|
+
import { isAbsolute as isAbsolute4, resolve as resolve7 } from "node:path";
|
|
51826
52076
|
var MAX_BODY_BYTES = 256 * 1024;
|
|
51827
52077
|
var HELPER_BASENAME = "push_gmail_draft.py";
|
|
51828
52078
|
var DRAFT_FLAGS = ["--to", "--body-file", "--body-stdin"];
|
|
@@ -51981,7 +52231,7 @@ function defaultReadBodyFile(path5) {
|
|
|
51981
52231
|
if (stat4.size > MAX_BODY_BYTES) {
|
|
51982
52232
|
throw new Error(`draft body is ${stat4.size} bytes, over the ${MAX_BODY_BYTES}-byte gate limit`);
|
|
51983
52233
|
}
|
|
51984
|
-
return
|
|
52234
|
+
return readFileSync36(path5, "utf8");
|
|
51985
52235
|
}
|
|
51986
52236
|
function parseRecipients(...raw) {
|
|
51987
52237
|
const all = raw.filter((v) => typeof v === "string").flatMap((v) => v.split(",")).map((v) => v.trim().toLowerCase()).filter((v) => v.length > 0);
|
|
@@ -52016,13 +52266,13 @@ function applyCd(tokens, state) {
|
|
|
52016
52266
|
return { dir: expanded, known: true };
|
|
52017
52267
|
if (!state.known)
|
|
52018
52268
|
return state;
|
|
52019
|
-
return { dir:
|
|
52269
|
+
return { dir: resolve7(state.dir, expanded), known: true };
|
|
52020
52270
|
}
|
|
52021
52271
|
function expandHome(path5) {
|
|
52022
52272
|
if (path5 === "~")
|
|
52023
52273
|
return homedir2();
|
|
52024
52274
|
if (path5.startsWith("~/"))
|
|
52025
|
-
return
|
|
52275
|
+
return resolve7(homedir2(), path5.slice(2));
|
|
52026
52276
|
return path5;
|
|
52027
52277
|
}
|
|
52028
52278
|
function classifyHelperSegment(tokens, dirState, readBodyFile) {
|
|
@@ -52048,7 +52298,7 @@ function classifyHelperSegment(tokens, dirState, readBodyFile) {
|
|
|
52048
52298
|
unreadable: `the draft push uses a relative \`--body-file\` (${bodyFile}) after a \`cd\` ` + `the voice gate cannot resolve, so it cannot tell which file ships. Pass an ` + `absolute \`--body-file\` path.`
|
|
52049
52299
|
};
|
|
52050
52300
|
}
|
|
52051
|
-
const resolved = isAbsolute4(expanded) ? expanded :
|
|
52301
|
+
const resolved = isAbsolute4(expanded) ? expanded : resolve7(dirState.dir, expanded);
|
|
52052
52302
|
let body;
|
|
52053
52303
|
try {
|
|
52054
52304
|
body = readBodyFile(resolved);
|
|
@@ -52341,7 +52591,7 @@ async function runVoiceGateDirect(args, deps = {}) {
|
|
|
52341
52591
|
let text;
|
|
52342
52592
|
if (args.file) {
|
|
52343
52593
|
try {
|
|
52344
|
-
text =
|
|
52594
|
+
text = readFileSync37(args.file, "utf8");
|
|
52345
52595
|
} catch (err) {
|
|
52346
52596
|
const msg = err instanceof Error ? err.message : "unknown error";
|
|
52347
52597
|
out.error(`Could not read ${args.file}: ${msg}`);
|