@plinth-music/cli 0.20.1 → 0.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.0",
7588
7588
  description: "Plinth capstone sync daemon and CLI",
7589
7589
  type: "module",
7590
7590
  private: false,
@@ -30505,6 +30505,560 @@ function ensureGitignore(workspaceSlug) {
30505
30505
  function backupStamp2(d) {
30506
30506
  return d.toISOString().replace(/[-:.]/g, "").replace("Z", "");
30507
30507
  }
30508
+ // src/lib/context/observation.ts
30509
+ import {
30510
+ closeSync as closeSync2,
30511
+ constants as FS,
30512
+ fstatSync,
30513
+ lstatSync as lstatSync3,
30514
+ openSync as openSync2,
30515
+ readSync,
30516
+ realpathSync as realpathSync2
30517
+ } from "node:fs";
30518
+ import { createHash as createHash2 } from "node:crypto";
30519
+ import { basename as basename2, dirname as dirname6, join as join8, resolve as resolve3, sep as sep4 } from "node:path";
30520
+ var OBSERVATION_MAX_BYTES = 64 * 1024 * 1024;
30521
+ var OBSERVATION_MAX_LINES = 200000;
30522
+ var READ_CHUNK = 1024 * 1024;
30523
+ var PROVENANCE_MAX = 256;
30524
+ var UNSAFE_PROVENANCE = /[\p{Cc}\p{Cf}]/u;
30525
+ function safeProvenance(v) {
30526
+ if (typeof v !== "string" || v === "")
30527
+ return null;
30528
+ if (v.length > PROVENANCE_MAX)
30529
+ return null;
30530
+ if (UNSAFE_PROVENANCE.test(v))
30531
+ return null;
30532
+ return v;
30533
+ }
30534
+ var ATTACHMENT_LABELS = new Set([
30535
+ "skill_listing",
30536
+ "deferred_tools_delta",
30537
+ "mcp_instructions_delta",
30538
+ "command_permissions",
30539
+ "agent_listing_delta",
30540
+ "total_tokens_reminder",
30541
+ "auto_mode",
30542
+ "remote_session_change",
30543
+ "file_history_snapshot"
30544
+ ]);
30545
+ function isFailure(x) {
30546
+ return x.status !== undefined;
30547
+ }
30548
+ function openSelected(selectedPath, hooks = {}) {
30549
+ const resolved = resolve3(selectedPath);
30550
+ let canonicalPath;
30551
+ try {
30552
+ canonicalPath = realpathSync2(resolved);
30553
+ } catch (err) {
30554
+ const code = err?.code;
30555
+ if (code === "ENOENT") {
30556
+ return { status: "absent", refusalReason: null, canonicalPath: null, indirection: false };
30557
+ }
30558
+ if (code === "ELOOP") {
30559
+ return {
30560
+ status: "refused",
30561
+ refusalReason: "path-unresolvable",
30562
+ canonicalPath: null,
30563
+ indirection: true
30564
+ };
30565
+ }
30566
+ return { status: "unreadable", refusalReason: null, canonicalPath: null, indirection: false };
30567
+ }
30568
+ const indirection = canonicalPath !== resolved;
30569
+ let before;
30570
+ try {
30571
+ before = lstatSync3(canonicalPath);
30572
+ } catch (err) {
30573
+ const code = err?.code;
30574
+ if (code === "ENOENT") {
30575
+ return { status: "absent", refusalReason: null, canonicalPath, indirection };
30576
+ }
30577
+ return { status: "unreadable", refusalReason: null, canonicalPath, indirection };
30578
+ }
30579
+ hooks.afterIdentityCheck?.();
30580
+ let fd;
30581
+ try {
30582
+ fd = openSync2(canonicalPath, FS.O_RDONLY | FS.O_NOFOLLOW | FS.O_NONBLOCK);
30583
+ } catch (err) {
30584
+ const code = err?.code;
30585
+ if (code === "ENOENT") {
30586
+ return { status: "absent", refusalReason: null, canonicalPath, indirection };
30587
+ }
30588
+ if (code === "ELOOP" || code === "EMLINK") {
30589
+ return { status: "refused", refusalReason: "target-changed", canonicalPath, indirection };
30590
+ }
30591
+ return { status: "unreadable", refusalReason: null, canonicalPath, indirection };
30592
+ }
30593
+ let after;
30594
+ try {
30595
+ after = fstatSync(fd);
30596
+ } catch {
30597
+ closeSync2(fd);
30598
+ return { status: "unreadable", refusalReason: null, canonicalPath, indirection };
30599
+ }
30600
+ if (!after.isFile()) {
30601
+ closeSync2(fd);
30602
+ return { status: "refused", refusalReason: "not-regular-file", canonicalPath, indirection };
30603
+ }
30604
+ if (after.dev !== before.dev || after.ino !== before.ino) {
30605
+ closeSync2(fd);
30606
+ return { status: "refused", refusalReason: "target-changed", canonicalPath, indirection };
30607
+ }
30608
+ return { fd, canonicalPath, indirection };
30609
+ }
30610
+ function readBounded(fd, maxBytes) {
30611
+ const hash2 = createHash2("sha256");
30612
+ const chunks = [];
30613
+ const buf = Buffer.allocUnsafe(READ_CHUNK);
30614
+ let bytesRead = 0;
30615
+ let truncated = false;
30616
+ for (;; ) {
30617
+ const want = Math.min(READ_CHUNK, maxBytes - bytesRead);
30618
+ if (want <= 0) {
30619
+ const probe2 = readSync(fd, buf, 0, 1, bytesRead);
30620
+ truncated = probe2 > 0;
30621
+ break;
30622
+ }
30623
+ const n = readSync(fd, buf, 0, want, bytesRead);
30624
+ if (n <= 0)
30625
+ break;
30626
+ const slice = Buffer.from(buf.subarray(0, n));
30627
+ hash2.update(slice);
30628
+ chunks.push(slice);
30629
+ bytesRead += n;
30630
+ }
30631
+ return {
30632
+ text: Buffer.concat(chunks).toString("utf8"),
30633
+ bytesRead,
30634
+ truncated,
30635
+ sha256: hash2.digest("hex")
30636
+ };
30637
+ }
30638
+ var USAGE_FIELDS = [
30639
+ ["inputTokens", ["input_tokens"]],
30640
+ ["cacheReadTokens", ["cache_read_input_tokens"]],
30641
+ ["cacheCreationTokens", ["cache_creation_input_tokens"]],
30642
+ ["outputTokens", ["output_tokens"]],
30643
+ ["cacheCreation1hTokens", ["cache_creation", "ephemeral_1h_input_tokens"]],
30644
+ ["cacheCreation5mTokens", ["cache_creation", "ephemeral_5m_input_tokens"]]
30645
+ ];
30646
+ function dig(obj, path) {
30647
+ let cur = obj;
30648
+ for (const key of path) {
30649
+ if (cur === null || typeof cur !== "object")
30650
+ return;
30651
+ cur = cur[key];
30652
+ }
30653
+ return cur;
30654
+ }
30655
+
30656
+ class UsageAccumulator {
30657
+ byRequest = new Map;
30658
+ sums = new Map;
30659
+ present = new Map;
30660
+ requests = 0;
30661
+ countedRecords = 0;
30662
+ duplicateRecords = 0;
30663
+ conflictingDuplicates = 0;
30664
+ untaggedRecords = 0;
30665
+ recordsWithoutUsage = 0;
30666
+ unresolvableRecords = 0;
30667
+ add(record2) {
30668
+ if (record2["type"] !== "assistant")
30669
+ return;
30670
+ const usage = dig(record2, ["message", "usage"]);
30671
+ const hasUsage = usage !== null && typeof usage === "object";
30672
+ if (hasUsage)
30673
+ this.countedRecords += 1;
30674
+ else
30675
+ this.recordsWithoutUsage += 1;
30676
+ const requestId = record2["requestId"];
30677
+ if (typeof requestId !== "string" || requestId === "") {
30678
+ if (hasUsage)
30679
+ this.untaggedRecords += 1;
30680
+ else
30681
+ this.unresolvableRecords += 1;
30682
+ return;
30683
+ }
30684
+ if (!this.byRequest.has(requestId)) {
30685
+ this.byRequest.set(requestId, null);
30686
+ this.requests += 1;
30687
+ }
30688
+ if (!hasUsage)
30689
+ return;
30690
+ const fingerprint = JSON.stringify(USAGE_FIELDS.map(([, path]) => dig(usage, path) ?? null));
30691
+ const prior = this.byRequest.get(requestId) ?? null;
30692
+ if (prior !== null) {
30693
+ if (prior === fingerprint)
30694
+ this.duplicateRecords += 1;
30695
+ else
30696
+ this.conflictingDuplicates += 1;
30697
+ return;
30698
+ }
30699
+ this.byRequest.set(requestId, fingerprint);
30700
+ for (const [name, path] of USAGE_FIELDS) {
30701
+ const raw = dig(usage, path);
30702
+ if (typeof raw !== "number" || !Number.isFinite(raw))
30703
+ continue;
30704
+ this.present.set(name, (this.present.get(name) ?? 0) + 1);
30705
+ this.sums.set(name, (this.sums.get(name) ?? 0) + raw);
30706
+ }
30707
+ }
30708
+ unresolved() {
30709
+ let n = 0;
30710
+ for (const fp of this.byRequest.values())
30711
+ if (fp === null)
30712
+ n += 1;
30713
+ return n;
30714
+ }
30715
+ finish() {
30716
+ if (this.countedRecords === 0 && this.recordsWithoutUsage === 0)
30717
+ return null;
30718
+ const unresolvedRequests = this.unresolved();
30719
+ const incompleteFields = [];
30720
+ const value = (name) => {
30721
+ const present2 = this.present.get(name) ?? 0;
30722
+ if (present2 > 0 && present2 === this.requests)
30723
+ return this.sums.get(name) ?? 0;
30724
+ if (present2 > 0)
30725
+ incompleteFields.push(name);
30726
+ return null;
30727
+ };
30728
+ const fields = Object.fromEntries(USAGE_FIELDS.map(([name]) => [name, value(name)]));
30729
+ const anyFullyCovered = USAGE_FIELDS.some(([name]) => (this.present.get(name) ?? 0) > 0 && (this.present.get(name) ?? 0) === this.requests);
30730
+ return {
30731
+ requests: this.requests,
30732
+ countedRecords: this.countedRecords,
30733
+ duplicateRecords: this.duplicateRecords,
30734
+ conflictingDuplicates: this.conflictingDuplicates,
30735
+ untaggedRecords: this.untaggedRecords,
30736
+ unresolvedRequests,
30737
+ recordsWithoutUsage: this.recordsWithoutUsage,
30738
+ unresolvableRecords: this.unresolvableRecords,
30739
+ ...fields,
30740
+ incompleteFields,
30741
+ incomplete: incompleteFields.length > 0 || this.conflictingDuplicates > 0 || this.untaggedRecords > 0 || unresolvedRequests > 0 || this.unresolvableRecords > 0 || this.requests > 0 && !anyFullyCovered
30742
+ };
30743
+ }
30744
+ }
30745
+ function hasToolResult(content) {
30746
+ if (!Array.isArray(content))
30747
+ return false;
30748
+ return content.some((b) => b !== null && typeof b === "object" && b["type"] === "tool_result");
30749
+ }
30750
+ function contentText(content) {
30751
+ if (typeof content === "string")
30752
+ return content;
30753
+ if (!Array.isArray(content))
30754
+ return "";
30755
+ return content.map((b) => b !== null && typeof b === "object" && typeof b["text"] === "string" ? b["text"] : "").join("");
30756
+ }
30757
+ function payloadBytes(payload) {
30758
+ if (payload === undefined)
30759
+ return 0;
30760
+ if (typeof payload === "string")
30761
+ return Buffer.byteLength(payload, "utf8");
30762
+ try {
30763
+ return Buffer.byteLength(JSON.stringify(payload) ?? "", "utf8");
30764
+ } catch {
30765
+ return 0;
30766
+ }
30767
+ }
30768
+
30769
+ class DeliveryAccumulator {
30770
+ rows = new Map;
30771
+ pendingCommand = false;
30772
+ bump(kind, label, bytes) {
30773
+ const key = `${kind} ${label}`;
30774
+ const row = this.rows.get(key) ?? { kind, label, occurrences: 0, recordedBytes: 0 };
30775
+ row.occurrences += 1;
30776
+ row.recordedBytes += bytes;
30777
+ this.rows.set(key, row);
30778
+ }
30779
+ add(record2) {
30780
+ const wasPending = this.pendingCommand;
30781
+ this.pendingCommand = false;
30782
+ const type = record2["type"];
30783
+ if (type === "attachment") {
30784
+ const att = record2["attachment"];
30785
+ const rawLabel = dig(att, ["type"]);
30786
+ const label = typeof rawLabel === "string" && ATTACHMENT_LABELS.has(rawLabel) ? rawLabel : "other";
30787
+ this.bump("harness-listing", label, payloadBytes(att));
30788
+ return;
30789
+ }
30790
+ if (type !== "user")
30791
+ return;
30792
+ const content = dig(record2, ["message", "content"]);
30793
+ const bytes = payloadBytes(content);
30794
+ const text = contentText(content);
30795
+ if (record2["isMeta"] === true) {
30796
+ if (wasPending)
30797
+ this.bump("command-body", "command-body", bytes);
30798
+ else
30799
+ this.bump("meta-injection", "meta-injection", bytes);
30800
+ return;
30801
+ }
30802
+ if (hasToolResult(content)) {
30803
+ this.bump("tool-result", "tool-result", bytes);
30804
+ return;
30805
+ }
30806
+ const opening = text.trimStart();
30807
+ this.pendingCommand = opening.startsWith("<command-message>") || opening.startsWith("<command-name>");
30808
+ this.bump("user-turn", "user-turn", bytes);
30809
+ }
30810
+ finish() {
30811
+ return [...this.rows.values()].sort((a, b) => b.recordedBytes - a.recordedBytes || a.label.localeCompare(b.label));
30812
+ }
30813
+ }
30814
+
30815
+ class BindingAccumulator {
30816
+ sessionIds = new Set;
30817
+ versions = new Set;
30818
+ cwds = new Set;
30819
+ branches = new Set;
30820
+ first = null;
30821
+ last = null;
30822
+ rejected = 0;
30823
+ add(record2) {
30824
+ const str2 = (k) => {
30825
+ const raw = record2[k];
30826
+ const safe = safeProvenance(raw);
30827
+ if (safe === null && typeof raw === "string" && raw !== "")
30828
+ this.rejected += 1;
30829
+ return safe;
30830
+ };
30831
+ const sid = str2("sessionId");
30832
+ if (sid !== null)
30833
+ this.sessionIds.add(sid);
30834
+ const ver = str2("version");
30835
+ if (ver !== null)
30836
+ this.versions.add(ver);
30837
+ const cwd = str2("cwd");
30838
+ if (cwd !== null)
30839
+ this.cwds.add(cwd);
30840
+ const branch = str2("gitBranch");
30841
+ if (branch !== null)
30842
+ this.branches.add(branch);
30843
+ const ts = str2("timestamp");
30844
+ if (ts !== null) {
30845
+ if (this.first === null || ts < this.first)
30846
+ this.first = ts;
30847
+ if (this.last === null || ts > this.last)
30848
+ this.last = ts;
30849
+ }
30850
+ }
30851
+ finish(workspaceMirrorDir) {
30852
+ const only = (s) => s.size === 1 ? [...s][0] : null;
30853
+ const cwd = only(this.cwds);
30854
+ const consistent = this.sessionIds.size === 1 && this.versions.size === 1 && this.cwds.size === 1;
30855
+ return {
30856
+ sessionId: only(this.sessionIds),
30857
+ runtimeVersion: only(this.versions),
30858
+ cwd,
30859
+ gitBranch: only(this.branches),
30860
+ firstTimestamp: this.first,
30861
+ lastTimestamp: this.last,
30862
+ distinctSessionIds: this.sessionIds.size,
30863
+ consistent,
30864
+ scope: deriveScope(cwd, workspaceMirrorDir),
30865
+ rejectedFields: this.rejected
30866
+ };
30867
+ }
30868
+ }
30869
+ function canonicalise(p) {
30870
+ const full = resolve3(p);
30871
+ let cur = full;
30872
+ const tail = [];
30873
+ for (;; ) {
30874
+ try {
30875
+ const real = realpathSync2(cur);
30876
+ return tail.length === 0 ? real : join8(real, ...tail.slice().reverse());
30877
+ } catch {
30878
+ const parent = dirname6(cur);
30879
+ if (parent === cur)
30880
+ return full;
30881
+ tail.push(basename2(cur));
30882
+ cur = parent;
30883
+ }
30884
+ }
30885
+ }
30886
+ function deriveScope(cwd, workspaceMirrorDir) {
30887
+ if (cwd === null || workspaceMirrorDir === undefined)
30888
+ return "unknown";
30889
+ const ws = canonicalise(workspaceMirrorDir);
30890
+ const here = canonicalise(cwd);
30891
+ if (here === ws)
30892
+ return "root";
30893
+ if (here.startsWith(ws.endsWith(sep4) ? ws : ws + sep4))
30894
+ return "below-root";
30895
+ return "outside";
30896
+ }
30897
+ function limitsFor(obs) {
30898
+ const limits = [
30899
+ {
30900
+ id: "observation-not-attributable",
30901
+ 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",
30902
+ owner: "not exposed by the measured artefact, runtime and this adapter; further effective-loading work stays with S2/E15 and the packaged half"
30903
+ },
30904
+ {
30905
+ id: "observation-interval",
30906
+ 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",
30907
+ owner: "the reader who selected the file; re-run to extend it"
30908
+ },
30909
+ {
30910
+ id: "observation-inventory-not-contemporaneous",
30911
+ 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",
30912
+ owner: "E15, which compares arms rather than inventories"
30913
+ },
30914
+ {
30915
+ id: "observation-compaction",
30916
+ 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",
30917
+ owner: "a later S2/E15 lane with a purpose-built compacted session"
30918
+ },
30919
+ {
30920
+ id: "observation-delivery-cause",
30921
+ 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",
30922
+ owner: "a later S2 lane, if per-route delivery proof is wanted"
30923
+ }
30924
+ ];
30925
+ if (obs.binding.rejectedFields > 0) {
30926
+ limits.push({
30927
+ id: "observation-provenance-refused",
30928
+ 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",
30929
+ owner: "the reader who selected the file"
30930
+ });
30931
+ }
30932
+ if (obs.indirection) {
30933
+ limits.push({
30934
+ id: "observation-path-indirection",
30935
+ what: "the selected path resolved through a link; the canonical path above is what was read",
30936
+ owner: "the reader who selected the file"
30937
+ });
30938
+ }
30939
+ if (!obs.binding.consistent) {
30940
+ limits.push({
30941
+ id: "observation-binding-inconsistent",
30942
+ 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",
30943
+ owner: "select a single-session transcript to attribute it"
30944
+ });
30945
+ }
30946
+ if (obs.binding.scope === "below-root") {
30947
+ limits.push({
30948
+ id: "observation-scope-unsupported",
30949
+ 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",
30950
+ owner: "a later S2 lane, if per-scope resolution is wanted"
30951
+ });
30952
+ }
30953
+ return limits;
30954
+ }
30955
+ function emptyBinding(workspaceMirrorDir) {
30956
+ return new BindingAccumulator().finish(workspaceMirrorDir);
30957
+ }
30958
+ function shell(selectedPath, status, refusalReason, canonicalPath, indirection, opts, extras = {}) {
30959
+ const base2 = {
30960
+ status,
30961
+ refusalReason,
30962
+ selectedPath,
30963
+ canonicalPath,
30964
+ indirection,
30965
+ bytesRead: extras.bytesRead ?? 0,
30966
+ sha256: extras.sha256 ?? null,
30967
+ lines: extras.lines ?? { total: 0, parsed: 0, malformed: 0, truncated: false, cutFinalLine: false },
30968
+ binding: emptyBinding(opts.workspaceMirrorDir),
30969
+ usage: null,
30970
+ deliveries: []
30971
+ };
30972
+ return { ...base2, limits: limitsFor(base2), complete: false };
30973
+ }
30974
+ function buildObservation(selectedPath, opts = {}) {
30975
+ const maxBytes = opts.maxBytes ?? OBSERVATION_MAX_BYTES;
30976
+ const maxLines = opts.maxLines ?? OBSERVATION_MAX_LINES;
30977
+ const opened = openSelected(selectedPath, opts.openHooks ?? {});
30978
+ if (isFailure(opened)) {
30979
+ return shell(selectedPath, opened.status, opened.refusalReason, opened.canonicalPath, opened.indirection, opts);
30980
+ }
30981
+ let read;
30982
+ try {
30983
+ read = readBounded(opened.fd, maxBytes);
30984
+ } catch {
30985
+ return shell(selectedPath, "unreadable", null, opened.canonicalPath, opened.indirection, opts);
30986
+ } finally {
30987
+ try {
30988
+ closeSync2(opened.fd);
30989
+ } catch {}
30990
+ }
30991
+ const pieces = read.text.split(`
30992
+ `);
30993
+ if (pieces.length > 0 && pieces[pieces.length - 1] === "")
30994
+ pieces.pop();
30995
+ let cutFinalLine = false;
30996
+ let truncated = read.truncated;
30997
+ if (read.truncated && pieces.length > 0 && !read.text.endsWith(`
30998
+ `)) {
30999
+ pieces.pop();
31000
+ cutFinalLine = true;
31001
+ }
31002
+ if (pieces.length > maxLines) {
31003
+ pieces.length = maxLines;
31004
+ truncated = true;
31005
+ }
31006
+ const nonBlank = pieces.filter((l) => l.trim() !== "");
31007
+ if (nonBlank.length === 0) {
31008
+ return shell(selectedPath, truncated ? "read" : "empty", null, opened.canonicalPath, opened.indirection, opts, {
31009
+ bytesRead: read.bytesRead,
31010
+ sha256: read.sha256,
31011
+ lines: { total: 0, parsed: 0, malformed: 0, truncated, cutFinalLine }
31012
+ });
31013
+ }
31014
+ const usage = new UsageAccumulator;
31015
+ const deliveries = new DeliveryAccumulator;
31016
+ const binding = new BindingAccumulator;
31017
+ let parsed = 0;
31018
+ let malformed = 0;
31019
+ for (const line of nonBlank) {
31020
+ let record2;
31021
+ try {
31022
+ record2 = JSON.parse(line);
31023
+ } catch {
31024
+ malformed += 1;
31025
+ continue;
31026
+ }
31027
+ if (record2 === null || typeof record2 !== "object" || Array.isArray(record2)) {
31028
+ malformed += 1;
31029
+ continue;
31030
+ }
31031
+ parsed += 1;
31032
+ const rec = record2;
31033
+ binding.add(rec);
31034
+ usage.add(rec);
31035
+ deliveries.add(rec);
31036
+ }
31037
+ const lines = {
31038
+ total: nonBlank.length,
31039
+ parsed,
31040
+ malformed,
31041
+ truncated,
31042
+ cutFinalLine
31043
+ };
31044
+ const status = parsed === 0 ? "malformed" : "read";
31045
+ const finishedUsage = status === "read" ? usage.finish() : null;
31046
+ const base2 = {
31047
+ status,
31048
+ refusalReason: null,
31049
+ selectedPath,
31050
+ canonicalPath: opened.canonicalPath,
31051
+ indirection: opened.indirection,
31052
+ bytesRead: read.bytesRead,
31053
+ sha256: read.sha256,
31054
+ lines,
31055
+ binding: binding.finish(opts.workspaceMirrorDir),
31056
+ usage: finishedUsage,
31057
+ deliveries: status === "read" ? deliveries.finish() : []
31058
+ };
31059
+ const complete = status === "read" && malformed === 0 && !truncated && !cutFinalLine && (finishedUsage === null || !finishedUsage.incomplete);
31060
+ return { ...base2, limits: limitsFor(base2), complete };
31061
+ }
30508
31062
 
30509
31063
  // src/lib/context/context-account.ts
30510
31064
  function localRow(workspaceSlug) {
@@ -30709,13 +31263,13 @@ function collectExternalSources() {
30709
31263
  var STANDING_LIMITS = [
30710
31264
  {
30711
31265
  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)"
31266
+ what: "what a session ACTUALLY loaded is not observed here. Everything above is bytes on disk and the hook's own rendered output",
31267
+ owner: "pass `--observed <transcript.jsonl>` to measure one selected session's recorded delivery. Per-source attribution stays unavailable even then"
30714
31268
  },
30715
31269
  {
30716
31270
  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"
31271
+ what: "tokens, cached and billed usage are not measured here",
31272
+ 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
31273
  },
30720
31274
  {
30721
31275
  id: "user-level-config",
@@ -30767,7 +31321,11 @@ function buildContextAccount(workspaceSlug, deps = {}) {
30767
31321
  collectExternalSources()
30768
31322
  ];
30769
31323
  const sources = parts.flatMap((p) => p.sources);
30770
- const limits = [...parts.flatMap((p) => p.limits), ...STANDING_LIMITS];
31324
+ const limits = [
31325
+ ...parts.flatMap((p) => p.limits),
31326
+ ...STANDING_LIMITS,
31327
+ ...deps.observation?.limits ?? []
31328
+ ];
30771
31329
  const refusedFeedingHook = sources.filter((s) => s.status === "refused" && (s.route === "hook-injection" || s.path === VOICE_FILENAME));
30772
31330
  if (refusedFeedingHook.length > 0) {
30773
31331
  limits.unshift({
@@ -30805,6 +31363,7 @@ function buildContextAccount(workspaceSlug, deps = {}) {
30805
31363
  observedLoadedBytes: null,
30806
31364
  estimatedTokens: null,
30807
31365
  conditionalStanding,
31366
+ observation: deps.observation ?? null,
30808
31367
  limits
30809
31368
  };
30810
31369
  }
@@ -31059,13 +31618,92 @@ function renderAccount(out, account) {
31059
31618
  out.info(` · ${a}`);
31060
31619
  out.info("");
31061
31620
  }
31621
+ if (account.observation !== null)
31622
+ renderObservation(out, account.observation);
31062
31623
  out.info("Not measured here");
31063
- out.info(" Observed loading: not observed. Tokens and billed usage: not measured.");
31624
+ if (account.observation === null) {
31625
+ out.info(" Observed loading: not observed. Tokens and billed usage: not measured.");
31626
+ } else {
31627
+ out.info(" Observed above is ONE selected session's recorded delivery and usage. No token is attributed to any file.");
31628
+ }
31064
31629
  for (const l of account.limits) {
31065
31630
  out.info(` · ${l.what}`);
31066
31631
  out.info(` owed to: ${l.owner}`);
31067
31632
  }
31068
31633
  }
31634
+ var REFUSAL_PROSE = {
31635
+ "not-regular-file": "not a regular file",
31636
+ "target-changed": "the file opened was not the file checked — refused rather than measured",
31637
+ "path-unresolvable": "the path could not be resolved"
31638
+ };
31639
+ var STATUS_PROSE = {
31640
+ absent: "not there",
31641
+ unreadable: "could not be read",
31642
+ empty: "no records",
31643
+ malformed: "records present, none parsed — NOT a measured zero"
31644
+ };
31645
+ function renderObservation(out, obs) {
31646
+ const head = obs.complete ? "Observed" : "Observed (PARTIAL)";
31647
+ if (obs.status !== "read") {
31648
+ const why = REFUSAL_PROSE[obs.refusalReason ?? ""] ?? STATUS_PROSE[obs.status] ?? obs.status;
31649
+ out.info(`${head} ${obs.selectedPath}`);
31650
+ out.info(` ${why}. Nothing was measured, and that is not a zero.`);
31651
+ if (obs.bytesRead > 0 || obs.lines.total > 0) {
31652
+ 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)}` : ""));
31653
+ }
31654
+ out.info("");
31655
+ return;
31656
+ }
31657
+ const b = obs.binding;
31658
+ out.info(`${head} ${fmt(obs.bytesRead)} bytes read from the selected transcript`);
31659
+ if (obs.canonicalPath !== null && obs.indirection) {
31660
+ out.info(` resolved through a link to ${obs.canonicalPath}`);
31661
+ }
31662
+ out.info(` session ${b.sessionId ?? "unknown"} · runtime ${b.runtimeVersion ?? "unknown"} · scope ${b.scope}`);
31663
+ out.info(` interval ${b.firstTimestamp ?? "unknown"} .. ${b.lastTimestamp ?? "unknown"} · sha256 ${obs.sha256?.slice(0, 16) ?? "unknown"}`);
31664
+ 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" : ""));
31665
+ if (b.rejectedFields > 0) {
31666
+ out.info(` ${fmt(b.rejectedFields)} provenance value(s) in the file were refused as unsafe or over-long and read as unknown above.`);
31667
+ }
31668
+ if (!b.consistent) {
31669
+ out.info(" NOT attributed to this workspace: session, runtime or directory is missing or varies across records.");
31670
+ }
31671
+ out.info("");
31672
+ const u = obs.usage;
31673
+ if (u === null) {
31674
+ out.info(" Usage — no record carried a usage object. Unknown, not zero.");
31675
+ } else {
31676
+ const n = (v) => v === null ? "unknown" : fmt(v);
31677
+ 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)` : ""));
31678
+ out.info(` fresh input ${n(u.inputTokens)} tokens`);
31679
+ out.info(` cache read ${n(u.cacheReadTokens)} tokens`);
31680
+ out.info(` cache written ${n(u.cacheCreationTokens)} tokens`);
31681
+ out.info(` output ${n(u.outputTokens)} tokens`);
31682
+ if (u.conflictingDuplicates > 0) {
31683
+ out.info(` ⚠ ${fmt(u.conflictingDuplicates)} request(s) reported conflicting usage; the figures above are incomplete`);
31684
+ }
31685
+ if (u.untaggedRecords > 0) {
31686
+ out.info(` ⚠ ${fmt(u.untaggedRecords)} record(s) carried usage with no request id; excluded, because they cannot be shown independent`);
31687
+ }
31688
+ if (u.unresolvedRequests > 0) {
31689
+ out.info(` ⚠ ${fmt(u.unresolvedRequests)} of ${fmt(u.requests)} request(s) carried no usage record, so what they cost is unknown — not zero`);
31690
+ }
31691
+ if (u.unresolvableRecords > 0) {
31692
+ out.info(` ⚠ ${fmt(u.unresolvableRecords)} record(s) had neither usage nor a request id; nothing can name or resolve them`);
31693
+ }
31694
+ if (u.incompleteFields.length > 0) {
31695
+ out.info(` ⚠ not every request reported: ${u.incompleteFields.join(", ")}`);
31696
+ }
31697
+ }
31698
+ out.info("");
31699
+ if (obs.deliveries.length > 0) {
31700
+ out.info(" Recorded deliveries — payload bytes as stored, not injected or billed bytes");
31701
+ for (const d of obs.deliveries) {
31702
+ out.info(` ${d.kind.padEnd(16)} ${d.label.padEnd(24)} ${String(d.occurrences).padStart(4)}x ${fmt(d.recordedBytes)} bytes`);
31703
+ }
31704
+ out.info("");
31705
+ }
31706
+ }
31069
31707
  async function runContext(args, deps = {}) {
31070
31708
  const out = new Output({ sink: deps.sink, noColor: deps.noColor });
31071
31709
  const config2 = (deps.loadConfigFn ?? loadConfig)();
@@ -31079,7 +31717,20 @@ async function runContext(args, deps = {}) {
31079
31717
  out.error(`Workspace "${slug}" not found. Run \`plinth login --workspace ${slug}\` first.`);
31080
31718
  return { exitCode: 1 };
31081
31719
  }
31720
+ let observation = null;
31721
+ if (args.observed !== undefined && args.observed !== "") {
31722
+ let mirrorDir;
31723
+ try {
31724
+ mirrorDir = workspaceMirrorPath(slug);
31725
+ } catch {
31726
+ mirrorDir = undefined;
31727
+ }
31728
+ observation = (deps.buildObservationFn ?? buildObservation)(args.observed, {
31729
+ workspaceMirrorDir: mirrorDir
31730
+ });
31731
+ }
31082
31732
  const account = buildContextAccount(slug, {
31733
+ observation,
31083
31734
  hook: deps.hook ?? (() => defaultHook(slug)),
31084
31735
  listMemberCommands: deps.listMemberCommands,
31085
31736
  readStoreModes: deps.readStoreModes ?? readMemoryStoreModesNoWrite
@@ -31110,6 +31761,11 @@ var contextCommand = defineCommand({
31110
31761
  description: "Emit the account as JSON",
31111
31762
  required: false
31112
31763
  },
31764
+ observed: {
31765
+ type: "string",
31766
+ 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",
31767
+ required: false
31768
+ },
31113
31769
  "no-color": {
31114
31770
  type: "boolean",
31115
31771
  description: "Disable ANSI colour output",
@@ -31117,7 +31773,7 @@ var contextCommand = defineCommand({
31117
31773
  }
31118
31774
  },
31119
31775
  async run({ args }) {
31120
- const result = await runContext({ workspace: args.workspace, json: args.json === true }, { noColor: noColorFromArgs(args) });
31776
+ const result = await runContext({ workspace: args.workspace, json: args.json === true, observed: args.observed }, { noColor: noColorFromArgs(args) });
31121
31777
  if (result.exitCode !== 0)
31122
31778
  process.exit(result.exitCode);
31123
31779
  }
@@ -31484,14 +32140,14 @@ var loginCommand = defineCommand({
31484
32140
  // src/lib/memory-gate/log.ts
31485
32141
  import {
31486
32142
  appendFileSync,
31487
- closeSync as closeSync2,
32143
+ closeSync as closeSync3,
31488
32144
  mkdirSync as mkdirSync8,
31489
- openSync as openSync2,
32145
+ openSync as openSync3,
31490
32146
  readFileSync as readFileSync12,
31491
- readSync,
32147
+ readSync as readSync2,
31492
32148
  statSync as statSync3
31493
32149
  } from "node:fs";
31494
- import { join as join9 } from "node:path";
32150
+ import { join as join10 } from "node:path";
31495
32151
 
31496
32152
  // src/lib/sessions/registry.ts
31497
32153
  import {
@@ -31503,7 +32159,7 @@ import {
31503
32159
  unlinkSync as unlinkSync6,
31504
32160
  writeFileSync as writeFileSync6
31505
32161
  } from "node:fs";
31506
- import { basename as basename2, dirname as dirname6, join as join8 } from "node:path";
32162
+ import { basename as basename3, dirname as dirname7, join as join9 } from "node:path";
31507
32163
  var SessionRecordSchema = exports_external.object({
31508
32164
  version: exports_external.literal(1),
31509
32165
  session_id: exports_external.string().min(1),
@@ -31524,13 +32180,13 @@ function sessionsDir(workspaceSlug) {
31524
32180
  if (!isSafeSegment(workspaceSlug)) {
31525
32181
  throw new Error(`Refusing unsafe workspace slug: ${workspaceSlug}`);
31526
32182
  }
31527
- return join8(plinthHome(), workspaceSlug, "sessions");
32183
+ return join9(plinthHome(), workspaceSlug, "sessions");
31528
32184
  }
31529
32185
  function sessionRecordPath(workspaceSlug, sessionId) {
31530
32186
  if (!isSafeSegment(sessionId)) {
31531
32187
  throw new Error(`Refusing unsafe session id: ${sessionId}`);
31532
32188
  }
31533
- return join8(sessionsDir(workspaceSlug), `${sessionId}.json`);
32189
+ return join9(sessionsDir(workspaceSlug), `${sessionId}.json`);
31534
32190
  }
31535
32191
  function registerSession(input) {
31536
32192
  const startTime = (input.startTimeFn ?? readPidStartTime)(input.pid);
@@ -31553,7 +32209,7 @@ function registerSession(input) {
31553
32209
  }
31554
32210
  var tmpCounter = 0;
31555
32211
  function writeRecordAtomic(target, record2) {
31556
- const dir = dirname6(target);
32212
+ const dir = dirname7(target);
31557
32213
  mkdirSync7(dir, { recursive: true, mode: 448 });
31558
32214
  const tmp = `${target}.${process.pid}.${tmpCounter++}.tmp`;
31559
32215
  sweepDeadTmpFiles(dir, target);
@@ -31569,7 +32225,7 @@ function writeRecordAtomic(target, record2) {
31569
32225
  }
31570
32226
  }
31571
32227
  function sweepDeadTmpFiles(dir, target) {
31572
- const prefix = `${basename2(target)}.`;
32228
+ const prefix = `${basename3(target)}.`;
31573
32229
  let names;
31574
32230
  try {
31575
32231
  names = readdirSync5(dir);
@@ -31586,7 +32242,7 @@ function sweepDeadTmpFiles(dir, target) {
31586
32242
  if (pid === process.pid || isPidAlive(pid))
31587
32243
  continue;
31588
32244
  try {
31589
- unlinkSync6(join8(dir, name));
32245
+ unlinkSync6(join9(dir, name));
31590
32246
  } catch {}
31591
32247
  }
31592
32248
  }
@@ -31651,7 +32307,7 @@ function listSessions(workspaceSlug, deps = {}) {
31651
32307
  for (const name of names) {
31652
32308
  if (!name.endsWith(".json"))
31653
32309
  continue;
31654
- const path3 = join8(sessionsDir(workspaceSlug), name);
32310
+ const path3 = join9(sessionsDir(workspaceSlug), name);
31655
32311
  const record2 = readSessionRecord(path3);
31656
32312
  if (!record2) {
31657
32313
  continue;
@@ -31710,10 +32366,10 @@ function memoryGateDir(workspaceSlug) {
31710
32366
  if (!isSafeSegment(workspaceSlug)) {
31711
32367
  throw new Error(`Refusing unsafe workspace slug: ${workspaceSlug}`);
31712
32368
  }
31713
- return join9(plinthHome(), "_memory_gate", workspaceSlug);
32369
+ return join10(plinthHome(), "_memory_gate", workspaceSlug);
31714
32370
  }
31715
32371
  function memoryGateLogPath(workspaceSlug) {
31716
- return join9(memoryGateDir(workspaceSlug), "log.jsonl");
32372
+ return join10(memoryGateDir(workspaceSlug), "log.jsonl");
31717
32373
  }
31718
32374
  function buildDecisionRecord(input) {
31719
32375
  const final = input.decision === "accept" ? input.proposed : input.decision === "reject" ? null : input.final ?? null;
@@ -31746,13 +32402,13 @@ function endsMidLine(path3) {
31746
32402
  }
31747
32403
  if (size === 0)
31748
32404
  return false;
31749
- const fd = openSync2(path3, "r");
32405
+ const fd = openSync3(path3, "r");
31750
32406
  try {
31751
32407
  const last = Buffer.alloc(1);
31752
- readSync(fd, last, 0, 1, size - 1);
32408
+ readSync2(fd, last, 0, 1, size - 1);
31753
32409
  return last[0] !== 10;
31754
32410
  } finally {
31755
- closeSync2(fd);
32411
+ closeSync3(fd);
31756
32412
  }
31757
32413
  }
31758
32414
  function appendMemoryGateRecord(workspaceSlug, record2) {
@@ -33017,10 +33673,10 @@ import { existsSync as existsSync9, readFileSync as readFileSync26, statSync as
33017
33673
 
33018
33674
  // src/lib/daemon-log.ts
33019
33675
  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";
33676
+ import { dirname as dirname8, join as join11 } from "node:path";
33021
33677
  var DEFAULT_DAEMON_LOG_MAX_BYTES = 5000000;
33022
33678
  function daemonLogPath() {
33023
- return join10(plinthHome(), "daemon.log");
33679
+ return join11(plinthHome(), "daemon.log");
33024
33680
  }
33025
33681
  function daemonLogMaxBytes() {
33026
33682
  const raw = process.env.PLINTH_DAEMON_LOG_MAX_BYTES;
@@ -33042,7 +33698,7 @@ class DaemonLog {
33042
33698
  this.now = opts.now ?? (() => new Date);
33043
33699
  this.maxBytes = opts.maxBytes ?? daemonLogMaxBytes();
33044
33700
  try {
33045
- mkdirSync9(dirname7(this.path), { recursive: true });
33701
+ mkdirSync9(dirname8(this.path), { recursive: true });
33046
33702
  } catch {}
33047
33703
  try {
33048
33704
  this.bytesWritten = statSync4(this.path).size;
@@ -33081,7 +33737,7 @@ class DaemonLog {
33081
33737
  // src/lib/destructive-gate.ts
33082
33738
  var import_gray_matter7 = __toESM(require_gray_matter(), 1);
33083
33739
  import { readFileSync as readFileSync14, statSync as statSync5 } from "node:fs";
33084
- import { basename as basename3 } from "node:path";
33740
+ import { basename as basename4 } from "node:path";
33085
33741
  var GUTTING_RATIO_DEFAULT = 0.5;
33086
33742
  var GUTTING_MIN_PRIOR_BYTES = 200;
33087
33743
  function envFloat(name, def) {
@@ -33146,7 +33802,7 @@ function classifyDestructive(event, entityType, state, deps = {}) {
33146
33802
  return null;
33147
33803
  }
33148
33804
  const liveInode = statInode(event.absolutePath);
33149
- const slug = basename3(event.absolutePath, ".md");
33805
+ const slug = basename4(event.absolutePath, ".md");
33150
33806
  const entry2 = (liveInode !== undefined ? getEntryByInode(state, entityType, liveInode) : undefined) ?? getEntryBySlug(state, entityType, slug);
33151
33807
  if (!entry2)
33152
33808
  return null;
@@ -33261,18 +33917,18 @@ import { readFileSync as readFileSync18 } from "node:fs";
33261
33917
 
33262
33918
  // src/lib/conflicts.ts
33263
33919
  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";
33920
+ import { dirname as dirname9, join as join12 } from "node:path";
33265
33921
  function conflictsRoot(workspaceSlug) {
33266
- return join11(plinthHome(), "_conflicts", workspaceSlug);
33922
+ return join12(plinthHome(), "_conflicts", workspaceSlug);
33267
33923
  }
33268
33924
  function conflictFilePath(args) {
33269
33925
  const { workspaceSlug, entityType, entitySlug, timestamp, side } = args;
33270
33926
  const iso = timestamp.toISOString().replace(/[:.]/g, "-");
33271
- return join11(conflictsRoot(workspaceSlug), `${entityType}.${entitySlug}.${iso}.${side}.md`);
33927
+ return join12(conflictsRoot(workspaceSlug), `${entityType}.${entitySlug}.${iso}.${side}.md`);
33272
33928
  }
33273
33929
  function stashConflict(args) {
33274
33930
  const target = conflictFilePath(args);
33275
- mkdirSync10(dirname8(target), { recursive: true, mode: 448 });
33931
+ mkdirSync10(dirname9(target), { recursive: true, mode: 448 });
33276
33932
  writeFileSync7(target, args.contents, { mode: 384 });
33277
33933
  return target;
33278
33934
  }
@@ -33280,11 +33936,11 @@ function fileConflictPath(args) {
33280
33936
  const { workspaceSlug, relPath, timestamp, side } = args;
33281
33937
  const iso = timestamp.toISOString().replace(/[:.]/g, "-");
33282
33938
  const safe = relPath.replace(/[/\\]/g, "__");
33283
- return join11(conflictsRoot(workspaceSlug), `files.${safe}.${iso}.${side}`);
33939
+ return join12(conflictsRoot(workspaceSlug), `files.${safe}.${iso}.${side}`);
33284
33940
  }
33285
33941
  function stashFileConflict(args) {
33286
33942
  const target = fileConflictPath(args);
33287
- mkdirSync10(dirname8(target), { recursive: true, mode: 448 });
33943
+ mkdirSync10(dirname9(target), { recursive: true, mode: 448 });
33288
33944
  writeFileSync7(target, args.bytes, { mode: 384 });
33289
33945
  return target;
33290
33946
  }
@@ -33317,7 +33973,7 @@ function listConflictStashes(workspaceSlug) {
33317
33973
  }
33318
33974
  const out = [];
33319
33975
  for (const file2 of names) {
33320
- const absPath = join11(dir, file2);
33976
+ const absPath = join12(dir, file2);
33321
33977
  let st;
33322
33978
  try {
33323
33979
  st = statSync6(absPath);
@@ -33346,9 +34002,9 @@ function listConflictStashes(workspaceSlug) {
33346
34002
  import { readFileSync as readFileSync15, statSync as statSync7 } from "node:fs";
33347
34003
 
33348
34004
  // src/lib/files/content-hash.ts
33349
- import { createHash as createHash2 } from "node:crypto";
34005
+ import { createHash as createHash3 } from "node:crypto";
33350
34006
  function sha256Bytes(bytes) {
33351
- return createHash2("sha256").update(bytes).digest("hex");
34007
+ return createHash3("sha256").update(bytes).digest("hex");
33352
34008
  }
33353
34009
 
33354
34010
  // src/lib/files/mime.ts
@@ -33669,7 +34325,7 @@ class PerIdMutex {
33669
34325
  // src/lib/push.ts
33670
34326
  var import_gray_matter10 = __toESM(require_gray_matter(), 1);
33671
34327
  import { readFileSync as readFileSync17, statSync as statSync8 } from "node:fs";
33672
- import { basename as basename4, relative as relative5 } from "node:path";
34328
+ import { basename as basename5, relative as relative5 } from "node:path";
33673
34329
 
33674
34330
  // src/lib/frontmatter-id.ts
33675
34331
  var import_gray_matter8 = __toESM(require_gray_matter(), 1);
@@ -34150,7 +34806,7 @@ async function pushFile(args) {
34150
34806
  const rel = relative5(workspaceMirrorPath(workspaceSlug), absolutePath);
34151
34807
  parsedSlug = strategy.parseMirrorPath(rel)?.slug ?? null;
34152
34808
  } catch {}
34153
- const slugFromPath = parsedSlug ?? basename4(absolutePath, ".md");
34809
+ const slugFromPath = parsedSlug ?? basename5(absolutePath, ".md");
34154
34810
  const slug = identity === "path" ? slugFromPath : slugFromFm ?? slugFromPath;
34155
34811
  if (!slug) {
34156
34812
  return {
@@ -34239,9 +34895,9 @@ async function reconcileContextDocConflict(args) {
34239
34895
  let fileSlug;
34240
34896
  try {
34241
34897
  const rel = relative5(workspaceMirrorPath(workspaceSlug), absolutePath);
34242
- fileSlug = strategy.parseMirrorPath(rel)?.slug ?? basename4(absolutePath, ".md");
34898
+ fileSlug = strategy.parseMirrorPath(rel)?.slug ?? basename5(absolutePath, ".md");
34243
34899
  } catch {
34244
- fileSlug = basename4(absolutePath, ".md");
34900
+ fileSlug = basename5(absolutePath, ".md");
34245
34901
  }
34246
34902
  if (fileSlug !== existingSlug) {
34247
34903
  const stashPath = stashConflict({
@@ -34997,7 +35653,7 @@ async function runPushDelete(args) {
34997
35653
  const rel = relative5(workspaceMirrorPath(args.workspaceSlug), args.absolutePath);
34998
35654
  parsedSlug = strategy.parseMirrorPath(rel)?.slug ?? null;
34999
35655
  } catch {}
35000
- const lookupSlug = parsedSlug ?? basename4(args.absolutePath, ".md");
35656
+ const lookupSlug = parsedSlug ?? basename5(args.absolutePath, ".md");
35001
35657
  const entry2 = getEntryBySlug(args.state, strategy.type, lookupSlug);
35002
35658
  if (entry2) {
35003
35659
  id = entry2.id;
@@ -35096,9 +35752,9 @@ async function pushRename(args) {
35096
35752
  let toSlug;
35097
35753
  try {
35098
35754
  const rel = relative5(workspaceMirrorPath(workspaceSlug), toPath);
35099
- toSlug = strategy.parseMirrorPath(rel)?.slug ?? basename4(toPath, ".md");
35755
+ toSlug = strategy.parseMirrorPath(rel)?.slug ?? basename5(toPath, ".md");
35100
35756
  } catch {
35101
- toSlug = basename4(toPath, ".md");
35757
+ toSlug = basename5(toPath, ".md");
35102
35758
  }
35103
35759
  return mutex.run(id, async () => {
35104
35760
  const live = getEntry(state, entityType, id);
@@ -35430,7 +36086,7 @@ function opPath(workspaceSlug, op) {
35430
36086
  }
35431
36087
 
35432
36088
  // src/lib/files/classify.ts
35433
- import { relative as relative6, sep as sep4 } from "node:path";
36089
+ import { relative as relative6, sep as sep5 } from "node:path";
35434
36090
  var FILES_SUBTREE = "files";
35435
36091
  function classifyFilesPath(args) {
35436
36092
  let root;
@@ -35440,20 +36096,20 @@ function classifyFilesPath(args) {
35440
36096
  return null;
35441
36097
  }
35442
36098
  const rel = relative6(root, args.absolutePath);
35443
- if (rel.startsWith("..") || rel.startsWith(sep4))
36099
+ if (rel.startsWith("..") || rel.startsWith(sep5))
35444
36100
  return null;
35445
- const prefix = FILES_SUBTREE + sep4;
36101
+ const prefix = FILES_SUBTREE + sep5;
35446
36102
  if (!rel.startsWith(prefix))
35447
36103
  return null;
35448
36104
  const sub = rel.slice(prefix.length);
35449
36105
  if (sub.length === 0)
35450
36106
  return null;
35451
- const posix = sep4 === "/" ? sub : sub.split(sep4).join("/");
36107
+ const posix = sep5 === "/" ? sub : sub.split(sep5).join("/");
35452
36108
  return validateFilesRelPath(posix) ? { relPath: posix } : null;
35453
36109
  }
35454
36110
 
35455
36111
  // src/lib/memory-facts/sync.ts
35456
- import { isAbsolute as isAbsolute2, relative as relative7, sep as sep5 } from "node:path";
36112
+ import { isAbsolute as isAbsolute2, relative as relative7, sep as sep6 } from "node:path";
35457
36113
 
35458
36114
  // src/lib/memory-facts/api.ts
35459
36115
  var FactCommonSchema = exports_external.object({
@@ -35774,7 +36430,7 @@ function classifyMemoryFactPath(args) {
35774
36430
  const rel = relative7(root, args.absolutePath);
35775
36431
  if (rel === "" || rel.startsWith("..") || isAbsolute2(rel))
35776
36432
  return null;
35777
- const mirrorRel = `${MEMORY_FACTS_DIR}/${rel.split(sep5).join("/")}`;
36433
+ const mirrorRel = `${MEMORY_FACTS_DIR}/${rel.split(sep6).join("/")}`;
35778
36434
  return { relPath: mirrorRel, fact: parseMemoryFactRelPath(mirrorRel) };
35779
36435
  }
35780
36436
  function classifyMemoryFactEvent(args) {
@@ -35933,7 +36589,7 @@ class FileDestructiveGate {
35933
36589
  import { readFileSync as readFileSync19, statSync as statSync10 } from "node:fs";
35934
36590
 
35935
36591
  // src/lib/unsynced.ts
35936
- import { join as join12, relative as relative8 } from "node:path";
36592
+ import { join as join13, relative as relative8 } from "node:path";
35937
36593
  var RECORDABLE_REASONS = new Set([
35938
36594
  "rate_limit",
35939
36595
  "server",
@@ -35995,7 +36651,7 @@ async function drainUnsyncedOps(args) {
35995
36651
  attempted += 1;
35996
36652
  try {
35997
36653
  if (op.target === "entity") {
35998
- const absolutePath = join12(workspaceMirrorPath(workspaceSlug), op.path);
36654
+ const absolutePath = join13(workspaceMirrorPath(workspaceSlug), op.path);
35999
36655
  const classified = classifyMirrorPath({ workspaceSlug, absolutePath });
36000
36656
  if (!classified) {
36001
36657
  clear("entity", op.path);
@@ -36240,10 +36896,10 @@ class ReaddirpStream extends Readable {
36240
36896
  }
36241
36897
  async _formatEntry(dirent, path5) {
36242
36898
  let entry2;
36243
- const basename5 = this._isDirent ? dirent.name : dirent;
36899
+ const basename6 = this._isDirent ? dirent.name : dirent;
36244
36900
  try {
36245
- const fullPath = presolve(pjoin(path5, basename5));
36246
- entry2 = { path: prelative(this._root, fullPath), fullPath, basename: basename5 };
36901
+ const fullPath = presolve(pjoin(path5, basename6));
36902
+ entry2 = { path: prelative(this._root, fullPath), fullPath, basename: basename6 };
36247
36903
  entry2[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
36248
36904
  } catch (err) {
36249
36905
  this._onError(err);
@@ -36770,9 +37426,9 @@ class NodeFsHandler {
36770
37426
  _watchWithNodeFs(path5, listener) {
36771
37427
  const opts = this.fsw.options;
36772
37428
  const directory = sp.dirname(path5);
36773
- const basename6 = sp.basename(path5);
37429
+ const basename7 = sp.basename(path5);
36774
37430
  const parent = this.fsw._getWatchedDir(directory);
36775
- parent.add(basename6);
37431
+ parent.add(basename7);
36776
37432
  const absolutePath = sp.resolve(path5);
36777
37433
  const options2 = {
36778
37434
  persistent: opts.persistent
@@ -36782,7 +37438,7 @@ class NodeFsHandler {
36782
37438
  let closer;
36783
37439
  if (opts.usePolling) {
36784
37440
  const enableBin = opts.interval !== opts.binaryInterval;
36785
- options2.interval = enableBin && isBinaryPath(basename6) ? opts.binaryInterval : opts.interval;
37441
+ options2.interval = enableBin && isBinaryPath(basename7) ? opts.binaryInterval : opts.interval;
36786
37442
  closer = setFsWatchFileListener(path5, absolutePath, options2, {
36787
37443
  listener,
36788
37444
  rawEmitter: this.fsw._emitRaw
@@ -36800,11 +37456,11 @@ class NodeFsHandler {
36800
37456
  if (this.fsw.closed) {
36801
37457
  return;
36802
37458
  }
36803
- const dirname10 = sp.dirname(file2);
36804
- const basename6 = sp.basename(file2);
36805
- const parent = this.fsw._getWatchedDir(dirname10);
37459
+ const dirname11 = sp.dirname(file2);
37460
+ const basename7 = sp.basename(file2);
37461
+ const parent = this.fsw._getWatchedDir(dirname11);
36806
37462
  let prevStats = stats;
36807
- if (parent.has(basename6))
37463
+ if (parent.has(basename7))
36808
37464
  return;
36809
37465
  const listener = async (path5, newStats) => {
36810
37466
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
@@ -36829,9 +37485,9 @@ class NodeFsHandler {
36829
37485
  prevStats = newStats2;
36830
37486
  }
36831
37487
  } catch (error52) {
36832
- this.fsw._remove(dirname10, basename6);
37488
+ this.fsw._remove(dirname11, basename7);
36833
37489
  }
36834
- } else if (parent.has(basename6)) {
37490
+ } else if (parent.has(basename7)) {
36835
37491
  const at = newStats.atimeMs;
36836
37492
  const mt = newStats.mtimeMs;
36837
37493
  if (!at || at <= mt || mt !== prevStats.mtimeMs) {
@@ -36918,7 +37574,7 @@ class NodeFsHandler {
36918
37574
  this._addToNodeFs(path5, initialAdd, wh, depth + 1);
36919
37575
  }
36920
37576
  }).on(EV.ERROR, this._boundHandleError);
36921
- return new Promise((resolve4, reject) => {
37577
+ return new Promise((resolve5, reject) => {
36922
37578
  if (!stream)
36923
37579
  return reject();
36924
37580
  stream.once(STR_END, () => {
@@ -36927,7 +37583,7 @@ class NodeFsHandler {
36927
37583
  return;
36928
37584
  }
36929
37585
  const wasThrottled = throttler ? throttler.clear() : false;
36930
- resolve4(undefined);
37586
+ resolve5(undefined);
36931
37587
  previous.getChildren().filter((item) => {
36932
37588
  return item !== directory && !current.has(item);
36933
37589
  }).forEach((item) => {
@@ -37686,7 +38342,7 @@ var chokidar_default = { watch, FSWatcher };
37686
38342
 
37687
38343
  // src/lib/watcher.ts
37688
38344
  import { statSync as statSync9 } from "node:fs";
37689
- import { sep as sep6 } from "node:path";
38345
+ import { sep as sep7 } from "node:path";
37690
38346
 
37691
38347
  // src/lib/rename-classifier.ts
37692
38348
  class RenameClassifier {
@@ -37817,7 +38473,7 @@ function watcherIgnoreMatcher(workspaceRoot) {
37817
38473
  return (absolutePath) => patterns.some((re) => re.test(absolutePath));
37818
38474
  }
37819
38475
  function escSep() {
37820
- return sep6 === "/" ? "/" : "\\\\";
38476
+ return sep7 === "/" ? "/" : "\\\\";
37821
38477
  }
37822
38478
 
37823
38479
  class DebounceMap {
@@ -41474,7 +42130,7 @@ class Semaphore {
41474
42130
  this.active += 1;
41475
42131
  return;
41476
42132
  }
41477
- await new Promise((resolve5) => this.waiters.push(resolve5));
42133
+ await new Promise((resolve6) => this.waiters.push(resolve6));
41478
42134
  }
41479
42135
  release() {
41480
42136
  const next = this.waiters.shift();
@@ -41541,11 +42197,11 @@ import {
41541
42197
  statSync as statSync16,
41542
42198
  unlinkSync as unlinkSync8
41543
42199
  } from "node:fs";
41544
- import { join as join16 } from "node:path";
42200
+ import { join as join17 } from "node:path";
41545
42201
 
41546
42202
  // src/lib/conflicts-view.ts
41547
42203
  import { existsSync as existsSync6 } from "node:fs";
41548
- import { join as join15 } from "node:path";
42204
+ import { join as join16 } from "node:path";
41549
42205
  var NO_GENERATED_MEMORY = {
41550
42206
  artistMemoryGenerated: () => false,
41551
42207
  workspaceMemoryGenerated: () => false,
@@ -41591,7 +42247,7 @@ function resolveConflictRows(workspaceSlug, stashes, generatedMemory = NO_GENERA
41591
42247
  if (validateFilesRelPath(rel) === null) {
41592
42248
  return { kind: "unsafe-path", stash };
41593
42249
  }
41594
- const abs = join15(root, "files", rel);
42250
+ const abs = join16(root, "files", rel);
41595
42251
  if (hasSymlinkedComponent(workspaceSlug, abs)) {
41596
42252
  return { kind: "unsafe-path", stash };
41597
42253
  }
@@ -41724,7 +42380,7 @@ function refreshConflictsView(workspaceSlug) {
41724
42380
  import { existsSync as existsSync7, readFileSync as readFileSync23, statSync as statSync14 } from "node:fs";
41725
42381
 
41726
42382
  // src/lib/files/extracted-text.ts
41727
- import { createHash as createHash3 } from "node:crypto";
42383
+ import { createHash as createHash4 } from "node:crypto";
41728
42384
  var DERIVED_TEXT_VERSION = 2;
41729
42385
  function yamlString3(value) {
41730
42386
  return JSON.stringify(value);
@@ -41798,7 +42454,7 @@ ${doc2.text}
41798
42454
  `;
41799
42455
  }
41800
42456
  function extractedTextHash(rendered) {
41801
- return createHash3("sha256").update(rendered, "utf8").digest("hex");
42457
+ return createHash4("sha256").update(rendered, "utf8").digest("hex");
41802
42458
  }
41803
42459
 
41804
42460
  // src/lib/files/pull.ts
@@ -42417,7 +43073,7 @@ function hasExistingContent(workspacePath) {
42417
43073
  if (!e.isDirectory())
42418
43074
  return true;
42419
43075
  try {
42420
- return readdirSync7(join16(workspacePath, e.name)).length > 0;
43076
+ return readdirSync7(join17(workspacePath, e.name)).length > 0;
42421
43077
  } catch {
42422
43078
  return true;
42423
43079
  }
@@ -44596,12 +45252,12 @@ async function runStart(workspaceSlug, deps = {}) {
44596
45252
  try {
44597
45253
  await Promise.race([
44598
45254
  watcher.drainPending().then(() => Promise.all([gate.drain(), fileGate.drain()])),
44599
- new Promise((resolve5) => setTimeout(() => resolve5(-1), SHUTDOWN_DRAIN_TIMEOUT_MS))
45255
+ new Promise((resolve6) => setTimeout(() => resolve6(-1), SHUTDOWN_DRAIN_TIMEOUT_MS))
44600
45256
  ]);
44601
45257
  } finally {
44602
45258
  await Promise.race([
44603
45259
  watcher.stop(),
44604
- new Promise((resolve5) => setTimeout(resolve5, SHUTDOWN_DRAIN_TIMEOUT_MS))
45260
+ new Promise((resolve6) => setTimeout(resolve6, SHUTDOWN_DRAIN_TIMEOUT_MS))
44605
45261
  ]);
44606
45262
  clearDaemonPid(slug);
44607
45263
  releaseDaemonLock(lockHandle);
@@ -45157,11 +45813,11 @@ function assessContextWalls(workspaceSlug, deps = {}) {
45157
45813
  // src/lib/build-stamp.ts
45158
45814
  import { execFileSync as execFileSync4 } from "node:child_process";
45159
45815
  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";
45816
+ import { dirname as dirname12, join as join18 } from "node:path";
45161
45817
  import { fileURLToPath } from "node:url";
45162
45818
  var BUILD_STAMP_FILENAME = "build-stamp.json";
45163
45819
  function stampPath(distDir) {
45164
- return join17(distDir, BUILD_STAMP_FILENAME);
45820
+ return join18(distDir, BUILD_STAMP_FILENAME);
45165
45821
  }
45166
45822
  function readHead(repoDir) {
45167
45823
  try {
@@ -45192,9 +45848,9 @@ function readBuildStamp(distDir) {
45192
45848
  function findRepoRoot(fromDir) {
45193
45849
  let dir = fromDir;
45194
45850
  for (;; ) {
45195
- if (existsSync10(join17(dir, ".git")))
45851
+ if (existsSync10(join18(dir, ".git")))
45196
45852
  return dir;
45197
- const parent = dirname11(dir);
45853
+ const parent = dirname12(dir);
45198
45854
  if (parent === dir)
45199
45855
  return null;
45200
45856
  dir = parent;
@@ -45218,7 +45874,7 @@ function checkBuildStaleness(deps = {}) {
45218
45874
  const metaUrl = deps.metaUrl ?? import.meta.url;
45219
45875
  let distDir;
45220
45876
  try {
45221
- distDir = dirname11(fileURLToPath(metaUrl));
45877
+ distDir = dirname12(fileURLToPath(metaUrl));
45222
45878
  } catch {
45223
45879
  return { kind: "unknown" };
45224
45880
  }
@@ -45242,7 +45898,7 @@ function checkBuildStaleness(deps = {}) {
45242
45898
 
45243
45899
  // src/lib/memory-links.ts
45244
45900
  import { readFileSync as readFileSync28 } from "node:fs";
45245
- import { relative as relative15, sep as sep7 } from "node:path";
45901
+ import { relative as relative15, sep as sep8 } from "node:path";
45246
45902
  var MEMORY_FILE_RE = /^(workspace-memory\.md|user-memory\.md|artists\/[^/]+\/memory\.md|memory\/[^/]+\.md|memory\/private\/[^/]+\.md)$/i;
45247
45903
  function scanMemoryLinks(deps) {
45248
45904
  const listFiles = deps.listFiles ?? ((r) => walkSubtreeFiles(r, isVcsInternal));
@@ -45255,7 +45911,7 @@ function scanMemoryLinks(deps) {
45255
45911
  } catch {
45256
45912
  return { scanned: 0, unreadable: [], dead: [] };
45257
45913
  }
45258
- const relPaths = absPaths.map((p) => relative15(root, p).split(sep7).join("/"));
45914
+ const relPaths = absPaths.map((p) => relative15(root, p).split(sep8).join("/"));
45259
45915
  const artists = buildArtistIndex(relPaths, root, (abs) => readFile(abs));
45260
45916
  const dead = [];
45261
45917
  const unreadable = [];
@@ -46321,7 +46977,7 @@ async function callVoiceGate(req) {
46321
46977
  }
46322
46978
 
46323
46979
  // src/lib/voice-gate/attempts.ts
46324
- import { createHash as createHash4 } from "node:crypto";
46980
+ import { createHash as createHash5 } from "node:crypto";
46325
46981
  import {
46326
46982
  mkdirSync as mkdirSync12,
46327
46983
  readFileSync as readFileSync30,
@@ -46329,7 +46985,7 @@ import {
46329
46985
  unlinkSync as unlinkSync9,
46330
46986
  writeFileSync as writeFileSync9
46331
46987
  } from "node:fs";
46332
- import { join as join18 } from "node:path";
46988
+ import { join as join19 } from "node:path";
46333
46989
  var MAX_REGENS = 2;
46334
46990
  var ENTRY_TTL_MS = 24 * 60 * 60 * 1000;
46335
46991
  var AttemptEntrySchema = exports_external.object({
@@ -46342,13 +46998,13 @@ var AttemptsFileSchema = exports_external.object({
46342
46998
  entries: exports_external.record(exports_external.string(), AttemptEntrySchema)
46343
46999
  });
46344
47000
  function attemptsDir(workspaceSlug) {
46345
- return join18(plinthHome(), "_voice_gate", workspaceSlug);
47001
+ return join19(plinthHome(), "_voice_gate", workspaceSlug);
46346
47002
  }
46347
47003
  function attemptsPath(workspaceSlug) {
46348
- return join18(attemptsDir(workspaceSlug), "attempts.json");
47004
+ return join19(attemptsDir(workspaceSlug), "attempts.json");
46349
47005
  }
46350
47006
  function attemptKey(identity) {
46351
- return createHash4("sha256").update(identity, "utf8").digest("hex").slice(0, 32);
47007
+ return createHash5("sha256").update(identity, "utf8").digest("hex").slice(0, 32);
46352
47008
  }
46353
47009
  function emptyFile() {
46354
47010
  return { version: 1, entries: {} };
@@ -46520,7 +47176,7 @@ function denyUngated(detail) {
46520
47176
  // src/lib/voice-gate/payload.ts
46521
47177
  import { readFileSync as readFileSync31, statSync as statSync20 } from "node:fs";
46522
47178
  import { homedir as homedir2 } from "node:os";
46523
- import { isAbsolute as isAbsolute4, resolve as resolve5 } from "node:path";
47179
+ import { isAbsolute as isAbsolute4, resolve as resolve6 } from "node:path";
46524
47180
  var MAX_BODY_BYTES = 256 * 1024;
46525
47181
  var HELPER_BASENAME = "push_gmail_draft.py";
46526
47182
  var DRAFT_FLAGS = ["--to", "--body-file", "--body-stdin"];
@@ -46714,13 +47370,13 @@ function applyCd(tokens, state) {
46714
47370
  return { dir: expanded, known: true };
46715
47371
  if (!state.known)
46716
47372
  return state;
46717
- return { dir: resolve5(state.dir, expanded), known: true };
47373
+ return { dir: resolve6(state.dir, expanded), known: true };
46718
47374
  }
46719
47375
  function expandHome(path5) {
46720
47376
  if (path5 === "~")
46721
47377
  return homedir2();
46722
47378
  if (path5.startsWith("~/"))
46723
- return resolve5(homedir2(), path5.slice(2));
47379
+ return resolve6(homedir2(), path5.slice(2));
46724
47380
  return path5;
46725
47381
  }
46726
47382
  function classifyHelperSegment(tokens, dirState, readBodyFile) {
@@ -46746,7 +47402,7 @@ function classifyHelperSegment(tokens, dirState, readBodyFile) {
46746
47402
  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
47403
  };
46748
47404
  }
46749
- const resolved = isAbsolute4(expanded) ? expanded : resolve5(dirState.dir, expanded);
47405
+ const resolved = isAbsolute4(expanded) ? expanded : resolve6(dirState.dir, expanded);
46750
47406
  let body;
46751
47407
  try {
46752
47408
  body = readBodyFile(resolved);