@plinth-music/cli 0.20.1 → 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js 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.20.1",
7587
+ version: "0.21.1",
7588
7588
  description: "Plinth capstone sync daemon and CLI",
7589
7589
  type: "module",
7590
7590
  private: false,
@@ -26125,6 +26125,27 @@ function isLaterVersion(a, b) {
26125
26125
  return false;
26126
26126
  return ta > tb;
26127
26127
  }
26128
+ function committedEntryIfNewer(workspaceSlug, entityType, entry) {
26129
+ let raw;
26130
+ try {
26131
+ raw = readFileSync7(stateFilePath(workspaceSlug), "utf8");
26132
+ } catch {
26133
+ return;
26134
+ }
26135
+ let committed;
26136
+ try {
26137
+ const parsed = JSON.parse(raw);
26138
+ committed = parsed.entries?.[entityType]?.[entry.id];
26139
+ } catch {
26140
+ return;
26141
+ }
26142
+ if (committed === undefined)
26143
+ return;
26144
+ const valid = StateEntrySchema.safeParse(committed);
26145
+ if (!valid.success)
26146
+ return;
26147
+ return isLaterVersion(valid.data, entry) ? valid.data : undefined;
26148
+ }
26128
26149
  function mergeKey(fresh, before, after) {
26129
26150
  if (before === after)
26130
26151
  return { value: fresh, overruled: false };
@@ -26200,8 +26221,7 @@ function mergeAnchor(fresh, before, after) {
26200
26221
  return fresh;
26201
26222
  return after;
26202
26223
  }
26203
- function commitState(before, after) {
26204
- const fresh = loadState(after.workspace_slug);
26224
+ function mergeWorkspaceState(fresh, before, after, wantCorrected = true) {
26205
26225
  const entityTypes = new Set([
26206
26226
  ...Object.keys(fresh.entries),
26207
26227
  ...Object.keys(before.entries),
@@ -26242,10 +26262,11 @@ function commitState(before, after) {
26242
26262
  last_trim_at: mergeScalar(fresh.last_trim_at, before.last_trim_at, after.last_trim_at),
26243
26263
  memory_facts: mergeScalar(fresh.memory_facts, before.memory_facts, after.memory_facts)
26244
26264
  };
26245
- writeState(merged);
26265
+ if (!wantCorrected)
26266
+ return { merged, corrected: after };
26246
26267
  const singletonOverruled = rules.overruled || memory.overruled || userMemory.overruled || userVoice.overruled;
26247
26268
  if (overruledEntries.length === 0 && files.overruled.length === 0 && !singletonOverruled) {
26248
- return after;
26269
+ return { merged, corrected: after };
26249
26270
  }
26250
26271
  let corrected = after;
26251
26272
  if (rules.overruled)
@@ -26264,8 +26285,20 @@ function commitState(before, after) {
26264
26285
  const committed = merged.files?.[path];
26265
26286
  corrected = committed ? upsertFileEntry(corrected, committed).state : removeFileEntry(corrected, path).state;
26266
26287
  }
26288
+ return { merged, corrected };
26289
+ }
26290
+ function commitState(before, after) {
26291
+ const { merged, corrected } = mergeWorkspaceState(loadState(after.workspace_slug), before, after);
26292
+ writeState(merged);
26267
26293
  return corrected;
26268
26294
  }
26295
+ function rebaseState(current, base2, next) {
26296
+ if (next === base2)
26297
+ return current;
26298
+ if (current === base2)
26299
+ return next;
26300
+ return mergeWorkspaceState(current, base2, next, false).merged;
26301
+ }
26269
26302
  function upsertEntry(state, entityType, entry) {
26270
26303
  const bucket = state.entries[entityType] ?? {};
26271
26304
  const existing = bucket[entry.id];
@@ -30505,6 +30538,560 @@ function ensureGitignore(workspaceSlug) {
30505
30538
  function backupStamp2(d) {
30506
30539
  return d.toISOString().replace(/[-:.]/g, "").replace("Z", "");
30507
30540
  }
30541
+ // src/lib/context/observation.ts
30542
+ import {
30543
+ closeSync as closeSync2,
30544
+ constants as FS,
30545
+ fstatSync,
30546
+ lstatSync as lstatSync3,
30547
+ openSync as openSync2,
30548
+ readSync,
30549
+ realpathSync as realpathSync2
30550
+ } from "node:fs";
30551
+ import { createHash as createHash2 } from "node:crypto";
30552
+ import { basename as basename2, dirname as dirname6, join as join8, resolve as resolve3, sep as sep4 } from "node:path";
30553
+ var OBSERVATION_MAX_BYTES = 64 * 1024 * 1024;
30554
+ var OBSERVATION_MAX_LINES = 200000;
30555
+ var READ_CHUNK = 1024 * 1024;
30556
+ var PROVENANCE_MAX = 256;
30557
+ var UNSAFE_PROVENANCE = /[\p{Cc}\p{Cf}]/u;
30558
+ function safeProvenance(v) {
30559
+ if (typeof v !== "string" || v === "")
30560
+ return null;
30561
+ if (v.length > PROVENANCE_MAX)
30562
+ return null;
30563
+ if (UNSAFE_PROVENANCE.test(v))
30564
+ return null;
30565
+ return v;
30566
+ }
30567
+ var ATTACHMENT_LABELS = new Set([
30568
+ "skill_listing",
30569
+ "deferred_tools_delta",
30570
+ "mcp_instructions_delta",
30571
+ "command_permissions",
30572
+ "agent_listing_delta",
30573
+ "total_tokens_reminder",
30574
+ "auto_mode",
30575
+ "remote_session_change",
30576
+ "file_history_snapshot"
30577
+ ]);
30578
+ function isFailure(x) {
30579
+ return x.status !== undefined;
30580
+ }
30581
+ function openSelected(selectedPath, hooks = {}) {
30582
+ const resolved = resolve3(selectedPath);
30583
+ let canonicalPath;
30584
+ try {
30585
+ canonicalPath = realpathSync2(resolved);
30586
+ } catch (err) {
30587
+ const code = err?.code;
30588
+ if (code === "ENOENT") {
30589
+ return { status: "absent", refusalReason: null, canonicalPath: null, indirection: false };
30590
+ }
30591
+ if (code === "ELOOP") {
30592
+ return {
30593
+ status: "refused",
30594
+ refusalReason: "path-unresolvable",
30595
+ canonicalPath: null,
30596
+ indirection: true
30597
+ };
30598
+ }
30599
+ return { status: "unreadable", refusalReason: null, canonicalPath: null, indirection: false };
30600
+ }
30601
+ const indirection = canonicalPath !== resolved;
30602
+ let before;
30603
+ try {
30604
+ before = lstatSync3(canonicalPath);
30605
+ } catch (err) {
30606
+ const code = err?.code;
30607
+ if (code === "ENOENT") {
30608
+ return { status: "absent", refusalReason: null, canonicalPath, indirection };
30609
+ }
30610
+ return { status: "unreadable", refusalReason: null, canonicalPath, indirection };
30611
+ }
30612
+ hooks.afterIdentityCheck?.();
30613
+ let fd;
30614
+ try {
30615
+ fd = openSync2(canonicalPath, FS.O_RDONLY | FS.O_NOFOLLOW | FS.O_NONBLOCK);
30616
+ } catch (err) {
30617
+ const code = err?.code;
30618
+ if (code === "ENOENT") {
30619
+ return { status: "absent", refusalReason: null, canonicalPath, indirection };
30620
+ }
30621
+ if (code === "ELOOP" || code === "EMLINK") {
30622
+ return { status: "refused", refusalReason: "target-changed", canonicalPath, indirection };
30623
+ }
30624
+ return { status: "unreadable", refusalReason: null, canonicalPath, indirection };
30625
+ }
30626
+ let after;
30627
+ try {
30628
+ after = fstatSync(fd);
30629
+ } catch {
30630
+ closeSync2(fd);
30631
+ return { status: "unreadable", refusalReason: null, canonicalPath, indirection };
30632
+ }
30633
+ if (!after.isFile()) {
30634
+ closeSync2(fd);
30635
+ return { status: "refused", refusalReason: "not-regular-file", canonicalPath, indirection };
30636
+ }
30637
+ if (after.dev !== before.dev || after.ino !== before.ino) {
30638
+ closeSync2(fd);
30639
+ return { status: "refused", refusalReason: "target-changed", canonicalPath, indirection };
30640
+ }
30641
+ return { fd, canonicalPath, indirection };
30642
+ }
30643
+ function readBounded(fd, maxBytes) {
30644
+ const hash2 = createHash2("sha256");
30645
+ const chunks = [];
30646
+ const buf = Buffer.allocUnsafe(READ_CHUNK);
30647
+ let bytesRead = 0;
30648
+ let truncated = false;
30649
+ for (;; ) {
30650
+ const want = Math.min(READ_CHUNK, maxBytes - bytesRead);
30651
+ if (want <= 0) {
30652
+ const probe2 = readSync(fd, buf, 0, 1, bytesRead);
30653
+ truncated = probe2 > 0;
30654
+ break;
30655
+ }
30656
+ const n = readSync(fd, buf, 0, want, bytesRead);
30657
+ if (n <= 0)
30658
+ break;
30659
+ const slice = Buffer.from(buf.subarray(0, n));
30660
+ hash2.update(slice);
30661
+ chunks.push(slice);
30662
+ bytesRead += n;
30663
+ }
30664
+ return {
30665
+ text: Buffer.concat(chunks).toString("utf8"),
30666
+ bytesRead,
30667
+ truncated,
30668
+ sha256: hash2.digest("hex")
30669
+ };
30670
+ }
30671
+ var USAGE_FIELDS = [
30672
+ ["inputTokens", ["input_tokens"]],
30673
+ ["cacheReadTokens", ["cache_read_input_tokens"]],
30674
+ ["cacheCreationTokens", ["cache_creation_input_tokens"]],
30675
+ ["outputTokens", ["output_tokens"]],
30676
+ ["cacheCreation1hTokens", ["cache_creation", "ephemeral_1h_input_tokens"]],
30677
+ ["cacheCreation5mTokens", ["cache_creation", "ephemeral_5m_input_tokens"]]
30678
+ ];
30679
+ function dig(obj, path) {
30680
+ let cur = obj;
30681
+ for (const key of path) {
30682
+ if (cur === null || typeof cur !== "object")
30683
+ return;
30684
+ cur = cur[key];
30685
+ }
30686
+ return cur;
30687
+ }
30688
+
30689
+ class UsageAccumulator {
30690
+ byRequest = new Map;
30691
+ sums = new Map;
30692
+ present = new Map;
30693
+ requests = 0;
30694
+ countedRecords = 0;
30695
+ duplicateRecords = 0;
30696
+ conflictingDuplicates = 0;
30697
+ untaggedRecords = 0;
30698
+ recordsWithoutUsage = 0;
30699
+ unresolvableRecords = 0;
30700
+ add(record2) {
30701
+ if (record2["type"] !== "assistant")
30702
+ return;
30703
+ const usage = dig(record2, ["message", "usage"]);
30704
+ const hasUsage = usage !== null && typeof usage === "object";
30705
+ if (hasUsage)
30706
+ this.countedRecords += 1;
30707
+ else
30708
+ this.recordsWithoutUsage += 1;
30709
+ const requestId = record2["requestId"];
30710
+ if (typeof requestId !== "string" || requestId === "") {
30711
+ if (hasUsage)
30712
+ this.untaggedRecords += 1;
30713
+ else
30714
+ this.unresolvableRecords += 1;
30715
+ return;
30716
+ }
30717
+ if (!this.byRequest.has(requestId)) {
30718
+ this.byRequest.set(requestId, null);
30719
+ this.requests += 1;
30720
+ }
30721
+ if (!hasUsage)
30722
+ return;
30723
+ const fingerprint = JSON.stringify(USAGE_FIELDS.map(([, path]) => dig(usage, path) ?? null));
30724
+ const prior = this.byRequest.get(requestId) ?? null;
30725
+ if (prior !== null) {
30726
+ if (prior === fingerprint)
30727
+ this.duplicateRecords += 1;
30728
+ else
30729
+ this.conflictingDuplicates += 1;
30730
+ return;
30731
+ }
30732
+ this.byRequest.set(requestId, fingerprint);
30733
+ for (const [name, path] of USAGE_FIELDS) {
30734
+ const raw = dig(usage, path);
30735
+ if (typeof raw !== "number" || !Number.isFinite(raw))
30736
+ continue;
30737
+ this.present.set(name, (this.present.get(name) ?? 0) + 1);
30738
+ this.sums.set(name, (this.sums.get(name) ?? 0) + raw);
30739
+ }
30740
+ }
30741
+ unresolved() {
30742
+ let n = 0;
30743
+ for (const fp of this.byRequest.values())
30744
+ if (fp === null)
30745
+ n += 1;
30746
+ return n;
30747
+ }
30748
+ finish() {
30749
+ if (this.countedRecords === 0 && this.recordsWithoutUsage === 0)
30750
+ return null;
30751
+ const unresolvedRequests = this.unresolved();
30752
+ const incompleteFields = [];
30753
+ const value = (name) => {
30754
+ const present2 = this.present.get(name) ?? 0;
30755
+ if (present2 > 0 && present2 === this.requests)
30756
+ return this.sums.get(name) ?? 0;
30757
+ if (present2 > 0)
30758
+ incompleteFields.push(name);
30759
+ return null;
30760
+ };
30761
+ const fields = Object.fromEntries(USAGE_FIELDS.map(([name]) => [name, value(name)]));
30762
+ const anyFullyCovered = USAGE_FIELDS.some(([name]) => (this.present.get(name) ?? 0) > 0 && (this.present.get(name) ?? 0) === this.requests);
30763
+ return {
30764
+ requests: this.requests,
30765
+ countedRecords: this.countedRecords,
30766
+ duplicateRecords: this.duplicateRecords,
30767
+ conflictingDuplicates: this.conflictingDuplicates,
30768
+ untaggedRecords: this.untaggedRecords,
30769
+ unresolvedRequests,
30770
+ recordsWithoutUsage: this.recordsWithoutUsage,
30771
+ unresolvableRecords: this.unresolvableRecords,
30772
+ ...fields,
30773
+ incompleteFields,
30774
+ incomplete: incompleteFields.length > 0 || this.conflictingDuplicates > 0 || this.untaggedRecords > 0 || unresolvedRequests > 0 || this.unresolvableRecords > 0 || this.requests > 0 && !anyFullyCovered
30775
+ };
30776
+ }
30777
+ }
30778
+ function hasToolResult(content) {
30779
+ if (!Array.isArray(content))
30780
+ return false;
30781
+ return content.some((b) => b !== null && typeof b === "object" && b["type"] === "tool_result");
30782
+ }
30783
+ function contentText(content) {
30784
+ if (typeof content === "string")
30785
+ return content;
30786
+ if (!Array.isArray(content))
30787
+ return "";
30788
+ return content.map((b) => b !== null && typeof b === "object" && typeof b["text"] === "string" ? b["text"] : "").join("");
30789
+ }
30790
+ function payloadBytes(payload) {
30791
+ if (payload === undefined)
30792
+ return 0;
30793
+ if (typeof payload === "string")
30794
+ return Buffer.byteLength(payload, "utf8");
30795
+ try {
30796
+ return Buffer.byteLength(JSON.stringify(payload) ?? "", "utf8");
30797
+ } catch {
30798
+ return 0;
30799
+ }
30800
+ }
30801
+
30802
+ class DeliveryAccumulator {
30803
+ rows = new Map;
30804
+ pendingCommand = false;
30805
+ bump(kind, label, bytes) {
30806
+ const key = `${kind} ${label}`;
30807
+ const row = this.rows.get(key) ?? { kind, label, occurrences: 0, recordedBytes: 0 };
30808
+ row.occurrences += 1;
30809
+ row.recordedBytes += bytes;
30810
+ this.rows.set(key, row);
30811
+ }
30812
+ add(record2) {
30813
+ const wasPending = this.pendingCommand;
30814
+ this.pendingCommand = false;
30815
+ const type = record2["type"];
30816
+ if (type === "attachment") {
30817
+ const att = record2["attachment"];
30818
+ const rawLabel = dig(att, ["type"]);
30819
+ const label = typeof rawLabel === "string" && ATTACHMENT_LABELS.has(rawLabel) ? rawLabel : "other";
30820
+ this.bump("harness-listing", label, payloadBytes(att));
30821
+ return;
30822
+ }
30823
+ if (type !== "user")
30824
+ return;
30825
+ const content = dig(record2, ["message", "content"]);
30826
+ const bytes = payloadBytes(content);
30827
+ const text = contentText(content);
30828
+ if (record2["isMeta"] === true) {
30829
+ if (wasPending)
30830
+ this.bump("command-body", "command-body", bytes);
30831
+ else
30832
+ this.bump("meta-injection", "meta-injection", bytes);
30833
+ return;
30834
+ }
30835
+ if (hasToolResult(content)) {
30836
+ this.bump("tool-result", "tool-result", bytes);
30837
+ return;
30838
+ }
30839
+ const opening = text.trimStart();
30840
+ this.pendingCommand = opening.startsWith("<command-message>") || opening.startsWith("<command-name>");
30841
+ this.bump("user-turn", "user-turn", bytes);
30842
+ }
30843
+ finish() {
30844
+ return [...this.rows.values()].sort((a, b) => b.recordedBytes - a.recordedBytes || a.label.localeCompare(b.label));
30845
+ }
30846
+ }
30847
+
30848
+ class BindingAccumulator {
30849
+ sessionIds = new Set;
30850
+ versions = new Set;
30851
+ cwds = new Set;
30852
+ branches = new Set;
30853
+ first = null;
30854
+ last = null;
30855
+ rejected = 0;
30856
+ add(record2) {
30857
+ const str2 = (k) => {
30858
+ const raw = record2[k];
30859
+ const safe = safeProvenance(raw);
30860
+ if (safe === null && typeof raw === "string" && raw !== "")
30861
+ this.rejected += 1;
30862
+ return safe;
30863
+ };
30864
+ const sid = str2("sessionId");
30865
+ if (sid !== null)
30866
+ this.sessionIds.add(sid);
30867
+ const ver = str2("version");
30868
+ if (ver !== null)
30869
+ this.versions.add(ver);
30870
+ const cwd = str2("cwd");
30871
+ if (cwd !== null)
30872
+ this.cwds.add(cwd);
30873
+ const branch = str2("gitBranch");
30874
+ if (branch !== null)
30875
+ this.branches.add(branch);
30876
+ const ts = str2("timestamp");
30877
+ if (ts !== null) {
30878
+ if (this.first === null || ts < this.first)
30879
+ this.first = ts;
30880
+ if (this.last === null || ts > this.last)
30881
+ this.last = ts;
30882
+ }
30883
+ }
30884
+ finish(workspaceMirrorDir) {
30885
+ const only = (s) => s.size === 1 ? [...s][0] : null;
30886
+ const cwd = only(this.cwds);
30887
+ const consistent = this.sessionIds.size === 1 && this.versions.size === 1 && this.cwds.size === 1;
30888
+ return {
30889
+ sessionId: only(this.sessionIds),
30890
+ runtimeVersion: only(this.versions),
30891
+ cwd,
30892
+ gitBranch: only(this.branches),
30893
+ firstTimestamp: this.first,
30894
+ lastTimestamp: this.last,
30895
+ distinctSessionIds: this.sessionIds.size,
30896
+ consistent,
30897
+ scope: deriveScope(cwd, workspaceMirrorDir),
30898
+ rejectedFields: this.rejected
30899
+ };
30900
+ }
30901
+ }
30902
+ function canonicalise(p) {
30903
+ const full = resolve3(p);
30904
+ let cur = full;
30905
+ const tail = [];
30906
+ for (;; ) {
30907
+ try {
30908
+ const real = realpathSync2(cur);
30909
+ return tail.length === 0 ? real : join8(real, ...tail.slice().reverse());
30910
+ } catch {
30911
+ const parent = dirname6(cur);
30912
+ if (parent === cur)
30913
+ return full;
30914
+ tail.push(basename2(cur));
30915
+ cur = parent;
30916
+ }
30917
+ }
30918
+ }
30919
+ function deriveScope(cwd, workspaceMirrorDir) {
30920
+ if (cwd === null || workspaceMirrorDir === undefined)
30921
+ return "unknown";
30922
+ const ws = canonicalise(workspaceMirrorDir);
30923
+ const here = canonicalise(cwd);
30924
+ if (here === ws)
30925
+ return "root";
30926
+ if (here.startsWith(ws.endsWith(sep4) ? ws : ws + sep4))
30927
+ return "below-root";
30928
+ return "outside";
30929
+ }
30930
+ function limitsFor(obs) {
30931
+ const limits = [
30932
+ {
30933
+ id: "observation-not-attributable",
30934
+ what: "which source contributed which tokens is not recoverable from this artefact: the standing context arrives as one aggregate in the first request's cache fields, with no per-source breakdown. The remainder is unattributable, not zero",
30935
+ owner: "not exposed by the measured artefact, runtime and this adapter; further effective-loading work stays with S2/E15 and the packaged half"
30936
+ },
30937
+ {
30938
+ id: "observation-interval",
30939
+ what: "this covers only the interval actually read from the selected file, identified by its byte boundary and digest. A live session keeps growing, so the same path measured later is a different interval",
30940
+ owner: "the reader who selected the file; re-run to extend it"
30941
+ },
30942
+ {
30943
+ id: "observation-inventory-not-contemporaneous",
30944
+ what: "the source inventory above is what is on disk NOW. It is not evidence that those files existed, or had those sizes, during the observed interval",
30945
+ owner: "E15, which compares arms rather than inventories"
30946
+ },
30947
+ {
30948
+ id: "observation-compaction",
30949
+ what: "resume, clear and compaction are not detected and were not demonstrated in any measured sample, so a compacted session may be reported as one continuous interval",
30950
+ owner: "a later S2/E15 lane with a purpose-built compacted session"
30951
+ },
30952
+ {
30953
+ id: "observation-delivery-cause",
30954
+ what: "a command body is labelled only when an invocation marker precedes it; an uncorrelated meta-injection's cause is not established. And a recorded delivery proves delivery happened, never that a body is not loaded by some other route",
30955
+ owner: "a later S2 lane, if per-route delivery proof is wanted"
30956
+ }
30957
+ ];
30958
+ if (obs.binding.rejectedFields > 0) {
30959
+ limits.push({
30960
+ id: "observation-provenance-refused",
30961
+ what: "one or more session/runtime/directory values in the file carried control characters or exceeded the length cap and were refused rather than printed, so they read as unknown above",
30962
+ owner: "the reader who selected the file"
30963
+ });
30964
+ }
30965
+ if (obs.indirection) {
30966
+ limits.push({
30967
+ id: "observation-path-indirection",
30968
+ what: "the selected path resolved through a link; the canonical path above is what was read",
30969
+ owner: "the reader who selected the file"
30970
+ });
30971
+ }
30972
+ if (!obs.binding.consistent) {
30973
+ limits.push({
30974
+ id: "observation-binding-inconsistent",
30975
+ what: "session id, runtime version or working directory is missing or varies across records, so this observation is NOT attributed to the workspace inventory and is reported separately",
30976
+ owner: "select a single-session transcript to attribute it"
30977
+ });
30978
+ }
30979
+ if (obs.binding.scope === "below-root") {
30980
+ limits.push({
30981
+ id: "observation-scope-unsupported",
30982
+ what: "the observed session ran below the workspace root, and the inventory's scoped-load class is not resolved per session, so its scoped sources are not matched to this observation",
30983
+ owner: "a later S2 lane, if per-scope resolution is wanted"
30984
+ });
30985
+ }
30986
+ return limits;
30987
+ }
30988
+ function emptyBinding(workspaceMirrorDir) {
30989
+ return new BindingAccumulator().finish(workspaceMirrorDir);
30990
+ }
30991
+ function shell(selectedPath, status, refusalReason, canonicalPath, indirection, opts, extras = {}) {
30992
+ const base2 = {
30993
+ status,
30994
+ refusalReason,
30995
+ selectedPath,
30996
+ canonicalPath,
30997
+ indirection,
30998
+ bytesRead: extras.bytesRead ?? 0,
30999
+ sha256: extras.sha256 ?? null,
31000
+ lines: extras.lines ?? { total: 0, parsed: 0, malformed: 0, truncated: false, cutFinalLine: false },
31001
+ binding: emptyBinding(opts.workspaceMirrorDir),
31002
+ usage: null,
31003
+ deliveries: []
31004
+ };
31005
+ return { ...base2, limits: limitsFor(base2), complete: false };
31006
+ }
31007
+ function buildObservation(selectedPath, opts = {}) {
31008
+ const maxBytes = opts.maxBytes ?? OBSERVATION_MAX_BYTES;
31009
+ const maxLines = opts.maxLines ?? OBSERVATION_MAX_LINES;
31010
+ const opened = openSelected(selectedPath, opts.openHooks ?? {});
31011
+ if (isFailure(opened)) {
31012
+ return shell(selectedPath, opened.status, opened.refusalReason, opened.canonicalPath, opened.indirection, opts);
31013
+ }
31014
+ let read;
31015
+ try {
31016
+ read = readBounded(opened.fd, maxBytes);
31017
+ } catch {
31018
+ return shell(selectedPath, "unreadable", null, opened.canonicalPath, opened.indirection, opts);
31019
+ } finally {
31020
+ try {
31021
+ closeSync2(opened.fd);
31022
+ } catch {}
31023
+ }
31024
+ const pieces = read.text.split(`
31025
+ `);
31026
+ if (pieces.length > 0 && pieces[pieces.length - 1] === "")
31027
+ pieces.pop();
31028
+ let cutFinalLine = false;
31029
+ let truncated = read.truncated;
31030
+ if (read.truncated && pieces.length > 0 && !read.text.endsWith(`
31031
+ `)) {
31032
+ pieces.pop();
31033
+ cutFinalLine = true;
31034
+ }
31035
+ if (pieces.length > maxLines) {
31036
+ pieces.length = maxLines;
31037
+ truncated = true;
31038
+ }
31039
+ const nonBlank = pieces.filter((l) => l.trim() !== "");
31040
+ if (nonBlank.length === 0) {
31041
+ return shell(selectedPath, truncated ? "read" : "empty", null, opened.canonicalPath, opened.indirection, opts, {
31042
+ bytesRead: read.bytesRead,
31043
+ sha256: read.sha256,
31044
+ lines: { total: 0, parsed: 0, malformed: 0, truncated, cutFinalLine }
31045
+ });
31046
+ }
31047
+ const usage = new UsageAccumulator;
31048
+ const deliveries = new DeliveryAccumulator;
31049
+ const binding = new BindingAccumulator;
31050
+ let parsed = 0;
31051
+ let malformed = 0;
31052
+ for (const line of nonBlank) {
31053
+ let record2;
31054
+ try {
31055
+ record2 = JSON.parse(line);
31056
+ } catch {
31057
+ malformed += 1;
31058
+ continue;
31059
+ }
31060
+ if (record2 === null || typeof record2 !== "object" || Array.isArray(record2)) {
31061
+ malformed += 1;
31062
+ continue;
31063
+ }
31064
+ parsed += 1;
31065
+ const rec = record2;
31066
+ binding.add(rec);
31067
+ usage.add(rec);
31068
+ deliveries.add(rec);
31069
+ }
31070
+ const lines = {
31071
+ total: nonBlank.length,
31072
+ parsed,
31073
+ malformed,
31074
+ truncated,
31075
+ cutFinalLine
31076
+ };
31077
+ const status = parsed === 0 ? "malformed" : "read";
31078
+ const finishedUsage = status === "read" ? usage.finish() : null;
31079
+ const base2 = {
31080
+ status,
31081
+ refusalReason: null,
31082
+ selectedPath,
31083
+ canonicalPath: opened.canonicalPath,
31084
+ indirection: opened.indirection,
31085
+ bytesRead: read.bytesRead,
31086
+ sha256: read.sha256,
31087
+ lines,
31088
+ binding: binding.finish(opts.workspaceMirrorDir),
31089
+ usage: finishedUsage,
31090
+ deliveries: status === "read" ? deliveries.finish() : []
31091
+ };
31092
+ const complete = status === "read" && malformed === 0 && !truncated && !cutFinalLine && (finishedUsage === null || !finishedUsage.incomplete);
31093
+ return { ...base2, limits: limitsFor(base2), complete };
31094
+ }
30508
31095
 
30509
31096
  // src/lib/context/context-account.ts
30510
31097
  function localRow(workspaceSlug) {
@@ -30709,13 +31296,13 @@ function collectExternalSources() {
30709
31296
  var STANDING_LIMITS = [
30710
31297
  {
30711
31298
  id: "observed-loading",
30712
- what: "what a session ACTUALLY loaded is not observed. Everything above is bytes on disk and the hook's own rendered output",
30713
- owner: "a later S2 lane: a bounded, explicit observation import (the transcript carries per-turn usage; no adapter is built)"
31299
+ what: "what a session ACTUALLY loaded is not observed here. Everything above is bytes on disk and the hook's own rendered output",
31300
+ owner: "pass `--observed <transcript.jsonl>` to measure one selected session's recorded delivery. Per-source attribution stays unavailable even then"
30714
31301
  },
30715
31302
  {
30716
31303
  id: "usage",
30717
- what: "tokens, cached and billed usage are not measured. The CLI has no token accounting of any kind",
30718
- owner: "the same later S2 lane, with the desktop half for effective-context diagnostics"
31304
+ what: "tokens, cached and billed usage are not measured here",
31305
+ owner: "pass `--observed <transcript.jsonl>` for one session's recorded per-request usage; the packaged/desktop half of effective-context diagnostics is still open"
30719
31306
  },
30720
31307
  {
30721
31308
  id: "user-level-config",
@@ -30767,7 +31354,11 @@ function buildContextAccount(workspaceSlug, deps = {}) {
30767
31354
  collectExternalSources()
30768
31355
  ];
30769
31356
  const sources = parts.flatMap((p) => p.sources);
30770
- const limits = [...parts.flatMap((p) => p.limits), ...STANDING_LIMITS];
31357
+ const limits = [
31358
+ ...parts.flatMap((p) => p.limits),
31359
+ ...STANDING_LIMITS,
31360
+ ...deps.observation?.limits ?? []
31361
+ ];
30771
31362
  const refusedFeedingHook = sources.filter((s) => s.status === "refused" && (s.route === "hook-injection" || s.path === VOICE_FILENAME));
30772
31363
  if (refusedFeedingHook.length > 0) {
30773
31364
  limits.unshift({
@@ -30805,6 +31396,7 @@ function buildContextAccount(workspaceSlug, deps = {}) {
30805
31396
  observedLoadedBytes: null,
30806
31397
  estimatedTokens: null,
30807
31398
  conditionalStanding,
31399
+ observation: deps.observation ?? null,
30808
31400
  limits
30809
31401
  };
30810
31402
  }
@@ -31059,13 +31651,92 @@ function renderAccount(out, account) {
31059
31651
  out.info(` · ${a}`);
31060
31652
  out.info("");
31061
31653
  }
31654
+ if (account.observation !== null)
31655
+ renderObservation(out, account.observation);
31062
31656
  out.info("Not measured here");
31063
- out.info(" Observed loading: not observed. Tokens and billed usage: not measured.");
31657
+ if (account.observation === null) {
31658
+ out.info(" Observed loading: not observed. Tokens and billed usage: not measured.");
31659
+ } else {
31660
+ out.info(" Observed above is ONE selected session's recorded delivery and usage. No token is attributed to any file.");
31661
+ }
31064
31662
  for (const l of account.limits) {
31065
31663
  out.info(` · ${l.what}`);
31066
31664
  out.info(` owed to: ${l.owner}`);
31067
31665
  }
31068
31666
  }
31667
+ var REFUSAL_PROSE = {
31668
+ "not-regular-file": "not a regular file",
31669
+ "target-changed": "the file opened was not the file checked — refused rather than measured",
31670
+ "path-unresolvable": "the path could not be resolved"
31671
+ };
31672
+ var STATUS_PROSE = {
31673
+ absent: "not there",
31674
+ unreadable: "could not be read",
31675
+ empty: "no records",
31676
+ malformed: "records present, none parsed — NOT a measured zero"
31677
+ };
31678
+ function renderObservation(out, obs) {
31679
+ const head = obs.complete ? "Observed" : "Observed (PARTIAL)";
31680
+ if (obs.status !== "read") {
31681
+ const why = REFUSAL_PROSE[obs.refusalReason ?? ""] ?? STATUS_PROSE[obs.status] ?? obs.status;
31682
+ out.info(`${head} ${obs.selectedPath}`);
31683
+ out.info(` ${why}. Nothing was measured, and that is not a zero.`);
31684
+ if (obs.bytesRead > 0 || obs.lines.total > 0) {
31685
+ out.info(` ${fmt(obs.bytesRead)} bytes read · ${fmt(obs.lines.total)} records seen` + (obs.lines.malformed > 0 ? ` · ${fmt(obs.lines.malformed)} malformed` : "") + (obs.lines.truncated ? " · stopped at the read bound" : "") + (obs.sha256 !== null ? ` · sha256 ${obs.sha256.slice(0, 16)}` : ""));
31686
+ }
31687
+ out.info("");
31688
+ return;
31689
+ }
31690
+ const b = obs.binding;
31691
+ out.info(`${head} ${fmt(obs.bytesRead)} bytes read from the selected transcript`);
31692
+ if (obs.canonicalPath !== null && obs.indirection) {
31693
+ out.info(` resolved through a link to ${obs.canonicalPath}`);
31694
+ }
31695
+ out.info(` session ${b.sessionId ?? "unknown"} · runtime ${b.runtimeVersion ?? "unknown"} · scope ${b.scope}`);
31696
+ out.info(` interval ${b.firstTimestamp ?? "unknown"} .. ${b.lastTimestamp ?? "unknown"} · sha256 ${obs.sha256?.slice(0, 16) ?? "unknown"}`);
31697
+ out.info(` ${fmt(obs.lines.parsed)} of ${fmt(obs.lines.total)} records parsed` + (obs.lines.malformed > 0 ? ` · ${fmt(obs.lines.malformed)} malformed` : "") + (obs.lines.truncated ? " · stopped at the read bound" : "") + (obs.lines.cutFinalLine ? " · final record severed by the bound" : ""));
31698
+ if (b.rejectedFields > 0) {
31699
+ out.info(` ${fmt(b.rejectedFields)} provenance value(s) in the file were refused as unsafe or over-long and read as unknown above.`);
31700
+ }
31701
+ if (!b.consistent) {
31702
+ out.info(" NOT attributed to this workspace: session, runtime or directory is missing or varies across records.");
31703
+ }
31704
+ out.info("");
31705
+ const u = obs.usage;
31706
+ if (u === null) {
31707
+ out.info(" Usage — no record carried a usage object. Unknown, not zero.");
31708
+ } else {
31709
+ const n = (v) => v === null ? "unknown" : fmt(v);
31710
+ out.info(` Usage over ${fmt(u.requests)} requests, from ${fmt(u.countedRecords)} usage-bearing records` + (u.duplicateRecords > 0 ? ` (${fmt(u.duplicateRecords)} repeated the same usage)` : ""));
31711
+ out.info(` fresh input ${n(u.inputTokens)} tokens`);
31712
+ out.info(` cache read ${n(u.cacheReadTokens)} tokens`);
31713
+ out.info(` cache written ${n(u.cacheCreationTokens)} tokens`);
31714
+ out.info(` output ${n(u.outputTokens)} tokens`);
31715
+ if (u.conflictingDuplicates > 0) {
31716
+ out.info(` ⚠ ${fmt(u.conflictingDuplicates)} request(s) reported conflicting usage; the figures above are incomplete`);
31717
+ }
31718
+ if (u.untaggedRecords > 0) {
31719
+ out.info(` ⚠ ${fmt(u.untaggedRecords)} record(s) carried usage with no request id; excluded, because they cannot be shown independent`);
31720
+ }
31721
+ if (u.unresolvedRequests > 0) {
31722
+ out.info(` ⚠ ${fmt(u.unresolvedRequests)} of ${fmt(u.requests)} request(s) carried no usage record, so what they cost is unknown — not zero`);
31723
+ }
31724
+ if (u.unresolvableRecords > 0) {
31725
+ out.info(` ⚠ ${fmt(u.unresolvableRecords)} record(s) had neither usage nor a request id; nothing can name or resolve them`);
31726
+ }
31727
+ if (u.incompleteFields.length > 0) {
31728
+ out.info(` ⚠ not every request reported: ${u.incompleteFields.join(", ")}`);
31729
+ }
31730
+ }
31731
+ out.info("");
31732
+ if (obs.deliveries.length > 0) {
31733
+ out.info(" Recorded deliveries — payload bytes as stored, not injected or billed bytes");
31734
+ for (const d of obs.deliveries) {
31735
+ out.info(` ${d.kind.padEnd(16)} ${d.label.padEnd(24)} ${String(d.occurrences).padStart(4)}x ${fmt(d.recordedBytes)} bytes`);
31736
+ }
31737
+ out.info("");
31738
+ }
31739
+ }
31069
31740
  async function runContext(args, deps = {}) {
31070
31741
  const out = new Output({ sink: deps.sink, noColor: deps.noColor });
31071
31742
  const config2 = (deps.loadConfigFn ?? loadConfig)();
@@ -31079,7 +31750,20 @@ async function runContext(args, deps = {}) {
31079
31750
  out.error(`Workspace "${slug}" not found. Run \`plinth login --workspace ${slug}\` first.`);
31080
31751
  return { exitCode: 1 };
31081
31752
  }
31753
+ let observation = null;
31754
+ if (args.observed !== undefined && args.observed !== "") {
31755
+ let mirrorDir;
31756
+ try {
31757
+ mirrorDir = workspaceMirrorPath(slug);
31758
+ } catch {
31759
+ mirrorDir = undefined;
31760
+ }
31761
+ observation = (deps.buildObservationFn ?? buildObservation)(args.observed, {
31762
+ workspaceMirrorDir: mirrorDir
31763
+ });
31764
+ }
31082
31765
  const account = buildContextAccount(slug, {
31766
+ observation,
31083
31767
  hook: deps.hook ?? (() => defaultHook(slug)),
31084
31768
  listMemberCommands: deps.listMemberCommands,
31085
31769
  readStoreModes: deps.readStoreModes ?? readMemoryStoreModesNoWrite
@@ -31110,6 +31794,11 @@ var contextCommand = defineCommand({
31110
31794
  description: "Emit the account as JSON",
31111
31795
  required: false
31112
31796
  },
31797
+ observed: {
31798
+ type: "string",
31799
+ description: "Path to ONE session transcript (.jsonl) to measure recorded delivery and usage from. Explicit: nothing is discovered or crawled, and no token is attributed to any file",
31800
+ required: false
31801
+ },
31113
31802
  "no-color": {
31114
31803
  type: "boolean",
31115
31804
  description: "Disable ANSI colour output",
@@ -31117,7 +31806,7 @@ var contextCommand = defineCommand({
31117
31806
  }
31118
31807
  },
31119
31808
  async run({ args }) {
31120
- const result = await runContext({ workspace: args.workspace, json: args.json === true }, { noColor: noColorFromArgs(args) });
31809
+ const result = await runContext({ workspace: args.workspace, json: args.json === true, observed: args.observed }, { noColor: noColorFromArgs(args) });
31121
31810
  if (result.exitCode !== 0)
31122
31811
  process.exit(result.exitCode);
31123
31812
  }
@@ -31484,14 +32173,14 @@ var loginCommand = defineCommand({
31484
32173
  // src/lib/memory-gate/log.ts
31485
32174
  import {
31486
32175
  appendFileSync,
31487
- closeSync as closeSync2,
32176
+ closeSync as closeSync3,
31488
32177
  mkdirSync as mkdirSync8,
31489
- openSync as openSync2,
32178
+ openSync as openSync3,
31490
32179
  readFileSync as readFileSync12,
31491
- readSync,
32180
+ readSync as readSync2,
31492
32181
  statSync as statSync3
31493
32182
  } from "node:fs";
31494
- import { join as join9 } from "node:path";
32183
+ import { join as join10 } from "node:path";
31495
32184
 
31496
32185
  // src/lib/sessions/registry.ts
31497
32186
  import {
@@ -31503,7 +32192,7 @@ import {
31503
32192
  unlinkSync as unlinkSync6,
31504
32193
  writeFileSync as writeFileSync6
31505
32194
  } from "node:fs";
31506
- import { basename as basename2, dirname as dirname6, join as join8 } from "node:path";
32195
+ import { basename as basename3, dirname as dirname7, join as join9 } from "node:path";
31507
32196
  var SessionRecordSchema = exports_external.object({
31508
32197
  version: exports_external.literal(1),
31509
32198
  session_id: exports_external.string().min(1),
@@ -31524,13 +32213,13 @@ function sessionsDir(workspaceSlug) {
31524
32213
  if (!isSafeSegment(workspaceSlug)) {
31525
32214
  throw new Error(`Refusing unsafe workspace slug: ${workspaceSlug}`);
31526
32215
  }
31527
- return join8(plinthHome(), workspaceSlug, "sessions");
32216
+ return join9(plinthHome(), workspaceSlug, "sessions");
31528
32217
  }
31529
32218
  function sessionRecordPath(workspaceSlug, sessionId) {
31530
32219
  if (!isSafeSegment(sessionId)) {
31531
32220
  throw new Error(`Refusing unsafe session id: ${sessionId}`);
31532
32221
  }
31533
- return join8(sessionsDir(workspaceSlug), `${sessionId}.json`);
32222
+ return join9(sessionsDir(workspaceSlug), `${sessionId}.json`);
31534
32223
  }
31535
32224
  function registerSession(input) {
31536
32225
  const startTime = (input.startTimeFn ?? readPidStartTime)(input.pid);
@@ -31553,7 +32242,7 @@ function registerSession(input) {
31553
32242
  }
31554
32243
  var tmpCounter = 0;
31555
32244
  function writeRecordAtomic(target, record2) {
31556
- const dir = dirname6(target);
32245
+ const dir = dirname7(target);
31557
32246
  mkdirSync7(dir, { recursive: true, mode: 448 });
31558
32247
  const tmp = `${target}.${process.pid}.${tmpCounter++}.tmp`;
31559
32248
  sweepDeadTmpFiles(dir, target);
@@ -31569,7 +32258,7 @@ function writeRecordAtomic(target, record2) {
31569
32258
  }
31570
32259
  }
31571
32260
  function sweepDeadTmpFiles(dir, target) {
31572
- const prefix = `${basename2(target)}.`;
32261
+ const prefix = `${basename3(target)}.`;
31573
32262
  let names;
31574
32263
  try {
31575
32264
  names = readdirSync5(dir);
@@ -31586,7 +32275,7 @@ function sweepDeadTmpFiles(dir, target) {
31586
32275
  if (pid === process.pid || isPidAlive(pid))
31587
32276
  continue;
31588
32277
  try {
31589
- unlinkSync6(join8(dir, name));
32278
+ unlinkSync6(join9(dir, name));
31590
32279
  } catch {}
31591
32280
  }
31592
32281
  }
@@ -31651,7 +32340,7 @@ function listSessions(workspaceSlug, deps = {}) {
31651
32340
  for (const name of names) {
31652
32341
  if (!name.endsWith(".json"))
31653
32342
  continue;
31654
- const path3 = join8(sessionsDir(workspaceSlug), name);
32343
+ const path3 = join9(sessionsDir(workspaceSlug), name);
31655
32344
  const record2 = readSessionRecord(path3);
31656
32345
  if (!record2) {
31657
32346
  continue;
@@ -31710,10 +32399,10 @@ function memoryGateDir(workspaceSlug) {
31710
32399
  if (!isSafeSegment(workspaceSlug)) {
31711
32400
  throw new Error(`Refusing unsafe workspace slug: ${workspaceSlug}`);
31712
32401
  }
31713
- return join9(plinthHome(), "_memory_gate", workspaceSlug);
32402
+ return join10(plinthHome(), "_memory_gate", workspaceSlug);
31714
32403
  }
31715
32404
  function memoryGateLogPath(workspaceSlug) {
31716
- return join9(memoryGateDir(workspaceSlug), "log.jsonl");
32405
+ return join10(memoryGateDir(workspaceSlug), "log.jsonl");
31717
32406
  }
31718
32407
  function buildDecisionRecord(input) {
31719
32408
  const final = input.decision === "accept" ? input.proposed : input.decision === "reject" ? null : input.final ?? null;
@@ -31746,13 +32435,13 @@ function endsMidLine(path3) {
31746
32435
  }
31747
32436
  if (size === 0)
31748
32437
  return false;
31749
- const fd = openSync2(path3, "r");
32438
+ const fd = openSync3(path3, "r");
31750
32439
  try {
31751
32440
  const last = Buffer.alloc(1);
31752
- readSync(fd, last, 0, 1, size - 1);
32441
+ readSync2(fd, last, 0, 1, size - 1);
31753
32442
  return last[0] !== 10;
31754
32443
  } finally {
31755
- closeSync2(fd);
32444
+ closeSync3(fd);
31756
32445
  }
31757
32446
  }
31758
32447
  function appendMemoryGateRecord(workspaceSlug, record2) {
@@ -33017,10 +33706,10 @@ import { existsSync as existsSync9, readFileSync as readFileSync26, statSync as
33017
33706
 
33018
33707
  // src/lib/daemon-log.ts
33019
33708
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync9, renameSync as renameSync7, statSync as statSync4 } from "node:fs";
33020
- import { dirname as dirname7, join as join10 } from "node:path";
33709
+ import { dirname as dirname8, join as join11 } from "node:path";
33021
33710
  var DEFAULT_DAEMON_LOG_MAX_BYTES = 5000000;
33022
33711
  function daemonLogPath() {
33023
- return join10(plinthHome(), "daemon.log");
33712
+ return join11(plinthHome(), "daemon.log");
33024
33713
  }
33025
33714
  function daemonLogMaxBytes() {
33026
33715
  const raw = process.env.PLINTH_DAEMON_LOG_MAX_BYTES;
@@ -33042,7 +33731,7 @@ class DaemonLog {
33042
33731
  this.now = opts.now ?? (() => new Date);
33043
33732
  this.maxBytes = opts.maxBytes ?? daemonLogMaxBytes();
33044
33733
  try {
33045
- mkdirSync9(dirname7(this.path), { recursive: true });
33734
+ mkdirSync9(dirname8(this.path), { recursive: true });
33046
33735
  } catch {}
33047
33736
  try {
33048
33737
  this.bytesWritten = statSync4(this.path).size;
@@ -33081,7 +33770,7 @@ class DaemonLog {
33081
33770
  // src/lib/destructive-gate.ts
33082
33771
  var import_gray_matter7 = __toESM(require_gray_matter(), 1);
33083
33772
  import { readFileSync as readFileSync14, statSync as statSync5 } from "node:fs";
33084
- import { basename as basename3 } from "node:path";
33773
+ import { basename as basename4 } from "node:path";
33085
33774
  var GUTTING_RATIO_DEFAULT = 0.5;
33086
33775
  var GUTTING_MIN_PRIOR_BYTES = 200;
33087
33776
  function envFloat(name, def) {
@@ -33146,7 +33835,7 @@ function classifyDestructive(event, entityType, state, deps = {}) {
33146
33835
  return null;
33147
33836
  }
33148
33837
  const liveInode = statInode(event.absolutePath);
33149
- const slug = basename3(event.absolutePath, ".md");
33838
+ const slug = basename4(event.absolutePath, ".md");
33150
33839
  const entry2 = (liveInode !== undefined ? getEntryByInode(state, entityType, liveInode) : undefined) ?? getEntryBySlug(state, entityType, slug);
33151
33840
  if (!entry2)
33152
33841
  return null;
@@ -33261,18 +33950,18 @@ import { readFileSync as readFileSync18 } from "node:fs";
33261
33950
 
33262
33951
  // src/lib/conflicts.ts
33263
33952
  import { mkdirSync as mkdirSync10, readdirSync as readdirSync6, statSync as statSync6, writeFileSync as writeFileSync7 } from "node:fs";
33264
- import { dirname as dirname8, join as join11 } from "node:path";
33953
+ import { dirname as dirname9, join as join12 } from "node:path";
33265
33954
  function conflictsRoot(workspaceSlug) {
33266
- return join11(plinthHome(), "_conflicts", workspaceSlug);
33955
+ return join12(plinthHome(), "_conflicts", workspaceSlug);
33267
33956
  }
33268
33957
  function conflictFilePath(args) {
33269
33958
  const { workspaceSlug, entityType, entitySlug, timestamp, side } = args;
33270
33959
  const iso = timestamp.toISOString().replace(/[:.]/g, "-");
33271
- return join11(conflictsRoot(workspaceSlug), `${entityType}.${entitySlug}.${iso}.${side}.md`);
33960
+ return join12(conflictsRoot(workspaceSlug), `${entityType}.${entitySlug}.${iso}.${side}.md`);
33272
33961
  }
33273
33962
  function stashConflict(args) {
33274
33963
  const target = conflictFilePath(args);
33275
- mkdirSync10(dirname8(target), { recursive: true, mode: 448 });
33964
+ mkdirSync10(dirname9(target), { recursive: true, mode: 448 });
33276
33965
  writeFileSync7(target, args.contents, { mode: 384 });
33277
33966
  return target;
33278
33967
  }
@@ -33280,11 +33969,11 @@ function fileConflictPath(args) {
33280
33969
  const { workspaceSlug, relPath, timestamp, side } = args;
33281
33970
  const iso = timestamp.toISOString().replace(/[:.]/g, "-");
33282
33971
  const safe = relPath.replace(/[/\\]/g, "__");
33283
- return join11(conflictsRoot(workspaceSlug), `files.${safe}.${iso}.${side}`);
33972
+ return join12(conflictsRoot(workspaceSlug), `files.${safe}.${iso}.${side}`);
33284
33973
  }
33285
33974
  function stashFileConflict(args) {
33286
33975
  const target = fileConflictPath(args);
33287
- mkdirSync10(dirname8(target), { recursive: true, mode: 448 });
33976
+ mkdirSync10(dirname9(target), { recursive: true, mode: 448 });
33288
33977
  writeFileSync7(target, args.bytes, { mode: 384 });
33289
33978
  return target;
33290
33979
  }
@@ -33317,7 +34006,7 @@ function listConflictStashes(workspaceSlug) {
33317
34006
  }
33318
34007
  const out = [];
33319
34008
  for (const file2 of names) {
33320
- const absPath = join11(dir, file2);
34009
+ const absPath = join12(dir, file2);
33321
34010
  let st;
33322
34011
  try {
33323
34012
  st = statSync6(absPath);
@@ -33346,9 +34035,9 @@ function listConflictStashes(workspaceSlug) {
33346
34035
  import { readFileSync as readFileSync15, statSync as statSync7 } from "node:fs";
33347
34036
 
33348
34037
  // src/lib/files/content-hash.ts
33349
- import { createHash as createHash2 } from "node:crypto";
34038
+ import { createHash as createHash3 } from "node:crypto";
33350
34039
  function sha256Bytes(bytes) {
33351
- return createHash2("sha256").update(bytes).digest("hex");
34040
+ return createHash3("sha256").update(bytes).digest("hex");
33352
34041
  }
33353
34042
 
33354
34043
  // src/lib/files/mime.ts
@@ -33668,8 +34357,8 @@ class PerIdMutex {
33668
34357
 
33669
34358
  // src/lib/push.ts
33670
34359
  var import_gray_matter10 = __toESM(require_gray_matter(), 1);
33671
- import { readFileSync as readFileSync17, statSync as statSync8 } from "node:fs";
33672
- import { basename as basename4, relative as relative5 } from "node:path";
34360
+ import { existsSync as existsSync4, readFileSync as readFileSync17, statSync as statSync8 } from "node:fs";
34361
+ import { basename as basename5, relative as relative5 } from "node:path";
33673
34362
 
33674
34363
  // src/lib/frontmatter-id.ts
33675
34364
  var import_gray_matter8 = __toESM(require_gray_matter(), 1);
@@ -33856,6 +34545,10 @@ function writeMirrorWithBodyPreserve(workspaceSlug, strategy, doc2, suppressor,
33856
34545
  }
33857
34546
 
33858
34547
  // src/lib/push.ts
34548
+ var DELETE_DECLINED_PATH_EXISTS = "the file is on disk again — a newer write owns this row";
34549
+ function deleteDeclinedSentence(relPath) {
34550
+ 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.`;
34551
+ }
33859
34552
  function normaliseWireBody(body) {
33860
34553
  if (body === undefined)
33861
34554
  return;
@@ -34150,7 +34843,7 @@ async function pushFile(args) {
34150
34843
  const rel = relative5(workspaceMirrorPath(workspaceSlug), absolutePath);
34151
34844
  parsedSlug = strategy.parseMirrorPath(rel)?.slug ?? null;
34152
34845
  } catch {}
34153
- const slugFromPath = parsedSlug ?? basename4(absolutePath, ".md");
34846
+ const slugFromPath = parsedSlug ?? basename5(absolutePath, ".md");
34154
34847
  const slug = identity === "path" ? slugFromPath : slugFromFm ?? slugFromPath;
34155
34848
  if (!slug) {
34156
34849
  return {
@@ -34233,15 +34926,16 @@ async function reconcileContextDocConflict(args) {
34233
34926
  now,
34234
34927
  output
34235
34928
  } = args;
34929
+ const base2 = args.state;
34236
34930
  let state = args.state;
34237
34931
  const existingSlug = existing.slug;
34238
34932
  const existingId = existing.id;
34239
34933
  let fileSlug;
34240
34934
  try {
34241
34935
  const rel = relative5(workspaceMirrorPath(workspaceSlug), absolutePath);
34242
- fileSlug = strategy.parseMirrorPath(rel)?.slug ?? basename4(absolutePath, ".md");
34936
+ fileSlug = strategy.parseMirrorPath(rel)?.slug ?? basename5(absolutePath, ".md");
34243
34937
  } catch {
34244
- fileSlug = basename4(absolutePath, ".md");
34938
+ fileSlug = basename5(absolutePath, ".md");
34245
34939
  }
34246
34940
  if (fileSlug !== existingSlug) {
34247
34941
  const stashPath = stashConflict({
@@ -34282,7 +34976,8 @@ async function reconcileContextDocConflict(args) {
34282
34976
  entitySlug: fileSlug,
34283
34977
  stashPath
34284
34978
  },
34285
- state: nextState
34979
+ state: nextState,
34980
+ base: base2
34286
34981
  };
34287
34982
  }
34288
34983
  const stashPreLandCloudCopy = () => stashConflict({
@@ -34344,7 +35039,8 @@ async function reconcileContextDocConflict(args) {
34344
35039
  entitySlug: updated.slug,
34345
35040
  stashPath: preLandStash
34346
35041
  },
34347
- state
35042
+ state,
35043
+ base: base2
34348
35044
  };
34349
35045
  }
34350
35046
  if (patchResult.code === 404) {
@@ -34402,7 +35098,8 @@ async function reconcileContextDocConflict(args) {
34402
35098
  entitySlug: fileSlug,
34403
35099
  stashPath
34404
35100
  },
34405
- state
35101
+ state,
35102
+ base: base2
34406
35103
  };
34407
35104
  }
34408
35105
  if (patchResult.reason === "context_doc_conflict") {
@@ -34430,10 +35127,11 @@ async function runPushUpsert(args) {
34430
35127
  const hashBody = hashableBody(strategy, bodyMarkdown);
34431
35128
  const newBodyHash = stableHash(hashBody);
34432
35129
  const newFrontmatterHash = stableHash({ ...userFm, ...lifted.topLevel });
34433
- const liveEntry = getEntry(args.state, strategy.type, args.stateEntry.id) ?? args.stateEntry;
35130
+ const snapshotEntry = getEntry(args.state, strategy.type, args.stateEntry.id) ?? args.stateEntry;
35131
+ const liveEntry = committedEntryIfNewer(args.workspaceSlug, strategy.type, snapshotEntry) ?? snapshotEntry;
34434
35132
  const bodyChanged = newBodyHash !== liveEntry.body_hash;
34435
35133
  const frontmatterChanged = newFrontmatterHash !== liveEntry.frontmatter_hash;
34436
- let workingState = args.state;
35134
+ let workingState = liveEntry === snapshotEntry ? args.state : upsertEntry(args.state, strategy.type, liveEntry).state;
34437
35135
  if (fm["id"] === undefined && workingState.frontmatter_id_backfill_version !== undefined) {
34438
35136
  const cleared = clearFrontmatterIdBackfillMarker(workingState);
34439
35137
  if (cleared.changed) {
@@ -34442,6 +35140,69 @@ async function runPushUpsert(args) {
34442
35140
  } catch {}
34443
35141
  }
34444
35142
  }
35143
+ const wireProjection = (md) => {
35144
+ try {
35145
+ const p = import_gray_matter10.default(md);
35146
+ const f = p.data ?? {};
35147
+ const l = splitUserFrontmatter(strategy, f);
35148
+ const u = userFrontmatter(strategy, l.frontmatter);
35149
+ return stableHash({
35150
+ body: strategy.bodyToWire(p.content),
35151
+ frontmatter: { ...u, ...l.topLevel }
35152
+ });
35153
+ } catch {
35154
+ return null;
35155
+ }
35156
+ };
35157
+ if (liveEntry !== snapshotEntry) {
35158
+ let onDisk = null;
35159
+ try {
35160
+ onDisk = readFileSync17(args.absolutePath, "utf8");
35161
+ } catch {
35162
+ onDisk = null;
35163
+ }
35164
+ if (onDisk !== null && onDisk !== args.raw) {
35165
+ let disk = null;
35166
+ try {
35167
+ disk = computeMirrorHashes(strategy, onDisk);
35168
+ } catch {
35169
+ disk = null;
35170
+ }
35171
+ if (disk !== null && disk.bodyHash === liveEntry.body_hash && disk.frontmatterHash === liveEntry.frontmatter_hash) {
35172
+ const ours = wireProjection(args.raw);
35173
+ const theirs = wireProjection(onDisk);
35174
+ if (ours !== null && theirs !== null && ours === theirs) {
35175
+ return {
35176
+ outcome: {
35177
+ kind: "noop",
35178
+ entityType: strategy.type,
35179
+ entitySlug: liveEntry.slug
35180
+ },
35181
+ state: workingState,
35182
+ base: workingState
35183
+ };
35184
+ }
35185
+ const stashPath2 = stashConflict({
35186
+ workspaceSlug: args.workspaceSlug,
35187
+ entityType: strategy.type,
35188
+ entitySlug: liveEntry.slug,
35189
+ timestamp: args.now(),
35190
+ contents: args.raw,
35191
+ side: "local"
35192
+ });
35193
+ return {
35194
+ outcome: {
35195
+ kind: "conflict",
35196
+ entityType: strategy.type,
35197
+ entitySlug: liveEntry.slug,
35198
+ stashPath: stashPath2
35199
+ },
35200
+ state: workingState,
35201
+ base: workingState
35202
+ };
35203
+ }
35204
+ }
35205
+ }
34445
35206
  if (!bodyChanged && !frontmatterChanged) {
34446
35207
  return {
34447
35208
  outcome: {
@@ -34449,7 +35210,8 @@ async function runPushUpsert(args) {
34449
35210
  entityType: strategy.type,
34450
35211
  entitySlug: liveEntry.slug
34451
35212
  },
34452
- state: workingState
35213
+ state: workingState,
35214
+ base: workingState
34453
35215
  };
34454
35216
  }
34455
35217
  const wireBodyFields = bodyChanged ? strategy.bodyToWire(bodyMarkdown) : undefined;
@@ -34468,7 +35230,8 @@ async function runPushUpsert(args) {
34468
35230
  entityType: strategy.type,
34469
35231
  entitySlug: liveEntry.slug
34470
35232
  },
34471
- state: persistEntry(workingState, strategy.type, updated)
35233
+ state: persistEntry(workingState, strategy.type, updated),
35234
+ base: workingState
34472
35235
  };
34473
35236
  }
34474
35237
  const mergedTopLevel = split || wireBodyFields?.topLevel ? {
@@ -34504,7 +35267,8 @@ async function runPushUpsert(args) {
34504
35267
  fields,
34505
35268
  pushed: false
34506
35269
  },
34507
- state: nextState2
35270
+ state: nextState2,
35271
+ base: workingState
34508
35272
  };
34509
35273
  }
34510
35274
  let patchResult = await patchEntity({
@@ -34577,7 +35341,8 @@ async function runPushUpsert(args) {
34577
35341
  fields,
34578
35342
  pushed: true
34579
35343
  },
34580
- state: nextState2
35344
+ state: nextState2,
35345
+ base: workingState
34581
35346
  };
34582
35347
  }
34583
35348
  return {
@@ -34586,7 +35351,8 @@ async function runPushUpsert(args) {
34586
35351
  entityType: strategy.type,
34587
35352
  entitySlug: updated.slug
34588
35353
  },
34589
- state: nextState2
35354
+ state: nextState2,
35355
+ base: workingState
34590
35356
  };
34591
35357
  }
34592
35358
  if (patchResult.code === 404) {
@@ -34596,7 +35362,8 @@ async function runPushUpsert(args) {
34596
35362
  entityType: strategy.type,
34597
35363
  entitySlug: liveEntry.slug
34598
35364
  },
34599
- state: workingState
35365
+ state: workingState,
35366
+ base: workingState
34600
35367
  };
34601
35368
  }
34602
35369
  if (patchResult.reason === "slug_conflict") {
@@ -34666,7 +35433,8 @@ async function runPushUpsert(args) {
34666
35433
  entitySlug: liveEntry.slug,
34667
35434
  stashPath
34668
35435
  },
34669
- state: nextState
35436
+ state: nextState,
35437
+ base: workingState
34670
35438
  };
34671
35439
  });
34672
35440
  }
@@ -34685,6 +35453,7 @@ async function reconcileTaskConflict(args) {
34685
35453
  now,
34686
35454
  output
34687
35455
  } = args;
35456
+ const base2 = args.state;
34688
35457
  let state = args.state;
34689
35458
  const stashLocalSide = () => stashConflict({
34690
35459
  workspaceSlug,
@@ -34717,7 +35486,8 @@ async function reconcileTaskConflict(args) {
34717
35486
  entitySlug: liveEntry.slug,
34718
35487
  stashPath: stashPath2
34719
35488
  },
34720
- state
35489
+ state,
35490
+ base: base2
34721
35491
  };
34722
35492
  }
34723
35493
  let cloudRow = null;
@@ -34735,7 +35505,8 @@ async function reconcileTaskConflict(args) {
34735
35505
  entityType: strategy.type,
34736
35506
  entitySlug: liveEntry.slug
34737
35507
  },
34738
- state
35508
+ state,
35509
+ base: base2
34739
35510
  };
34740
35511
  }
34741
35512
  const stashCloudSide = () => stashConflict({
@@ -34775,7 +35546,8 @@ async function reconcileTaskConflict(args) {
34775
35546
  entitySlug: patchResult.doc.slug,
34776
35547
  stashPath: stashPath2
34777
35548
  },
34778
- state
35549
+ state,
35550
+ base: base2
34779
35551
  };
34780
35552
  }
34781
35553
  if (patchResult.code === 404) {
@@ -34786,7 +35558,8 @@ async function reconcileTaskConflict(args) {
34786
35558
  entityType: strategy.type,
34787
35559
  entitySlug: liveEntry.slug
34788
35560
  },
34789
- state
35561
+ state,
35562
+ base: base2
34790
35563
  };
34791
35564
  }
34792
35565
  const stashPath = stashLocalSide();
@@ -34809,7 +35582,8 @@ async function reconcileTaskConflict(args) {
34809
35582
  entitySlug: liveEntry.slug,
34810
35583
  stashPath
34811
35584
  },
34812
- state
35585
+ state,
35586
+ base: base2
34813
35587
  };
34814
35588
  }
34815
35589
  function writeCreatedIdBack(args) {
@@ -34920,7 +35694,8 @@ async function runPushCreate(args) {
34920
35694
  fields,
34921
35695
  pushed: true
34922
35696
  },
34923
- state: nextState2
35697
+ state: nextState2,
35698
+ base: args.state
34924
35699
  };
34925
35700
  }
34926
35701
  return {
@@ -34929,7 +35704,8 @@ async function runPushCreate(args) {
34929
35704
  entityType: strategy.type,
34930
35705
  entitySlug: doc2.slug
34931
35706
  },
34932
- state: nextState2
35707
+ state: nextState2,
35708
+ base: args.state
34933
35709
  };
34934
35710
  }
34935
35711
  if (createResult.reason === "context_doc_conflict") {
@@ -34978,7 +35754,8 @@ async function runPushCreate(args) {
34978
35754
  entitySlug: args.slug,
34979
35755
  stashPath
34980
35756
  },
34981
- state: nextState
35757
+ state: nextState,
35758
+ base: args.state
34982
35759
  };
34983
35760
  });
34984
35761
  }
@@ -34997,7 +35774,7 @@ async function runPushDelete(args) {
34997
35774
  const rel = relative5(workspaceMirrorPath(args.workspaceSlug), args.absolutePath);
34998
35775
  parsedSlug = strategy.parseMirrorPath(rel)?.slug ?? null;
34999
35776
  } catch {}
35000
- const lookupSlug = parsedSlug ?? basename4(args.absolutePath, ".md");
35777
+ const lookupSlug = parsedSlug ?? basename5(args.absolutePath, ".md");
35001
35778
  const entry2 = getEntryBySlug(args.state, strategy.type, lookupSlug);
35002
35779
  if (entry2) {
35003
35780
  id = entry2.id;
@@ -35012,12 +35789,31 @@ async function runPushDelete(args) {
35012
35789
  absolutePath: args.absolutePath,
35013
35790
  reason: "untracked file — no cloud row to delete"
35014
35791
  },
35015
- state: args.state
35792
+ state: args.state,
35793
+ base: args.state
35016
35794
  };
35017
35795
  }
35018
35796
  return args.mutex.run(id, async () => {
35019
- const live = getEntry(args.state, strategy.type, id) ?? null;
35797
+ const snapshot = getEntry(args.state, strategy.type, id) ?? null;
35798
+ const live = snapshot ? committedEntryIfNewer(args.workspaceSlug, strategy.type, snapshot) ?? snapshot : null;
35799
+ if (existsSync4(args.absolutePath)) {
35800
+ args.output?.log(entityDeleteSuppressedLine({
35801
+ entityType: strategy.type,
35802
+ slug,
35803
+ reason: "path_exists"
35804
+ }));
35805
+ return {
35806
+ outcome: {
35807
+ kind: "ignored",
35808
+ absolutePath: args.absolutePath,
35809
+ reason: DELETE_DECLINED_PATH_EXISTS
35810
+ },
35811
+ state: args.state,
35812
+ base: args.state
35813
+ };
35814
+ }
35020
35815
  const effectiveExpected = live?.updated_at ?? expectedUpdatedAt;
35816
+ const workingState = live && live !== snapshot ? upsertEntry(args.state, strategy.type, live).state : args.state;
35021
35817
  const result = await deleteEntity({
35022
35818
  strategy,
35023
35819
  baseUrl: args.baseUrl,
@@ -35027,7 +35823,7 @@ async function runPushDelete(args) {
35027
35823
  fetchImpl: args.fetchImpl
35028
35824
  });
35029
35825
  if (result.ok) {
35030
- const nextState2 = dropEntry(args.state, strategy.type, id);
35826
+ const nextState2 = dropEntry(workingState, strategy.type, id);
35031
35827
  args.output?.log(`[DELETE entityType=${strategy.type} slug=${slug} id=${id}]`);
35032
35828
  return {
35033
35829
  outcome: {
@@ -35035,11 +35831,12 @@ async function runPushDelete(args) {
35035
35831
  entityType: strategy.type,
35036
35832
  entitySlug: slug
35037
35833
  },
35038
- state: nextState2
35834
+ state: nextState2,
35835
+ base: workingState
35039
35836
  };
35040
35837
  }
35041
35838
  if (result.code === 404) {
35042
- const nextState2 = dropEntry(args.state, strategy.type, id);
35839
+ const nextState2 = dropEntry(workingState, strategy.type, id);
35043
35840
  args.output?.log(`[DELETE entityType=${strategy.type} slug=${slug} id=${id} note=already_absent]`);
35044
35841
  return {
35045
35842
  outcome: {
@@ -35047,7 +35844,8 @@ async function runPushDelete(args) {
35047
35844
  entityType: strategy.type,
35048
35845
  entitySlug: slug
35049
35846
  },
35050
- state: nextState2
35847
+ state: nextState2,
35848
+ base: workingState
35051
35849
  };
35052
35850
  }
35053
35851
  const nextState = await pullAndWriteMirror({
@@ -35069,7 +35867,8 @@ async function runPushDelete(args) {
35069
35867
  entitySlug: slug,
35070
35868
  stashPath: ""
35071
35869
  },
35072
- state: nextState
35870
+ state: nextState,
35871
+ base: workingState
35073
35872
  };
35074
35873
  });
35075
35874
  }
@@ -35096,13 +35895,15 @@ async function pushRename(args) {
35096
35895
  let toSlug;
35097
35896
  try {
35098
35897
  const rel = relative5(workspaceMirrorPath(workspaceSlug), toPath);
35099
- toSlug = strategy.parseMirrorPath(rel)?.slug ?? basename4(toPath, ".md");
35898
+ toSlug = strategy.parseMirrorPath(rel)?.slug ?? basename5(toPath, ".md");
35100
35899
  } catch {
35101
- toSlug = basename4(toPath, ".md");
35900
+ toSlug = basename5(toPath, ".md");
35102
35901
  }
35103
35902
  return mutex.run(id, async () => {
35104
- const live = getEntry(state, entityType, id);
35903
+ const snapshot = getEntry(state, entityType, id);
35904
+ const live = snapshot ? committedEntryIfNewer(workspaceSlug, entityType, snapshot) ?? snapshot : undefined;
35105
35905
  const effectiveExpected = live?.updated_at ?? expectedUpdatedAt;
35906
+ const workingState = live && live !== snapshot ? upsertEntry(state, entityType, live).state : state;
35106
35907
  let patchResult = await patchEntity({
35107
35908
  strategy,
35108
35909
  baseUrl,
@@ -35162,7 +35963,7 @@ async function pushRename(args) {
35162
35963
  updated.body_len = renameHashBody.length;
35163
35964
  } catch {}
35164
35965
  }
35165
- const nextState2 = persistEntry(state, entityType, updated);
35966
+ const nextState2 = persistEntry(workingState, entityType, updated);
35166
35967
  output?.log(`[RENAME entityType=${entityType} fromSlug=${fromSlug} toSlug=${doc2.slug} id=${doc2.id}]`);
35167
35968
  return {
35168
35969
  outcome: {
@@ -35171,13 +35972,15 @@ async function pushRename(args) {
35171
35972
  fromSlug,
35172
35973
  toSlug: doc2.slug
35173
35974
  },
35174
- state: nextState2
35975
+ state: nextState2,
35976
+ base: workingState
35175
35977
  };
35176
35978
  }
35177
35979
  if (patchResult.code === 404) {
35178
35980
  return {
35179
35981
  outcome: { kind: "not_found", entityType, entitySlug: fromSlug },
35180
- state
35982
+ state: workingState,
35983
+ base: workingState
35181
35984
  };
35182
35985
  }
35183
35986
  if (patchResult.reason === "slug_conflict") {
@@ -35199,7 +36002,7 @@ async function pushRename(args) {
35199
36002
  baseUrl,
35200
36003
  pat,
35201
36004
  id: patchResult.existing.id,
35202
- state,
36005
+ state: workingState,
35203
36006
  fetchImpl,
35204
36007
  echo,
35205
36008
  output,
@@ -35225,7 +36028,8 @@ async function pushRename(args) {
35225
36028
  toSlug,
35226
36029
  stashPath: stashPath2
35227
36030
  },
35228
- state: finalState
36031
+ state: finalState,
36032
+ base: workingState
35229
36033
  };
35230
36034
  }
35231
36035
  let contents = "";
@@ -35246,7 +36050,7 @@ async function pushRename(args) {
35246
36050
  baseUrl,
35247
36051
  pat,
35248
36052
  id,
35249
- state,
36053
+ state: workingState,
35250
36054
  fetchImpl,
35251
36055
  echo,
35252
36056
  output,
@@ -35259,7 +36063,8 @@ async function pushRename(args) {
35259
36063
  entitySlug: fromSlug,
35260
36064
  stashPath
35261
36065
  },
35262
- state: nextState
36066
+ state: nextState,
36067
+ base: workingState
35263
36068
  };
35264
36069
  });
35265
36070
  }
@@ -35295,13 +36100,14 @@ async function applyBatch(batch, deps, mutex) {
35295
36100
  await applyFileOp(op, deps);
35296
36101
  continue;
35297
36102
  }
36103
+ const base2 = deps.getState();
35298
36104
  const result = await pushFile({
35299
36105
  workspaceSlug: deps.workspaceSlug,
35300
36106
  baseUrl: deps.baseUrl,
35301
36107
  pat: deps.pat,
35302
36108
  absolutePath: opPath(deps.workspaceSlug, op),
35303
36109
  entityType: op.entityType,
35304
- state: deps.getState(),
36110
+ state: base2,
35305
36111
  exists: op.kind === "overwrite",
35306
36112
  unlinkContext: op.kind === "delete" ? { id: op.id, slug: op.slug, updated_at: op.updated_at } : null,
35307
36113
  deps: {
@@ -35312,7 +36118,10 @@ async function applyBatch(batch, deps, mutex) {
35312
36118
  echo: deps.echo
35313
36119
  }
35314
36120
  });
35315
- deps.setState(result.state);
36121
+ deps.applyState(result.base ?? base2, result.state);
36122
+ if (result.outcome.kind === "ignored" && result.outcome.reason === DELETE_DECLINED_PATH_EXISTS) {
36123
+ deps.output?.warn(deleteDeclinedSentence(opPath(deps.workspaceSlug, op)));
36124
+ }
35316
36125
  } catch (err) {
35317
36126
  const msg = err instanceof Error ? err.message : "unknown error";
35318
36127
  deps.output?.warn(`Apply failed for ${opLabel(op)}: ${msg} (left for the next pull to reconcile).`);
@@ -35322,27 +36131,29 @@ async function applyBatch(batch, deps, mutex) {
35322
36131
  async function applyFileOp(op, deps) {
35323
36132
  const fileDeps = { fetchImpl: deps.fetchImpl, now: deps.now, output: deps.output };
35324
36133
  if (op.kind === "delete") {
36134
+ const base3 = deps.getState();
35325
36135
  const result2 = await pushFilesDelete({
35326
36136
  workspaceSlug: deps.workspaceSlug,
35327
36137
  baseUrl: deps.baseUrl,
35328
36138
  pat: deps.pat,
35329
36139
  relPath: op.path,
35330
- state: deps.getState(),
36140
+ state: base3,
35331
36141
  deps: fileDeps
35332
36142
  });
35333
- deps.setState(result2.state);
36143
+ deps.applyState(base3, result2.state);
35334
36144
  return;
35335
36145
  }
36146
+ const base2 = deps.getState();
35336
36147
  const result = await pushFilesUpsert({
35337
36148
  workspaceSlug: deps.workspaceSlug,
35338
36149
  baseUrl: deps.baseUrl,
35339
36150
  pat: deps.pat,
35340
36151
  absolutePath: filesSubtreePath(deps.workspaceSlug, op.path),
35341
36152
  relPath: op.path,
35342
- state: deps.getState(),
36153
+ state: base2,
35343
36154
  deps: fileDeps
35344
36155
  });
35345
- deps.setState(result.state);
36156
+ deps.applyState(base2, result.state);
35346
36157
  }
35347
36158
  async function discardBatchOps(batch, deps) {
35348
36159
  for (const op of batch.ops) {
@@ -35371,19 +36182,20 @@ async function discardBatchOps(batch, deps) {
35371
36182
  });
35372
36183
  }
35373
36184
  }
36185
+ const base2 = deps.getState();
35374
36186
  const next = await pullAndWriteMirror({
35375
36187
  strategy,
35376
36188
  workspaceSlug: deps.workspaceSlug,
35377
36189
  baseUrl: deps.baseUrl,
35378
36190
  pat: deps.pat,
35379
36191
  id: op.id,
35380
- state: deps.getState(),
36192
+ state: base2,
35381
36193
  fetchImpl: deps.fetchImpl,
35382
36194
  echo: deps.echo,
35383
36195
  output: deps.output,
35384
36196
  now: deps.now
35385
36197
  });
35386
- deps.setState(next);
36198
+ deps.applyState(base2, next);
35387
36199
  } catch (err) {
35388
36200
  const msg = err instanceof Error ? err.message : "unknown error";
35389
36201
  deps.output?.warn(`Discard restore failed for ${opLabel(op)}: ${msg} (the next pull will reconcile).`);
@@ -35407,17 +36219,18 @@ async function discardFileOp(op, deps) {
35407
36219
  side: "local"
35408
36220
  });
35409
36221
  }
36222
+ const base2 = deps.getState();
35410
36223
  const next = await restoreFileFromCloud({
35411
36224
  workspaceSlug: deps.workspaceSlug,
35412
36225
  baseUrl: deps.baseUrl,
35413
36226
  pat: deps.pat,
35414
36227
  id: op.id,
35415
36228
  relPath: op.path,
35416
- state: deps.getState(),
36229
+ state: base2,
35417
36230
  fetchImpl: deps.fetchImpl,
35418
36231
  output: deps.output
35419
36232
  });
35420
- deps.setState(next);
36233
+ deps.applyState(base2, next);
35421
36234
  }
35422
36235
  function opPath(workspaceSlug, op) {
35423
36236
  try {
@@ -35430,7 +36243,7 @@ function opPath(workspaceSlug, op) {
35430
36243
  }
35431
36244
 
35432
36245
  // src/lib/files/classify.ts
35433
- import { relative as relative6, sep as sep4 } from "node:path";
36246
+ import { relative as relative6, sep as sep5 } from "node:path";
35434
36247
  var FILES_SUBTREE = "files";
35435
36248
  function classifyFilesPath(args) {
35436
36249
  let root;
@@ -35440,20 +36253,20 @@ function classifyFilesPath(args) {
35440
36253
  return null;
35441
36254
  }
35442
36255
  const rel = relative6(root, args.absolutePath);
35443
- if (rel.startsWith("..") || rel.startsWith(sep4))
36256
+ if (rel.startsWith("..") || rel.startsWith(sep5))
35444
36257
  return null;
35445
- const prefix = FILES_SUBTREE + sep4;
36258
+ const prefix = FILES_SUBTREE + sep5;
35446
36259
  if (!rel.startsWith(prefix))
35447
36260
  return null;
35448
36261
  const sub = rel.slice(prefix.length);
35449
36262
  if (sub.length === 0)
35450
36263
  return null;
35451
- const posix = sep4 === "/" ? sub : sub.split(sep4).join("/");
36264
+ const posix = sep5 === "/" ? sub : sub.split(sep5).join("/");
35452
36265
  return validateFilesRelPath(posix) ? { relPath: posix } : null;
35453
36266
  }
35454
36267
 
35455
36268
  // src/lib/memory-facts/sync.ts
35456
- import { isAbsolute as isAbsolute2, relative as relative7, sep as sep5 } from "node:path";
36269
+ import { isAbsolute as isAbsolute2, relative as relative7, sep as sep6 } from "node:path";
35457
36270
 
35458
36271
  // src/lib/memory-facts/api.ts
35459
36272
  var FactCommonSchema = exports_external.object({
@@ -35774,7 +36587,7 @@ function classifyMemoryFactPath(args) {
35774
36587
  const rel = relative7(root, args.absolutePath);
35775
36588
  if (rel === "" || rel.startsWith("..") || isAbsolute2(rel))
35776
36589
  return null;
35777
- const mirrorRel = `${MEMORY_FACTS_DIR}/${rel.split(sep5).join("/")}`;
36590
+ const mirrorRel = `${MEMORY_FACTS_DIR}/${rel.split(sep6).join("/")}`;
35778
36591
  return { relPath: mirrorRel, fact: parseMemoryFactRelPath(mirrorRel) };
35779
36592
  }
35780
36593
  function classifyMemoryFactEvent(args) {
@@ -35933,7 +36746,7 @@ class FileDestructiveGate {
35933
36746
  import { readFileSync as readFileSync19, statSync as statSync10 } from "node:fs";
35934
36747
 
35935
36748
  // src/lib/unsynced.ts
35936
- import { join as join12, relative as relative8 } from "node:path";
36749
+ import { join as join13, relative as relative8 } from "node:path";
35937
36750
  var RECORDABLE_REASONS = new Set([
35938
36751
  "rate_limit",
35939
36752
  "server",
@@ -35978,7 +36791,7 @@ function recordFileUnsynced(args) {
35978
36791
  });
35979
36792
  }
35980
36793
  async function drainUnsyncedOps(args) {
35981
- const { workspaceSlug, baseUrl, pat, getState, setState, fetchImpl, mutex, output, echo } = args;
36794
+ const { workspaceSlug, baseUrl, pat, getState, applyState, fetchImpl, mutex, output, echo } = args;
35982
36795
  const now = args.now ?? (() => new Date);
35983
36796
  const ops = listUnsynced(getState());
35984
36797
  let attempted = 0;
@@ -35989,51 +36802,59 @@ async function drainUnsyncedOps(args) {
35989
36802
  const before = getState();
35990
36803
  const { state: next, changed } = removeUnsynced(before, target, path5);
35991
36804
  if (changed)
35992
- setState(commitState(before, next));
36805
+ applyState(before, commitState(before, next));
35993
36806
  };
35994
36807
  for (const op of ops) {
35995
36808
  attempted += 1;
35996
36809
  try {
35997
36810
  if (op.target === "entity") {
35998
- const absolutePath = join12(workspaceMirrorPath(workspaceSlug), op.path);
36811
+ const absolutePath = join13(workspaceMirrorPath(workspaceSlug), op.path);
35999
36812
  const classified = classifyMirrorPath({ workspaceSlug, absolutePath });
36000
36813
  if (!classified) {
36001
36814
  clear("entity", op.path);
36002
36815
  resolved += 1;
36003
36816
  continue;
36004
36817
  }
36818
+ const base2 = getState();
36005
36819
  const result = await pushFile({
36006
36820
  workspaceSlug,
36007
36821
  baseUrl,
36008
36822
  pat,
36009
36823
  absolutePath,
36010
36824
  entityType: classified.entityType,
36011
- state: getState(),
36825
+ state: base2,
36012
36826
  exists: op.op === "upsert",
36013
36827
  unlinkContext: null,
36014
36828
  deps: { fetchImpl, now, mutex, output, echo }
36015
36829
  });
36016
- setState(result.state);
36830
+ applyState(result.base ?? base2, result.state);
36831
+ if (result.outcome.kind === "ignored" && result.outcome.reason === DELETE_DECLINED_PATH_EXISTS) {
36832
+ output?.warn(deleteDeclinedSentence(op.path));
36833
+ }
36017
36834
  } else {
36018
36835
  const absolutePath = filesSubtreePath(workspaceSlug, op.path);
36019
- const doFile = () => op.op === "delete" ? pushFilesDelete({
36020
- workspaceSlug,
36021
- baseUrl,
36022
- pat,
36023
- relPath: op.path,
36024
- state: getState(),
36025
- deps: { fetchImpl, now, output }
36026
- }) : pushFilesUpsert({
36027
- workspaceSlug,
36028
- baseUrl,
36029
- pat,
36030
- absolutePath,
36031
- relPath: op.path,
36032
- state: getState(),
36033
- deps: { fetchImpl, now, output }
36034
- });
36836
+ let base2;
36837
+ const doFile = () => {
36838
+ base2 = getState();
36839
+ return op.op === "delete" ? pushFilesDelete({
36840
+ workspaceSlug,
36841
+ baseUrl,
36842
+ pat,
36843
+ relPath: op.path,
36844
+ state: base2,
36845
+ deps: { fetchImpl, now, output }
36846
+ }) : pushFilesUpsert({
36847
+ workspaceSlug,
36848
+ baseUrl,
36849
+ pat,
36850
+ absolutePath,
36851
+ relPath: op.path,
36852
+ state: base2,
36853
+ deps: { fetchImpl, now, output }
36854
+ });
36855
+ };
36035
36856
  const result = mutex ? await mutex.run(`files:${op.path}`, doFile) : await doFile();
36036
- setState(result.state);
36857
+ applyState(base2, result.state);
36037
36858
  }
36038
36859
  clear(op.target, op.path);
36039
36860
  resolved += 1;
@@ -36053,7 +36874,7 @@ async function drainUnsyncedOps(args) {
36053
36874
  message: cat.serverMessage,
36054
36875
  rejected_at: now().toISOString()
36055
36876
  });
36056
- setState(commitState(beforeReject, next2));
36877
+ applyState(beforeReject, commitState(beforeReject, next2));
36057
36878
  continue;
36058
36879
  }
36059
36880
  stillFailing += 1;
@@ -36066,7 +36887,7 @@ async function drainUnsyncedOps(args) {
36066
36887
  last_reason: cat.reason
36067
36888
  });
36068
36889
  if (changed)
36069
- setState(commitState(beforeRetry, next));
36890
+ applyState(beforeRetry, commitState(beforeRetry, next));
36070
36891
  }
36071
36892
  }
36072
36893
  return { attempted, resolved, stillFailing, rejected };
@@ -36240,10 +37061,10 @@ class ReaddirpStream extends Readable {
36240
37061
  }
36241
37062
  async _formatEntry(dirent, path5) {
36242
37063
  let entry2;
36243
- const basename5 = this._isDirent ? dirent.name : dirent;
37064
+ const basename6 = this._isDirent ? dirent.name : dirent;
36244
37065
  try {
36245
- const fullPath = presolve(pjoin(path5, basename5));
36246
- entry2 = { path: prelative(this._root, fullPath), fullPath, basename: basename5 };
37066
+ const fullPath = presolve(pjoin(path5, basename6));
37067
+ entry2 = { path: prelative(this._root, fullPath), fullPath, basename: basename6 };
36247
37068
  entry2[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
36248
37069
  } catch (err) {
36249
37070
  this._onError(err);
@@ -36770,9 +37591,9 @@ class NodeFsHandler {
36770
37591
  _watchWithNodeFs(path5, listener) {
36771
37592
  const opts = this.fsw.options;
36772
37593
  const directory = sp.dirname(path5);
36773
- const basename6 = sp.basename(path5);
37594
+ const basename7 = sp.basename(path5);
36774
37595
  const parent = this.fsw._getWatchedDir(directory);
36775
- parent.add(basename6);
37596
+ parent.add(basename7);
36776
37597
  const absolutePath = sp.resolve(path5);
36777
37598
  const options2 = {
36778
37599
  persistent: opts.persistent
@@ -36782,7 +37603,7 @@ class NodeFsHandler {
36782
37603
  let closer;
36783
37604
  if (opts.usePolling) {
36784
37605
  const enableBin = opts.interval !== opts.binaryInterval;
36785
- options2.interval = enableBin && isBinaryPath(basename6) ? opts.binaryInterval : opts.interval;
37606
+ options2.interval = enableBin && isBinaryPath(basename7) ? opts.binaryInterval : opts.interval;
36786
37607
  closer = setFsWatchFileListener(path5, absolutePath, options2, {
36787
37608
  listener,
36788
37609
  rawEmitter: this.fsw._emitRaw
@@ -36800,11 +37621,11 @@ class NodeFsHandler {
36800
37621
  if (this.fsw.closed) {
36801
37622
  return;
36802
37623
  }
36803
- const dirname10 = sp.dirname(file2);
36804
- const basename6 = sp.basename(file2);
36805
- const parent = this.fsw._getWatchedDir(dirname10);
37624
+ const dirname11 = sp.dirname(file2);
37625
+ const basename7 = sp.basename(file2);
37626
+ const parent = this.fsw._getWatchedDir(dirname11);
36806
37627
  let prevStats = stats;
36807
- if (parent.has(basename6))
37628
+ if (parent.has(basename7))
36808
37629
  return;
36809
37630
  const listener = async (path5, newStats) => {
36810
37631
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
@@ -36829,9 +37650,9 @@ class NodeFsHandler {
36829
37650
  prevStats = newStats2;
36830
37651
  }
36831
37652
  } catch (error52) {
36832
- this.fsw._remove(dirname10, basename6);
37653
+ this.fsw._remove(dirname11, basename7);
36833
37654
  }
36834
- } else if (parent.has(basename6)) {
37655
+ } else if (parent.has(basename7)) {
36835
37656
  const at = newStats.atimeMs;
36836
37657
  const mt = newStats.mtimeMs;
36837
37658
  if (!at || at <= mt || mt !== prevStats.mtimeMs) {
@@ -36918,7 +37739,7 @@ class NodeFsHandler {
36918
37739
  this._addToNodeFs(path5, initialAdd, wh, depth + 1);
36919
37740
  }
36920
37741
  }).on(EV.ERROR, this._boundHandleError);
36921
- return new Promise((resolve4, reject) => {
37742
+ return new Promise((resolve5, reject) => {
36922
37743
  if (!stream)
36923
37744
  return reject();
36924
37745
  stream.once(STR_END, () => {
@@ -36927,7 +37748,7 @@ class NodeFsHandler {
36927
37748
  return;
36928
37749
  }
36929
37750
  const wasThrottled = throttler ? throttler.clear() : false;
36930
- resolve4(undefined);
37751
+ resolve5(undefined);
36931
37752
  previous.getChildren().filter((item) => {
36932
37753
  return item !== directory && !current.has(item);
36933
37754
  }).forEach((item) => {
@@ -37686,7 +38507,7 @@ var chokidar_default = { watch, FSWatcher };
37686
38507
 
37687
38508
  // src/lib/watcher.ts
37688
38509
  import { statSync as statSync9 } from "node:fs";
37689
- import { sep as sep6 } from "node:path";
38510
+ import { sep as sep7 } from "node:path";
37690
38511
 
37691
38512
  // src/lib/rename-classifier.ts
37692
38513
  class RenameClassifier {
@@ -37817,7 +38638,7 @@ function watcherIgnoreMatcher(workspaceRoot) {
37817
38638
  return (absolutePath) => patterns.some((re) => re.test(absolutePath));
37818
38639
  }
37819
38640
  function escSep() {
37820
- return sep6 === "/" ? "/" : "\\\\";
38641
+ return sep7 === "/" ? "/" : "\\\\";
37821
38642
  }
37822
38643
 
37823
38644
  class DebounceMap {
@@ -38345,7 +39166,9 @@ async function pushArtistMemory(args) {
38345
39166
  }
38346
39167
  const localHash = stableHash(local);
38347
39168
  const runPatch = async () => {
38348
- let base2 = args.mutex ? loadState(workspaceSlug) : state;
39169
+ const snapshotEntry = getEntryBySlug(state, ENTITY_TYPE, slug);
39170
+ const fresher = args.mutex && snapshotEntry ? committedEntryIfNewer(workspaceSlug, ENTITY_TYPE, snapshotEntry) : undefined;
39171
+ let base2 = fresher ? upsertEntry(state, ENTITY_TYPE, fresher).state : state;
38349
39172
  const entry2 = getEntryBySlug(base2, ENTITY_TYPE, slug);
38350
39173
  if (!entry2)
38351
39174
  return { state: base2, outcome: { kind: "ignored", slug } };
@@ -41474,7 +42297,7 @@ class Semaphore {
41474
42297
  this.active += 1;
41475
42298
  return;
41476
42299
  }
41477
- await new Promise((resolve5) => this.waiters.push(resolve5));
42300
+ await new Promise((resolve6) => this.waiters.push(resolve6));
41478
42301
  }
41479
42302
  release() {
41480
42303
  const next = this.waiters.shift();
@@ -41541,11 +42364,11 @@ import {
41541
42364
  statSync as statSync16,
41542
42365
  unlinkSync as unlinkSync8
41543
42366
  } from "node:fs";
41544
- import { join as join16 } from "node:path";
42367
+ import { join as join17 } from "node:path";
41545
42368
 
41546
42369
  // src/lib/conflicts-view.ts
41547
42370
  import { existsSync as existsSync6 } from "node:fs";
41548
- import { join as join15 } from "node:path";
42371
+ import { join as join16 } from "node:path";
41549
42372
  var NO_GENERATED_MEMORY = {
41550
42373
  artistMemoryGenerated: () => false,
41551
42374
  workspaceMemoryGenerated: () => false,
@@ -41591,7 +42414,7 @@ function resolveConflictRows(workspaceSlug, stashes, generatedMemory = NO_GENERA
41591
42414
  if (validateFilesRelPath(rel) === null) {
41592
42415
  return { kind: "unsafe-path", stash };
41593
42416
  }
41594
- const abs = join15(root, "files", rel);
42417
+ const abs = join16(root, "files", rel);
41595
42418
  if (hasSymlinkedComponent(workspaceSlug, abs)) {
41596
42419
  return { kind: "unsafe-path", stash };
41597
42420
  }
@@ -41724,7 +42547,7 @@ function refreshConflictsView(workspaceSlug) {
41724
42547
  import { existsSync as existsSync7, readFileSync as readFileSync23, statSync as statSync14 } from "node:fs";
41725
42548
 
41726
42549
  // src/lib/files/extracted-text.ts
41727
- import { createHash as createHash3 } from "node:crypto";
42550
+ import { createHash as createHash4 } from "node:crypto";
41728
42551
  var DERIVED_TEXT_VERSION = 2;
41729
42552
  function yamlString3(value) {
41730
42553
  return JSON.stringify(value);
@@ -41798,7 +42621,7 @@ ${doc2.text}
41798
42621
  `;
41799
42622
  }
41800
42623
  function extractedTextHash(rendered) {
41801
- return createHash3("sha256").update(rendered, "utf8").digest("hex");
42624
+ return createHash4("sha256").update(rendered, "utf8").digest("hex");
41802
42625
  }
41803
42626
 
41804
42627
  // src/lib/files/pull.ts
@@ -42417,7 +43240,7 @@ function hasExistingContent(workspacePath) {
42417
43240
  if (!e.isDirectory())
42418
43241
  return true;
42419
43242
  try {
42420
- return readdirSync7(join16(workspacePath, e.name)).length > 0;
43243
+ return readdirSync7(join17(workspacePath, e.name)).length > 0;
42421
43244
  } catch {
42422
43245
  return true;
42423
43246
  }
@@ -43221,7 +44044,7 @@ function makeWatchHandler(deps) {
43221
44044
  spinner,
43222
44045
  mutex,
43223
44046
  getState,
43224
- setState,
44047
+ applyState,
43225
44048
  fetchImpl,
43226
44049
  now,
43227
44050
  output,
@@ -43231,6 +44054,10 @@ function makeWatchHandler(deps) {
43231
44054
  fileGate,
43232
44055
  isFileFrozen
43233
44056
  } = deps;
44057
+ const applyFromCurrent = (update) => {
44058
+ const base2 = getState();
44059
+ applyState(base2, update(base2));
44060
+ };
43234
44061
  const handleFilesEvent = async (relPath, absolutePath, exists) => {
43235
44062
  try {
43236
44063
  if (isFileFrozen?.(relPath))
@@ -43240,8 +44067,8 @@ function makeWatchHandler(deps) {
43240
44067
  } catch (err) {
43241
44068
  if (!(err instanceof MirrorSymlinkError))
43242
44069
  throw err;
43243
- setState(recordFileSymlinkRefused({
43244
- state: getState(),
44070
+ applyFromCurrent((base2) => recordFileSymlinkRefused({
44071
+ state: base2,
43245
44072
  relPath,
43246
44073
  op: exists ? "upsert" : "delete",
43247
44074
  now: now ?? (() => new Date)
@@ -43267,15 +44094,16 @@ function makeWatchHandler(deps) {
43267
44094
  }
43268
44095
  }
43269
44096
  await mutex.run(`files:${relPath}`, async () => {
44097
+ const base2 = getState();
43270
44098
  const result = await pushFilesDelete({
43271
44099
  workspaceSlug,
43272
44100
  baseUrl,
43273
44101
  pat,
43274
44102
  relPath,
43275
- state: getState(),
44103
+ state: base2,
43276
44104
  deps: { fetchImpl, now, output, suppressor }
43277
44105
  });
43278
- setState(clearReportedSafeFileRejected(result.state, relPath));
44106
+ applyState(base2, clearReportedSafeFileRejected(result.state, relPath));
43279
44107
  reportFileOutcome(spinner, workspaceSlug, getState(), result.outcome);
43280
44108
  });
43281
44109
  return;
@@ -43300,8 +44128,8 @@ function makeWatchHandler(deps) {
43300
44128
  max: MAX_WORKSPACE_FILE_BYTES,
43301
44129
  source: "client"
43302
44130
  }));
43303
- setState(recordFileOverCap({
43304
- state: getState(),
44131
+ applyFromCurrent((base2) => recordFileOverCap({
44132
+ state: base2,
43305
44133
  relPath,
43306
44134
  size: st.size,
43307
44135
  max: MAX_WORKSPACE_FILE_BYTES,
@@ -43329,17 +44157,18 @@ function makeWatchHandler(deps) {
43329
44157
  }
43330
44158
  }
43331
44159
  await mutex.run(`files:${relPath}`, async () => {
44160
+ const base2 = getState();
43332
44161
  const result = await pushFilesUpsert({
43333
44162
  workspaceSlug,
43334
44163
  baseUrl,
43335
44164
  pat,
43336
44165
  absolutePath,
43337
44166
  relPath,
43338
- state: getState(),
44167
+ state: base2,
43339
44168
  prepared: { bytes, hash: hash2, size: st.size, inode: st.ino },
43340
44169
  deps: { fetchImpl, now, output, suppressor }
43341
44170
  });
43342
- setState(result.outcome.kind === "over_cap" ? result.state : clearFileRejected(result.state, relPath));
44171
+ applyState(base2, result.outcome.kind === "over_cap" ? result.state : clearFileRejected(result.state, relPath));
43343
44172
  reportFileOutcome(spinner, workspaceSlug, getState(), result.outcome);
43344
44173
  });
43345
44174
  } catch (err) {
@@ -43347,16 +44176,16 @@ function makeWatchHandler(deps) {
43347
44176
  output?.log(fileFailedLine({ path: relPath, ...categorizeError(err) }));
43348
44177
  spinner.warn(`File push failed for files/${relPath}: ${msg}`);
43349
44178
  if (isRecordableFailure(err)) {
43350
- setState(recordFileUnsynced({
43351
- state: getState(),
44179
+ applyFromCurrent((base2) => recordFileUnsynced({
44180
+ state: base2,
43352
44181
  relPath,
43353
44182
  op: exists ? "upsert" : "delete",
43354
44183
  err,
43355
44184
  now: now ?? (() => new Date)
43356
44185
  }));
43357
44186
  } else if (isPermanentReject(err)) {
43358
- setState(recordFileRejected({
43359
- state: getState(),
44187
+ applyFromCurrent((base2) => recordFileRejected({
44188
+ state: base2,
43360
44189
  relPath,
43361
44190
  op: exists ? "upsert" : "delete",
43362
44191
  err,
@@ -43384,17 +44213,18 @@ function makeWatchHandler(deps) {
43384
44213
  }
43385
44214
  try {
43386
44215
  await mutex.run(WORKSPACE_RULES_MUTEX_KEY, async () => {
44216
+ const base2 = getState();
43387
44217
  const result = await pushWorkspaceRules({
43388
44218
  workspaceSlug,
43389
44219
  baseUrl,
43390
44220
  pat,
43391
- state: getState(),
44221
+ state: base2,
43392
44222
  fetchImpl,
43393
44223
  now,
43394
44224
  output,
43395
44225
  suppressor
43396
44226
  });
43397
- setState(result.state);
44227
+ applyState(base2, result.state);
43398
44228
  reportWorkspaceRulesOutcome(spinner, workspaceSlug, result.state, result.outcome);
43399
44229
  });
43400
44230
  } catch (err) {
@@ -43422,17 +44252,18 @@ function makeWatchHandler(deps) {
43422
44252
  }
43423
44253
  try {
43424
44254
  await mutex.run(WORKSPACE_MEMORY_MUTEX_KEY, async () => {
44255
+ const base2 = getState();
43425
44256
  const result = await pushWorkspaceMemory({
43426
44257
  workspaceSlug,
43427
44258
  baseUrl,
43428
44259
  pat,
43429
- state: getState(),
44260
+ state: base2,
43430
44261
  fetchImpl,
43431
44262
  now,
43432
44263
  output,
43433
44264
  suppressor
43434
44265
  });
43435
- setState(result.state);
44266
+ applyState(base2, result.state);
43436
44267
  reportWorkspaceMemoryOutcome(spinner, workspaceSlug, result.state, result.outcome);
43437
44268
  });
43438
44269
  } catch (err) {
@@ -43460,17 +44291,18 @@ function makeWatchHandler(deps) {
43460
44291
  }
43461
44292
  try {
43462
44293
  await mutex.run(USER_MEMORY_MUTEX_KEY, async () => {
44294
+ const base2 = getState();
43463
44295
  const result = await pushUserMemory({
43464
44296
  workspaceSlug,
43465
44297
  baseUrl,
43466
44298
  pat,
43467
- state: getState(),
44299
+ state: base2,
43468
44300
  fetchImpl,
43469
44301
  now,
43470
44302
  output,
43471
44303
  suppressor
43472
44304
  });
43473
- setState(result.state);
44305
+ applyState(base2, result.state);
43474
44306
  reportUserMemoryOutcome(spinner, workspaceSlug, result.state, result.outcome);
43475
44307
  });
43476
44308
  } catch (err) {
@@ -43498,17 +44330,18 @@ function makeWatchHandler(deps) {
43498
44330
  }
43499
44331
  try {
43500
44332
  await mutex.run(VOICE_MUTEX_KEY, async () => {
44333
+ const base2 = getState();
43501
44334
  const result = await pushVoice({
43502
44335
  workspaceSlug,
43503
44336
  baseUrl,
43504
44337
  pat,
43505
- state: getState(),
44338
+ state: base2,
43506
44339
  fetchImpl,
43507
44340
  now,
43508
44341
  output,
43509
44342
  suppressor
43510
44343
  });
43511
- setState(result.state);
44344
+ applyState(base2, result.state);
43512
44345
  reportVoiceOutcome(spinner, workspaceSlug, result.state, result.outcome);
43513
44346
  });
43514
44347
  } catch (err) {
@@ -43535,19 +44368,20 @@ function makeWatchHandler(deps) {
43535
44368
  }
43536
44369
  }
43537
44370
  try {
44371
+ const base2 = getState();
43538
44372
  const result = await pushArtistMemory({
43539
44373
  workspaceSlug,
43540
44374
  baseUrl,
43541
44375
  pat,
43542
44376
  slug,
43543
- state: getState(),
44377
+ state: base2,
43544
44378
  fetchImpl,
43545
44379
  now,
43546
44380
  output,
43547
44381
  suppressor,
43548
44382
  mutex
43549
44383
  });
43550
- setState(result.state);
44384
+ applyState(base2, result.state);
43551
44385
  reportArtistMemoryOutcome(spinner, workspaceSlug, result.state, result.outcome);
43552
44386
  } catch (err) {
43553
44387
  const msg = err instanceof Error ? err.message : "unknown push error";
@@ -43580,6 +44414,7 @@ function makeWatchHandler(deps) {
43580
44414
  await handle({ kind: "upsert", absolutePath: event.toPath });
43581
44415
  return;
43582
44416
  }
44417
+ const base3 = getState();
43583
44418
  const result2 = await pushRename({
43584
44419
  workspaceSlug,
43585
44420
  baseUrl,
@@ -43590,7 +44425,7 @@ function makeWatchHandler(deps) {
43590
44425
  id: event.id,
43591
44426
  expectedUpdatedAt: event.expectedUpdatedAt,
43592
44427
  fromSlug: event.fromSlug,
43593
- state: getState(),
44428
+ state: base3,
43594
44429
  deps: {
43595
44430
  fetchImpl,
43596
44431
  now,
@@ -43599,7 +44434,7 @@ function makeWatchHandler(deps) {
43599
44434
  echo: suppressor ? { watcher: "live", suppressor } : undefined
43600
44435
  }
43601
44436
  });
43602
- setState(result2.state);
44437
+ applyState(base3, result2.state);
43603
44438
  reportOutcome(spinner, workspaceSlug, result2.state, result2.outcome);
43604
44439
  return;
43605
44440
  }
@@ -43658,8 +44493,8 @@ function makeWatchHandler(deps) {
43658
44493
  if (!classified) {
43659
44494
  const key = entitySymlinkRefusalKey({ workspaceSlug, absolutePath });
43660
44495
  if (key) {
43661
- setState(recordEntitySymlinkRefused({
43662
- state: getState(),
44496
+ applyFromCurrent((base3) => recordEntitySymlinkRefused({
44497
+ state: base3,
43663
44498
  mirrorRelativePath: key,
43664
44499
  op: event.kind === "unlink" ? "delete" : "upsert",
43665
44500
  now: now ?? (() => new Date)
@@ -43716,13 +44551,14 @@ function makeWatchHandler(deps) {
43716
44551
  return;
43717
44552
  }
43718
44553
  }
44554
+ const base2 = getState();
43719
44555
  const result = await pushFile({
43720
44556
  workspaceSlug,
43721
44557
  baseUrl,
43722
44558
  pat,
43723
44559
  absolutePath,
43724
44560
  entityType: classified.entityType,
43725
- state: getState(),
44561
+ state: base2,
43726
44562
  exists: event.kind === "upsert",
43727
44563
  unlinkContext: event.kind === "unlink" && event.stateEntry ? {
43728
44564
  id: event.stateEntry.id,
@@ -43738,7 +44574,7 @@ function makeWatchHandler(deps) {
43738
44574
  echo: suppressor ? { watcher: "live", suppressor } : undefined
43739
44575
  }
43740
44576
  });
43741
- setState(clearEntityRejected(result.state, workspaceSlug, absolutePath));
44577
+ applyState(result.base ?? base2, clearEntityRejected(result.state, workspaceSlug, absolutePath));
43742
44578
  reportOutcome(spinner, workspaceSlug, getState(), result.outcome);
43743
44579
  } catch (err) {
43744
44580
  const msg = err instanceof Error ? err.message : "unknown push error";
@@ -43754,8 +44590,8 @@ function makeWatchHandler(deps) {
43754
44590
  }));
43755
44591
  }
43756
44592
  if (classified && event.kind !== "renamed" && isRecordableFailure(err)) {
43757
- setState(recordEntityUnsynced({
43758
- state: getState(),
44593
+ applyFromCurrent((base2) => recordEntityUnsynced({
44594
+ state: base2,
43759
44595
  workspaceSlug,
43760
44596
  absolutePath: path5,
43761
44597
  op: event.kind === "unlink" ? "delete" : "upsert",
@@ -43763,8 +44599,8 @@ function makeWatchHandler(deps) {
43763
44599
  now: now ?? (() => new Date)
43764
44600
  }));
43765
44601
  } else if (classified && event.kind !== "renamed" && isPermanentReject(err)) {
43766
- setState(recordEntityRejected({
43767
- state: getState(),
44602
+ applyFromCurrent((base2) => recordEntityRejected({
44603
+ state: base2,
43768
44604
  workspaceSlug,
43769
44605
  absolutePath: path5,
43770
44606
  op: event.kind === "unlink" ? "delete" : "upsert",
@@ -43783,6 +44619,7 @@ function discardSink() {
43783
44619
  }
43784
44620
  async function flushHeldEntityOp(deps) {
43785
44621
  const now = deps.now ?? (() => new Date);
44622
+ const base2 = deps.getState();
43786
44623
  try {
43787
44624
  const result = await pushFile({
43788
44625
  workspaceSlug: deps.workspaceSlug,
@@ -43790,7 +44627,7 @@ async function flushHeldEntityOp(deps) {
43790
44627
  pat: deps.pat,
43791
44628
  absolutePath: deps.op.absolutePath,
43792
44629
  entityType: deps.op.entityType,
43793
- state: deps.getState(),
44630
+ state: base2,
43794
44631
  exists: deps.op.kind === "overwrite",
43795
44632
  unlinkContext: deps.op.kind === "delete" ? { id: deps.op.id, slug: deps.op.slug, updated_at: deps.op.updatedAt } : null,
43796
44633
  deps: {
@@ -43801,7 +44638,10 @@ async function flushHeldEntityOp(deps) {
43801
44638
  echo: deps.echo
43802
44639
  }
43803
44640
  });
43804
- deps.setState(result.state);
44641
+ deps.applyState(result.base ?? base2, result.state);
44642
+ if (result.outcome.kind === "ignored" && result.outcome.reason === DELETE_DECLINED_PATH_EXISTS) {
44643
+ deps.spinner.warn(deleteDeclinedSentence(deps.op.absolutePath));
44644
+ }
43805
44645
  reportOutcome(deps.spinner, deps.workspaceSlug, deps.getState(), result.outcome);
43806
44646
  } catch (err) {
43807
44647
  const msg = err instanceof Error ? err.message : "unknown push error";
@@ -43813,8 +44653,8 @@ async function flushHeldEntityOp(deps) {
43813
44653
  }));
43814
44654
  deps.spinner.warn(`Push failed for ${deps.op.entityType}/${deps.op.slug}: ${msg}`);
43815
44655
  if (isRecordableFailure(err)) {
43816
- deps.setState(recordEntityUnsynced({
43817
- state: deps.getState(),
44656
+ deps.applyState(base2, recordEntityUnsynced({
44657
+ state: base2,
43818
44658
  workspaceSlug: deps.workspaceSlug,
43819
44659
  absolutePath: deps.op.absolutePath,
43820
44660
  op: deps.op.kind === "delete" ? "delete" : "upsert",
@@ -43832,14 +44672,16 @@ async function flushHeldFileOpImpl(deps) {
43832
44672
  output: deps.output,
43833
44673
  suppressor: deps.suppressor
43834
44674
  };
44675
+ let base2;
43835
44676
  const run = async () => {
44677
+ base2 = deps.getState();
43836
44678
  try {
43837
44679
  const result = deps.op.kind === "delete" ? await pushFilesDelete({
43838
44680
  workspaceSlug: deps.workspaceSlug,
43839
44681
  baseUrl: deps.baseUrl,
43840
44682
  pat: deps.pat,
43841
44683
  relPath: deps.op.relPath,
43842
- state: deps.getState(),
44684
+ state: base2,
43843
44685
  deps: fileDeps
43844
44686
  }) : await pushFilesUpsert({
43845
44687
  workspaceSlug: deps.workspaceSlug,
@@ -43847,18 +44689,18 @@ async function flushHeldFileOpImpl(deps) {
43847
44689
  pat: deps.pat,
43848
44690
  absolutePath: deps.op.absolutePath,
43849
44691
  relPath: deps.op.relPath,
43850
- state: deps.getState(),
44692
+ state: base2,
43851
44693
  deps: fileDeps
43852
44694
  });
43853
- deps.setState(result.state);
44695
+ deps.applyState(base2, result.state);
43854
44696
  reportFileOutcome(deps.spinner, deps.workspaceSlug, deps.getState(), result.outcome);
43855
44697
  } catch (err) {
43856
44698
  const msg = err instanceof Error ? err.message : "unknown push error";
43857
44699
  deps.output?.log(fileFailedLine({ path: deps.op.relPath, ...categorizeError(err) }));
43858
44700
  deps.spinner.warn(`File push failed for files/${deps.op.relPath}: ${msg}`);
43859
44701
  if (isRecordableFailure(err)) {
43860
- deps.setState(recordFileUnsynced({
43861
- state: deps.getState(),
44702
+ deps.applyState(base2, recordFileUnsynced({
44703
+ state: base2,
43862
44704
  relPath: deps.op.relPath,
43863
44705
  op: deps.op.kind === "delete" ? "delete" : "upsert",
43864
44706
  err,
@@ -44153,8 +44995,8 @@ async function runStart(workspaceSlug, deps = {}) {
44153
44995
  baseUrl: entry2.api_base_url,
44154
44996
  pat,
44155
44997
  getState: () => state,
44156
- setState: (s) => {
44157
- state = s;
44998
+ applyState: (base2, next) => {
44999
+ state = rebaseState(state, base2, next);
44158
45000
  },
44159
45001
  fetchImpl,
44160
45002
  now: deps.now,
@@ -44171,8 +45013,8 @@ async function runStart(workspaceSlug, deps = {}) {
44171
45013
  baseUrl: entry2.api_base_url,
44172
45014
  pat,
44173
45015
  getState: () => state,
44174
- setState: (s) => {
44175
- state = s;
45016
+ applyState: (base2, next) => {
45017
+ state = rebaseState(state, base2, next);
44176
45018
  },
44177
45019
  fetchImpl,
44178
45020
  now: deps.now,
@@ -44210,8 +45052,8 @@ async function runStart(workspaceSlug, deps = {}) {
44210
45052
  pat,
44211
45053
  op,
44212
45054
  getState: () => state,
44213
- setState: (s) => {
44214
- state = s;
45055
+ applyState: (base2, next) => {
45056
+ state = rebaseState(state, base2, next);
44215
45057
  },
44216
45058
  mutex,
44217
45059
  fetchImpl,
@@ -44274,8 +45116,8 @@ async function runStart(workspaceSlug, deps = {}) {
44274
45116
  pat,
44275
45117
  op,
44276
45118
  getState: () => state,
44277
- setState: (s) => {
44278
- state = s;
45119
+ applyState: (base2, next) => {
45120
+ state = rebaseState(state, base2, next);
44279
45121
  },
44280
45122
  mutex,
44281
45123
  fetchImpl,
@@ -44331,8 +45173,8 @@ async function runStart(workspaceSlug, deps = {}) {
44331
45173
  spinner,
44332
45174
  mutex,
44333
45175
  getState: () => state,
44334
- setState: (s) => {
44335
- state = s;
45176
+ applyState: (base2, next) => {
45177
+ state = rebaseState(state, base2, next);
44336
45178
  },
44337
45179
  fetchImpl,
44338
45180
  now: deps.now,
@@ -44397,8 +45239,8 @@ async function runStart(workspaceSlug, deps = {}) {
44397
45239
  baseUrl: entry2.api_base_url,
44398
45240
  pat,
44399
45241
  getState: () => state,
44400
- setState: (s) => {
44401
- state = s;
45242
+ applyState: (base2, next) => {
45243
+ state = rebaseState(state, base2, next);
44402
45244
  },
44403
45245
  fetchImpl,
44404
45246
  now: deps.now,
@@ -44415,8 +45257,8 @@ async function runStart(workspaceSlug, deps = {}) {
44415
45257
  baseUrl: entry2.api_base_url,
44416
45258
  pat,
44417
45259
  getState: () => state,
44418
- setState: (s) => {
44419
- state = s;
45260
+ applyState: (base2, next) => {
45261
+ state = rebaseState(state, base2, next);
44420
45262
  },
44421
45263
  fetchImpl,
44422
45264
  now: deps.now,
@@ -44431,58 +45273,70 @@ async function runStart(workspaceSlug, deps = {}) {
44431
45273
  spinner.warn(`${redriven.rejected} write${redriven.rejected === 1 ? "" : "s"} permanently rejected — see \`plinth status\``);
44432
45274
  spinner.update(`Watching ${slug} · ${watchingSummary(state)}`);
44433
45275
  }
44434
- const rulesRecon = await mutex.run(WORKSPACE_RULES_MUTEX_KEY, () => reconcileWorkspaceRules({
44435
- workspaceSlug: slug,
44436
- baseUrl: entry2.api_base_url,
44437
- pat,
44438
- state,
44439
- fetchImpl,
44440
- now: deps.now,
44441
- output: out,
44442
- suppressor
44443
- }));
44444
- if (rulesRecon.state !== state)
44445
- state = rulesRecon.state;
45276
+ let rulesBase = state;
45277
+ const rulesRecon = await mutex.run(WORKSPACE_RULES_MUTEX_KEY, () => {
45278
+ rulesBase = state;
45279
+ return reconcileWorkspaceRules({
45280
+ workspaceSlug: slug,
45281
+ baseUrl: entry2.api_base_url,
45282
+ pat,
45283
+ state: rulesBase,
45284
+ fetchImpl,
45285
+ now: deps.now,
45286
+ output: out,
45287
+ suppressor
45288
+ });
45289
+ });
45290
+ state = rebaseState(state, rulesBase, rulesRecon.state);
44446
45291
  reportSingletonReconcile(spinner, slug, state, WORKSPACE_RULES_FILENAME, rulesRecon.outcome);
44447
- const memoryRecon = await mutex.run(WORKSPACE_MEMORY_MUTEX_KEY, () => reconcileWorkspaceMemory({
44448
- workspaceSlug: slug,
44449
- baseUrl: entry2.api_base_url,
44450
- pat,
44451
- state,
44452
- fetchImpl,
44453
- now: deps.now,
44454
- output: out,
44455
- suppressor
44456
- }));
44457
- if (memoryRecon.state !== state)
44458
- state = memoryRecon.state;
45292
+ let memoryBase = state;
45293
+ const memoryRecon = await mutex.run(WORKSPACE_MEMORY_MUTEX_KEY, () => {
45294
+ memoryBase = state;
45295
+ return reconcileWorkspaceMemory({
45296
+ workspaceSlug: slug,
45297
+ baseUrl: entry2.api_base_url,
45298
+ pat,
45299
+ state: memoryBase,
45300
+ fetchImpl,
45301
+ now: deps.now,
45302
+ output: out,
45303
+ suppressor
45304
+ });
45305
+ });
45306
+ state = rebaseState(state, memoryBase, memoryRecon.state);
44459
45307
  reportSingletonReconcile(spinner, slug, state, WORKSPACE_MEMORY_FILENAME, memoryRecon.outcome);
44460
- const userMemoryRecon = await mutex.run(USER_MEMORY_MUTEX_KEY, () => reconcileUserMemory({
44461
- workspaceSlug: slug,
44462
- baseUrl: entry2.api_base_url,
44463
- pat,
44464
- state,
44465
- fetchImpl,
44466
- now: deps.now,
44467
- output: out,
44468
- suppressor
44469
- }));
44470
- if (userMemoryRecon.state !== state)
44471
- state = userMemoryRecon.state;
44472
- reportSingletonReconcile(spinner, slug, state, USER_MEMORY_FILENAME, userMemoryRecon.outcome);
44473
- try {
44474
- const voiceRecon = await mutex.run(VOICE_MUTEX_KEY, () => reconcileVoice({
45308
+ let userMemoryBase = state;
45309
+ const userMemoryRecon = await mutex.run(USER_MEMORY_MUTEX_KEY, () => {
45310
+ userMemoryBase = state;
45311
+ return reconcileUserMemory({
44475
45312
  workspaceSlug: slug,
44476
45313
  baseUrl: entry2.api_base_url,
44477
45314
  pat,
44478
- state,
45315
+ state: userMemoryBase,
44479
45316
  fetchImpl,
44480
45317
  now: deps.now,
44481
45318
  output: out,
44482
45319
  suppressor
44483
- }));
44484
- if (voiceRecon.state !== state)
44485
- state = voiceRecon.state;
45320
+ });
45321
+ });
45322
+ state = rebaseState(state, userMemoryBase, userMemoryRecon.state);
45323
+ reportSingletonReconcile(spinner, slug, state, USER_MEMORY_FILENAME, userMemoryRecon.outcome);
45324
+ try {
45325
+ let voiceBase = state;
45326
+ const voiceRecon = await mutex.run(VOICE_MUTEX_KEY, () => {
45327
+ voiceBase = state;
45328
+ return reconcileVoice({
45329
+ workspaceSlug: slug,
45330
+ baseUrl: entry2.api_base_url,
45331
+ pat,
45332
+ state: voiceBase,
45333
+ fetchImpl,
45334
+ now: deps.now,
45335
+ output: out,
45336
+ suppressor
45337
+ });
45338
+ });
45339
+ state = rebaseState(state, voiceBase, voiceRecon.state);
44486
45340
  reportSingletonReconcile(spinner, slug, state, VOICE_FILENAME, voiceRecon.outcome);
44487
45341
  const reconWarning = voiceMalformedWarning(state, slug);
44488
45342
  if (reconWarning)
@@ -44490,19 +45344,19 @@ async function runStart(workspaceSlug, deps = {}) {
44490
45344
  } catch (err) {
44491
45345
  out.log(`[VOICE_RECONCILE_FAILED ${categorizeError(err).reason}]`);
44492
45346
  }
45347
+ const memBase = state;
44493
45348
  const memRecon = await reconcileArtistMemory({
44494
45349
  workspaceSlug: slug,
44495
45350
  baseUrl: entry2.api_base_url,
44496
45351
  pat,
44497
- state,
45352
+ state: memBase,
44498
45353
  fetchImpl,
44499
45354
  now: deps.now,
44500
45355
  output: out,
44501
45356
  suppressor,
44502
45357
  mutex
44503
45358
  });
44504
- if (memRecon.state !== state)
44505
- state = memRecon.state;
45359
+ state = rebaseState(state, memBase, memRecon.state);
44506
45360
  if (memRecon.pushed > 0) {
44507
45361
  spinner.success(`↑ synced ${memRecon.pushed} memory file${memRecon.pushed === 1 ? "" : "s"}`);
44508
45362
  spinner.update(`Watching ${slug} · ${watchingSummary(state)}`);
@@ -44596,12 +45450,12 @@ async function runStart(workspaceSlug, deps = {}) {
44596
45450
  try {
44597
45451
  await Promise.race([
44598
45452
  watcher.drainPending().then(() => Promise.all([gate.drain(), fileGate.drain()])),
44599
- new Promise((resolve5) => setTimeout(() => resolve5(-1), SHUTDOWN_DRAIN_TIMEOUT_MS))
45453
+ new Promise((resolve6) => setTimeout(() => resolve6(-1), SHUTDOWN_DRAIN_TIMEOUT_MS))
44600
45454
  ]);
44601
45455
  } finally {
44602
45456
  await Promise.race([
44603
45457
  watcher.stop(),
44604
- new Promise((resolve5) => setTimeout(resolve5, SHUTDOWN_DRAIN_TIMEOUT_MS))
45458
+ new Promise((resolve6) => setTimeout(resolve6, SHUTDOWN_DRAIN_TIMEOUT_MS))
44605
45459
  ]);
44606
45460
  clearDaemonPid(slug);
44607
45461
  releaseDaemonLock(lockHandle);
@@ -45157,11 +46011,11 @@ function assessContextWalls(workspaceSlug, deps = {}) {
45157
46011
  // src/lib/build-stamp.ts
45158
46012
  import { execFileSync as execFileSync4 } from "node:child_process";
45159
46013
  import { existsSync as existsSync10, mkdirSync as mkdirSync11, readFileSync as readFileSync27, writeFileSync as writeFileSync8 } from "node:fs";
45160
- import { dirname as dirname11, join as join17 } from "node:path";
46014
+ import { dirname as dirname12, join as join18 } from "node:path";
45161
46015
  import { fileURLToPath } from "node:url";
45162
46016
  var BUILD_STAMP_FILENAME = "build-stamp.json";
45163
46017
  function stampPath(distDir) {
45164
- return join17(distDir, BUILD_STAMP_FILENAME);
46018
+ return join18(distDir, BUILD_STAMP_FILENAME);
45165
46019
  }
45166
46020
  function readHead(repoDir) {
45167
46021
  try {
@@ -45192,9 +46046,9 @@ function readBuildStamp(distDir) {
45192
46046
  function findRepoRoot(fromDir) {
45193
46047
  let dir = fromDir;
45194
46048
  for (;; ) {
45195
- if (existsSync10(join17(dir, ".git")))
46049
+ if (existsSync10(join18(dir, ".git")))
45196
46050
  return dir;
45197
- const parent = dirname11(dir);
46051
+ const parent = dirname12(dir);
45198
46052
  if (parent === dir)
45199
46053
  return null;
45200
46054
  dir = parent;
@@ -45218,7 +46072,7 @@ function checkBuildStaleness(deps = {}) {
45218
46072
  const metaUrl = deps.metaUrl ?? import.meta.url;
45219
46073
  let distDir;
45220
46074
  try {
45221
- distDir = dirname11(fileURLToPath(metaUrl));
46075
+ distDir = dirname12(fileURLToPath(metaUrl));
45222
46076
  } catch {
45223
46077
  return { kind: "unknown" };
45224
46078
  }
@@ -45242,7 +46096,7 @@ function checkBuildStaleness(deps = {}) {
45242
46096
 
45243
46097
  // src/lib/memory-links.ts
45244
46098
  import { readFileSync as readFileSync28 } from "node:fs";
45245
- import { relative as relative15, sep as sep7 } from "node:path";
46099
+ import { relative as relative15, sep as sep8 } from "node:path";
45246
46100
  var MEMORY_FILE_RE = /^(workspace-memory\.md|user-memory\.md|artists\/[^/]+\/memory\.md|memory\/[^/]+\.md|memory\/private\/[^/]+\.md)$/i;
45247
46101
  function scanMemoryLinks(deps) {
45248
46102
  const listFiles = deps.listFiles ?? ((r) => walkSubtreeFiles(r, isVcsInternal));
@@ -45255,7 +46109,7 @@ function scanMemoryLinks(deps) {
45255
46109
  } catch {
45256
46110
  return { scanned: 0, unreadable: [], dead: [] };
45257
46111
  }
45258
- const relPaths = absPaths.map((p) => relative15(root, p).split(sep7).join("/"));
46112
+ const relPaths = absPaths.map((p) => relative15(root, p).split(sep8).join("/"));
45259
46113
  const artists = buildArtistIndex(relPaths, root, (abs) => readFile(abs));
45260
46114
  const dead = [];
45261
46115
  const unreadable = [];
@@ -46321,7 +47175,7 @@ async function callVoiceGate(req) {
46321
47175
  }
46322
47176
 
46323
47177
  // src/lib/voice-gate/attempts.ts
46324
- import { createHash as createHash4 } from "node:crypto";
47178
+ import { createHash as createHash5 } from "node:crypto";
46325
47179
  import {
46326
47180
  mkdirSync as mkdirSync12,
46327
47181
  readFileSync as readFileSync30,
@@ -46329,7 +47183,7 @@ import {
46329
47183
  unlinkSync as unlinkSync9,
46330
47184
  writeFileSync as writeFileSync9
46331
47185
  } from "node:fs";
46332
- import { join as join18 } from "node:path";
47186
+ import { join as join19 } from "node:path";
46333
47187
  var MAX_REGENS = 2;
46334
47188
  var ENTRY_TTL_MS = 24 * 60 * 60 * 1000;
46335
47189
  var AttemptEntrySchema = exports_external.object({
@@ -46342,13 +47196,13 @@ var AttemptsFileSchema = exports_external.object({
46342
47196
  entries: exports_external.record(exports_external.string(), AttemptEntrySchema)
46343
47197
  });
46344
47198
  function attemptsDir(workspaceSlug) {
46345
- return join18(plinthHome(), "_voice_gate", workspaceSlug);
47199
+ return join19(plinthHome(), "_voice_gate", workspaceSlug);
46346
47200
  }
46347
47201
  function attemptsPath(workspaceSlug) {
46348
- return join18(attemptsDir(workspaceSlug), "attempts.json");
47202
+ return join19(attemptsDir(workspaceSlug), "attempts.json");
46349
47203
  }
46350
47204
  function attemptKey(identity) {
46351
- return createHash4("sha256").update(identity, "utf8").digest("hex").slice(0, 32);
47205
+ return createHash5("sha256").update(identity, "utf8").digest("hex").slice(0, 32);
46352
47206
  }
46353
47207
  function emptyFile() {
46354
47208
  return { version: 1, entries: {} };
@@ -46520,7 +47374,7 @@ function denyUngated(detail) {
46520
47374
  // src/lib/voice-gate/payload.ts
46521
47375
  import { readFileSync as readFileSync31, statSync as statSync20 } from "node:fs";
46522
47376
  import { homedir as homedir2 } from "node:os";
46523
- import { isAbsolute as isAbsolute4, resolve as resolve5 } from "node:path";
47377
+ import { isAbsolute as isAbsolute4, resolve as resolve6 } from "node:path";
46524
47378
  var MAX_BODY_BYTES = 256 * 1024;
46525
47379
  var HELPER_BASENAME = "push_gmail_draft.py";
46526
47380
  var DRAFT_FLAGS = ["--to", "--body-file", "--body-stdin"];
@@ -46714,13 +47568,13 @@ function applyCd(tokens, state) {
46714
47568
  return { dir: expanded, known: true };
46715
47569
  if (!state.known)
46716
47570
  return state;
46717
- return { dir: resolve5(state.dir, expanded), known: true };
47571
+ return { dir: resolve6(state.dir, expanded), known: true };
46718
47572
  }
46719
47573
  function expandHome(path5) {
46720
47574
  if (path5 === "~")
46721
47575
  return homedir2();
46722
47576
  if (path5.startsWith("~/"))
46723
- return resolve5(homedir2(), path5.slice(2));
47577
+ return resolve6(homedir2(), path5.slice(2));
46724
47578
  return path5;
46725
47579
  }
46726
47580
  function classifyHelperSegment(tokens, dirState, readBodyFile) {
@@ -46746,7 +47600,7 @@ function classifyHelperSegment(tokens, dirState, readBodyFile) {
46746
47600
  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.`
46747
47601
  };
46748
47602
  }
46749
- const resolved = isAbsolute4(expanded) ? expanded : resolve5(dirState.dir, expanded);
47603
+ const resolved = isAbsolute4(expanded) ? expanded : resolve6(dirState.dir, expanded);
46750
47604
  let body;
46751
47605
  try {
46752
47606
  body = readBodyFile(resolved);