@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/CHANGELOG.md +32 -0
- package/README.md +1 -1
- package/dist/build-stamp.json +2 -2
- package/dist/cli.js +750 -94
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -7584,7 +7584,7 @@ function _getBuiltinFlags(long, short, userNames, userAliases) {
|
|
|
7584
7584
|
// package.json
|
|
7585
7585
|
var package_default = {
|
|
7586
7586
|
name: "@plinth-music/cli",
|
|
7587
|
-
version: "0.
|
|
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: "
|
|
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
|
|
30718
|
-
owner: "
|
|
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 = [
|
|
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
|
-
|
|
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
|
|
32143
|
+
closeSync as closeSync3,
|
|
31488
32144
|
mkdirSync as mkdirSync8,
|
|
31489
|
-
openSync as
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 = `${
|
|
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(
|
|
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 =
|
|
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
|
|
32369
|
+
return join10(plinthHome(), "_memory_gate", workspaceSlug);
|
|
31714
32370
|
}
|
|
31715
32371
|
function memoryGateLogPath(workspaceSlug) {
|
|
31716
|
-
return
|
|
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 =
|
|
32405
|
+
const fd = openSync3(path3, "r");
|
|
31750
32406
|
try {
|
|
31751
32407
|
const last = Buffer.alloc(1);
|
|
31752
|
-
|
|
32408
|
+
readSync2(fd, last, 0, 1, size - 1);
|
|
31753
32409
|
return last[0] !== 10;
|
|
31754
32410
|
} finally {
|
|
31755
|
-
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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 =
|
|
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
|
|
33920
|
+
import { dirname as dirname9, join as join12 } from "node:path";
|
|
33265
33921
|
function conflictsRoot(workspaceSlug) {
|
|
33266
|
-
return
|
|
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
|
|
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(
|
|
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
|
|
33939
|
+
return join12(conflictsRoot(workspaceSlug), `files.${safe}.${iso}.${side}`);
|
|
33284
33940
|
}
|
|
33285
33941
|
function stashFileConflict(args) {
|
|
33286
33942
|
const target = fileConflictPath(args);
|
|
33287
|
-
mkdirSync10(
|
|
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 =
|
|
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
|
|
34005
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
33350
34006
|
function sha256Bytes(bytes) {
|
|
33351
|
-
return
|
|
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
|
|
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 ??
|
|
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 ??
|
|
34898
|
+
fileSlug = strategy.parseMirrorPath(rel)?.slug ?? basename5(absolutePath, ".md");
|
|
34243
34899
|
} catch {
|
|
34244
|
-
fileSlug =
|
|
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 ??
|
|
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 ??
|
|
35755
|
+
toSlug = strategy.parseMirrorPath(rel)?.slug ?? basename5(toPath, ".md");
|
|
35100
35756
|
} catch {
|
|
35101
|
-
toSlug =
|
|
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
|
|
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(
|
|
36099
|
+
if (rel.startsWith("..") || rel.startsWith(sep5))
|
|
35444
36100
|
return null;
|
|
35445
|
-
const prefix = FILES_SUBTREE +
|
|
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 =
|
|
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
|
|
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(
|
|
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
|
|
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 =
|
|
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
|
|
36899
|
+
const basename6 = this._isDirent ? dirent.name : dirent;
|
|
36244
36900
|
try {
|
|
36245
|
-
const fullPath = presolve(pjoin(path5,
|
|
36246
|
-
entry2 = { path: prelative(this._root, fullPath), fullPath, basename:
|
|
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
|
|
37429
|
+
const basename7 = sp.basename(path5);
|
|
36774
37430
|
const parent = this.fsw._getWatchedDir(directory);
|
|
36775
|
-
parent.add(
|
|
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(
|
|
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
|
|
36804
|
-
const
|
|
36805
|
-
const parent = this.fsw._getWatchedDir(
|
|
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(
|
|
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(
|
|
37488
|
+
this.fsw._remove(dirname11, basename7);
|
|
36833
37489
|
}
|
|
36834
|
-
} else if (parent.has(
|
|
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((
|
|
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
|
-
|
|
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
|
|
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
|
|
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((
|
|
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
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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(
|
|
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((
|
|
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((
|
|
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
|
|
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
|
|
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(
|
|
45851
|
+
if (existsSync10(join18(dir, ".git")))
|
|
45196
45852
|
return dir;
|
|
45197
|
-
const parent =
|
|
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 =
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
47001
|
+
return join19(plinthHome(), "_voice_gate", workspaceSlug);
|
|
46346
47002
|
}
|
|
46347
47003
|
function attemptsPath(workspaceSlug) {
|
|
46348
|
-
return
|
|
47004
|
+
return join19(attemptsDir(workspaceSlug), "attempts.json");
|
|
46349
47005
|
}
|
|
46350
47006
|
function attemptKey(identity) {
|
|
46351
|
-
return
|
|
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
|
|
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:
|
|
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
|
|
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 :
|
|
47405
|
+
const resolved = isAbsolute4(expanded) ? expanded : resolve6(dirState.dir, expanded);
|
|
46750
47406
|
let body;
|
|
46751
47407
|
try {
|
|
46752
47408
|
body = readBodyFile(resolved);
|