@plinth-music/cli 0.20.0 → 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 +56 -2
- package/README.md +1 -1
- package/dist/build-stamp.json +2 -2
- package/dist/cli.js +761 -101
- 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({
|
|
@@ -35547,6 +36203,10 @@ function isGeneratedMemoryStash(label, deps) {
|
|
|
35547
36203
|
|
|
35548
36204
|
// src/lib/memory-facts/refuse.ts
|
|
35549
36205
|
function refuseGeneratedMemoryEdit(args) {
|
|
36206
|
+
if (args.localContent === args.canonicalBody) {
|
|
36207
|
+
args.writeCanonical(args.canonicalBody);
|
|
36208
|
+
return { state: args.state, stashPath: null };
|
|
36209
|
+
}
|
|
35550
36210
|
const stashPath = stashConflict({
|
|
35551
36211
|
workspaceSlug: args.workspaceSlug,
|
|
35552
36212
|
entityType: args.conflictEntity,
|
|
@@ -35770,7 +36430,7 @@ function classifyMemoryFactPath(args) {
|
|
|
35770
36430
|
const rel = relative7(root, args.absolutePath);
|
|
35771
36431
|
if (rel === "" || rel.startsWith("..") || isAbsolute2(rel))
|
|
35772
36432
|
return null;
|
|
35773
|
-
const mirrorRel = `${MEMORY_FACTS_DIR}/${rel.split(
|
|
36433
|
+
const mirrorRel = `${MEMORY_FACTS_DIR}/${rel.split(sep6).join("/")}`;
|
|
35774
36434
|
return { relPath: mirrorRel, fact: parseMemoryFactRelPath(mirrorRel) };
|
|
35775
36435
|
}
|
|
35776
36436
|
function classifyMemoryFactEvent(args) {
|
|
@@ -35929,7 +36589,7 @@ class FileDestructiveGate {
|
|
|
35929
36589
|
import { readFileSync as readFileSync19, statSync as statSync10 } from "node:fs";
|
|
35930
36590
|
|
|
35931
36591
|
// src/lib/unsynced.ts
|
|
35932
|
-
import { join as
|
|
36592
|
+
import { join as join13, relative as relative8 } from "node:path";
|
|
35933
36593
|
var RECORDABLE_REASONS = new Set([
|
|
35934
36594
|
"rate_limit",
|
|
35935
36595
|
"server",
|
|
@@ -35991,7 +36651,7 @@ async function drainUnsyncedOps(args) {
|
|
|
35991
36651
|
attempted += 1;
|
|
35992
36652
|
try {
|
|
35993
36653
|
if (op.target === "entity") {
|
|
35994
|
-
const absolutePath =
|
|
36654
|
+
const absolutePath = join13(workspaceMirrorPath(workspaceSlug), op.path);
|
|
35995
36655
|
const classified = classifyMirrorPath({ workspaceSlug, absolutePath });
|
|
35996
36656
|
if (!classified) {
|
|
35997
36657
|
clear("entity", op.path);
|
|
@@ -36236,10 +36896,10 @@ class ReaddirpStream extends Readable {
|
|
|
36236
36896
|
}
|
|
36237
36897
|
async _formatEntry(dirent, path5) {
|
|
36238
36898
|
let entry2;
|
|
36239
|
-
const
|
|
36899
|
+
const basename6 = this._isDirent ? dirent.name : dirent;
|
|
36240
36900
|
try {
|
|
36241
|
-
const fullPath = presolve(pjoin(path5,
|
|
36242
|
-
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 };
|
|
36243
36903
|
entry2[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
36244
36904
|
} catch (err) {
|
|
36245
36905
|
this._onError(err);
|
|
@@ -36766,9 +37426,9 @@ class NodeFsHandler {
|
|
|
36766
37426
|
_watchWithNodeFs(path5, listener) {
|
|
36767
37427
|
const opts = this.fsw.options;
|
|
36768
37428
|
const directory = sp.dirname(path5);
|
|
36769
|
-
const
|
|
37429
|
+
const basename7 = sp.basename(path5);
|
|
36770
37430
|
const parent = this.fsw._getWatchedDir(directory);
|
|
36771
|
-
parent.add(
|
|
37431
|
+
parent.add(basename7);
|
|
36772
37432
|
const absolutePath = sp.resolve(path5);
|
|
36773
37433
|
const options2 = {
|
|
36774
37434
|
persistent: opts.persistent
|
|
@@ -36778,7 +37438,7 @@ class NodeFsHandler {
|
|
|
36778
37438
|
let closer;
|
|
36779
37439
|
if (opts.usePolling) {
|
|
36780
37440
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
36781
|
-
options2.interval = enableBin && isBinaryPath(
|
|
37441
|
+
options2.interval = enableBin && isBinaryPath(basename7) ? opts.binaryInterval : opts.interval;
|
|
36782
37442
|
closer = setFsWatchFileListener(path5, absolutePath, options2, {
|
|
36783
37443
|
listener,
|
|
36784
37444
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -36796,11 +37456,11 @@ class NodeFsHandler {
|
|
|
36796
37456
|
if (this.fsw.closed) {
|
|
36797
37457
|
return;
|
|
36798
37458
|
}
|
|
36799
|
-
const
|
|
36800
|
-
const
|
|
36801
|
-
const parent = this.fsw._getWatchedDir(
|
|
37459
|
+
const dirname11 = sp.dirname(file2);
|
|
37460
|
+
const basename7 = sp.basename(file2);
|
|
37461
|
+
const parent = this.fsw._getWatchedDir(dirname11);
|
|
36802
37462
|
let prevStats = stats;
|
|
36803
|
-
if (parent.has(
|
|
37463
|
+
if (parent.has(basename7))
|
|
36804
37464
|
return;
|
|
36805
37465
|
const listener = async (path5, newStats) => {
|
|
36806
37466
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
|
|
@@ -36825,9 +37485,9 @@ class NodeFsHandler {
|
|
|
36825
37485
|
prevStats = newStats2;
|
|
36826
37486
|
}
|
|
36827
37487
|
} catch (error52) {
|
|
36828
|
-
this.fsw._remove(
|
|
37488
|
+
this.fsw._remove(dirname11, basename7);
|
|
36829
37489
|
}
|
|
36830
|
-
} else if (parent.has(
|
|
37490
|
+
} else if (parent.has(basename7)) {
|
|
36831
37491
|
const at = newStats.atimeMs;
|
|
36832
37492
|
const mt = newStats.mtimeMs;
|
|
36833
37493
|
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
@@ -36914,7 +37574,7 @@ class NodeFsHandler {
|
|
|
36914
37574
|
this._addToNodeFs(path5, initialAdd, wh, depth + 1);
|
|
36915
37575
|
}
|
|
36916
37576
|
}).on(EV.ERROR, this._boundHandleError);
|
|
36917
|
-
return new Promise((
|
|
37577
|
+
return new Promise((resolve5, reject) => {
|
|
36918
37578
|
if (!stream)
|
|
36919
37579
|
return reject();
|
|
36920
37580
|
stream.once(STR_END, () => {
|
|
@@ -36923,7 +37583,7 @@ class NodeFsHandler {
|
|
|
36923
37583
|
return;
|
|
36924
37584
|
}
|
|
36925
37585
|
const wasThrottled = throttler ? throttler.clear() : false;
|
|
36926
|
-
|
|
37586
|
+
resolve5(undefined);
|
|
36927
37587
|
previous.getChildren().filter((item) => {
|
|
36928
37588
|
return item !== directory && !current.has(item);
|
|
36929
37589
|
}).forEach((item) => {
|
|
@@ -37682,7 +38342,7 @@ var chokidar_default = { watch, FSWatcher };
|
|
|
37682
38342
|
|
|
37683
38343
|
// src/lib/watcher.ts
|
|
37684
38344
|
import { statSync as statSync9 } from "node:fs";
|
|
37685
|
-
import { sep as
|
|
38345
|
+
import { sep as sep7 } from "node:path";
|
|
37686
38346
|
|
|
37687
38347
|
// src/lib/rename-classifier.ts
|
|
37688
38348
|
class RenameClassifier {
|
|
@@ -37813,7 +38473,7 @@ function watcherIgnoreMatcher(workspaceRoot) {
|
|
|
37813
38473
|
return (absolutePath) => patterns.some((re) => re.test(absolutePath));
|
|
37814
38474
|
}
|
|
37815
38475
|
function escSep() {
|
|
37816
|
-
return
|
|
38476
|
+
return sep7 === "/" ? "/" : "\\\\";
|
|
37817
38477
|
}
|
|
37818
38478
|
|
|
37819
38479
|
class DebounceMap {
|
|
@@ -38398,7 +39058,7 @@ async function pushArtistMemory(args) {
|
|
|
38398
39058
|
};
|
|
38399
39059
|
return {
|
|
38400
39060
|
state: persistEntry2(refused.state, stamped),
|
|
38401
|
-
outcome: { kind: "generated_refused", slug, stashPath: refused.stashPath }
|
|
39061
|
+
outcome: refused.stashPath === null ? { kind: "noop", slug } : { kind: "generated_refused", slug, stashPath: refused.stashPath }
|
|
38402
39062
|
};
|
|
38403
39063
|
}
|
|
38404
39064
|
const acked = entry2.memory_hash;
|
|
@@ -40829,7 +41489,7 @@ async function pushWorkspaceMemory(args) {
|
|
|
40829
41489
|
});
|
|
40830
41490
|
return {
|
|
40831
41491
|
state: next2,
|
|
40832
|
-
outcome: { kind: "generated_refused", stashPath: refused.stashPath }
|
|
41492
|
+
outcome: refused.stashPath === null ? { kind: "noop" } : { kind: "generated_refused", stashPath: refused.stashPath }
|
|
40833
41493
|
};
|
|
40834
41494
|
}
|
|
40835
41495
|
const gate = applySecretGate({
|
|
@@ -40897,7 +41557,7 @@ async function pushWorkspaceMemory(args) {
|
|
|
40897
41557
|
});
|
|
40898
41558
|
return {
|
|
40899
41559
|
state: next2,
|
|
40900
|
-
outcome: { kind: "generated_refused", stashPath: refused.stashPath }
|
|
41560
|
+
outcome: refused.stashPath === null ? { kind: "noop" } : { kind: "generated_refused", stashPath: refused.stashPath }
|
|
40901
41561
|
};
|
|
40902
41562
|
}
|
|
40903
41563
|
{
|
|
@@ -40946,7 +41606,7 @@ async function pushWorkspaceMemory(args) {
|
|
|
40946
41606
|
});
|
|
40947
41607
|
return {
|
|
40948
41608
|
state: next2,
|
|
40949
|
-
outcome: { kind: "generated_refused", stashPath: refused.stashPath }
|
|
41609
|
+
outcome: refused.stashPath === null ? { kind: "noop" } : { kind: "generated_refused", stashPath: refused.stashPath }
|
|
40950
41610
|
};
|
|
40951
41611
|
}
|
|
40952
41612
|
}
|
|
@@ -41221,7 +41881,7 @@ async function pushSingleton(descriptor, args) {
|
|
|
41221
41881
|
const next2 = persist2(descriptor, refused.state, ackedFrom(cloud, stableHash(cloud.body_md)));
|
|
41222
41882
|
return {
|
|
41223
41883
|
state: next2,
|
|
41224
|
-
outcome: { kind: "generated_refused", stashPath: refused.stashPath }
|
|
41884
|
+
outcome: refused.stashPath === null ? { kind: "noop" } : { kind: "generated_refused", stashPath: refused.stashPath }
|
|
41225
41885
|
};
|
|
41226
41886
|
}
|
|
41227
41887
|
let gated = state;
|
|
@@ -41284,7 +41944,7 @@ async function pushSingleton(descriptor, args) {
|
|
|
41284
41944
|
const next2 = persist2(descriptor, refused.state, ackedFrom(cloud, stableHash(cloud.body_md)));
|
|
41285
41945
|
return {
|
|
41286
41946
|
state: next2,
|
|
41287
|
-
outcome: { kind: "generated_refused", stashPath: refused.stashPath }
|
|
41947
|
+
outcome: refused.stashPath === null ? { kind: "noop" } : { kind: "generated_refused", stashPath: refused.stashPath }
|
|
41288
41948
|
};
|
|
41289
41949
|
}
|
|
41290
41950
|
{
|
|
@@ -41325,7 +41985,7 @@ async function pushSingleton(descriptor, args) {
|
|
|
41325
41985
|
const next2 = persist2(descriptor, refused.state, ackedFrom(cloud, stableHash(cloud.body_md)));
|
|
41326
41986
|
return {
|
|
41327
41987
|
state: next2,
|
|
41328
|
-
outcome: { kind: "generated_refused", stashPath: refused.stashPath }
|
|
41988
|
+
outcome: refused.stashPath === null ? { kind: "noop" } : { kind: "generated_refused", stashPath: refused.stashPath }
|
|
41329
41989
|
};
|
|
41330
41990
|
}
|
|
41331
41991
|
}
|
|
@@ -41470,7 +42130,7 @@ class Semaphore {
|
|
|
41470
42130
|
this.active += 1;
|
|
41471
42131
|
return;
|
|
41472
42132
|
}
|
|
41473
|
-
await new Promise((
|
|
42133
|
+
await new Promise((resolve6) => this.waiters.push(resolve6));
|
|
41474
42134
|
}
|
|
41475
42135
|
release() {
|
|
41476
42136
|
const next = this.waiters.shift();
|
|
@@ -41537,11 +42197,11 @@ import {
|
|
|
41537
42197
|
statSync as statSync16,
|
|
41538
42198
|
unlinkSync as unlinkSync8
|
|
41539
42199
|
} from "node:fs";
|
|
41540
|
-
import { join as
|
|
42200
|
+
import { join as join17 } from "node:path";
|
|
41541
42201
|
|
|
41542
42202
|
// src/lib/conflicts-view.ts
|
|
41543
42203
|
import { existsSync as existsSync6 } from "node:fs";
|
|
41544
|
-
import { join as
|
|
42204
|
+
import { join as join16 } from "node:path";
|
|
41545
42205
|
var NO_GENERATED_MEMORY = {
|
|
41546
42206
|
artistMemoryGenerated: () => false,
|
|
41547
42207
|
workspaceMemoryGenerated: () => false,
|
|
@@ -41587,7 +42247,7 @@ function resolveConflictRows(workspaceSlug, stashes, generatedMemory = NO_GENERA
|
|
|
41587
42247
|
if (validateFilesRelPath(rel) === null) {
|
|
41588
42248
|
return { kind: "unsafe-path", stash };
|
|
41589
42249
|
}
|
|
41590
|
-
const abs =
|
|
42250
|
+
const abs = join16(root, "files", rel);
|
|
41591
42251
|
if (hasSymlinkedComponent(workspaceSlug, abs)) {
|
|
41592
42252
|
return { kind: "unsafe-path", stash };
|
|
41593
42253
|
}
|
|
@@ -41720,7 +42380,7 @@ function refreshConflictsView(workspaceSlug) {
|
|
|
41720
42380
|
import { existsSync as existsSync7, readFileSync as readFileSync23, statSync as statSync14 } from "node:fs";
|
|
41721
42381
|
|
|
41722
42382
|
// src/lib/files/extracted-text.ts
|
|
41723
|
-
import { createHash as
|
|
42383
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
41724
42384
|
var DERIVED_TEXT_VERSION = 2;
|
|
41725
42385
|
function yamlString3(value) {
|
|
41726
42386
|
return JSON.stringify(value);
|
|
@@ -41794,7 +42454,7 @@ ${doc2.text}
|
|
|
41794
42454
|
`;
|
|
41795
42455
|
}
|
|
41796
42456
|
function extractedTextHash(rendered) {
|
|
41797
|
-
return
|
|
42457
|
+
return createHash4("sha256").update(rendered, "utf8").digest("hex");
|
|
41798
42458
|
}
|
|
41799
42459
|
|
|
41800
42460
|
// src/lib/files/pull.ts
|
|
@@ -42413,7 +43073,7 @@ function hasExistingContent(workspacePath) {
|
|
|
42413
43073
|
if (!e.isDirectory())
|
|
42414
43074
|
return true;
|
|
42415
43075
|
try {
|
|
42416
|
-
return readdirSync7(
|
|
43076
|
+
return readdirSync7(join17(workspacePath, e.name)).length > 0;
|
|
42417
43077
|
} catch {
|
|
42418
43078
|
return true;
|
|
42419
43079
|
}
|
|
@@ -44592,12 +45252,12 @@ async function runStart(workspaceSlug, deps = {}) {
|
|
|
44592
45252
|
try {
|
|
44593
45253
|
await Promise.race([
|
|
44594
45254
|
watcher.drainPending().then(() => Promise.all([gate.drain(), fileGate.drain()])),
|
|
44595
|
-
new Promise((
|
|
45255
|
+
new Promise((resolve6) => setTimeout(() => resolve6(-1), SHUTDOWN_DRAIN_TIMEOUT_MS))
|
|
44596
45256
|
]);
|
|
44597
45257
|
} finally {
|
|
44598
45258
|
await Promise.race([
|
|
44599
45259
|
watcher.stop(),
|
|
44600
|
-
new Promise((
|
|
45260
|
+
new Promise((resolve6) => setTimeout(resolve6, SHUTDOWN_DRAIN_TIMEOUT_MS))
|
|
44601
45261
|
]);
|
|
44602
45262
|
clearDaemonPid(slug);
|
|
44603
45263
|
releaseDaemonLock(lockHandle);
|
|
@@ -45153,11 +45813,11 @@ function assessContextWalls(workspaceSlug, deps = {}) {
|
|
|
45153
45813
|
// src/lib/build-stamp.ts
|
|
45154
45814
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
45155
45815
|
import { existsSync as existsSync10, mkdirSync as mkdirSync11, readFileSync as readFileSync27, writeFileSync as writeFileSync8 } from "node:fs";
|
|
45156
|
-
import { dirname as
|
|
45816
|
+
import { dirname as dirname12, join as join18 } from "node:path";
|
|
45157
45817
|
import { fileURLToPath } from "node:url";
|
|
45158
45818
|
var BUILD_STAMP_FILENAME = "build-stamp.json";
|
|
45159
45819
|
function stampPath(distDir) {
|
|
45160
|
-
return
|
|
45820
|
+
return join18(distDir, BUILD_STAMP_FILENAME);
|
|
45161
45821
|
}
|
|
45162
45822
|
function readHead(repoDir) {
|
|
45163
45823
|
try {
|
|
@@ -45188,9 +45848,9 @@ function readBuildStamp(distDir) {
|
|
|
45188
45848
|
function findRepoRoot(fromDir) {
|
|
45189
45849
|
let dir = fromDir;
|
|
45190
45850
|
for (;; ) {
|
|
45191
|
-
if (existsSync10(
|
|
45851
|
+
if (existsSync10(join18(dir, ".git")))
|
|
45192
45852
|
return dir;
|
|
45193
|
-
const parent =
|
|
45853
|
+
const parent = dirname12(dir);
|
|
45194
45854
|
if (parent === dir)
|
|
45195
45855
|
return null;
|
|
45196
45856
|
dir = parent;
|
|
@@ -45214,7 +45874,7 @@ function checkBuildStaleness(deps = {}) {
|
|
|
45214
45874
|
const metaUrl = deps.metaUrl ?? import.meta.url;
|
|
45215
45875
|
let distDir;
|
|
45216
45876
|
try {
|
|
45217
|
-
distDir =
|
|
45877
|
+
distDir = dirname12(fileURLToPath(metaUrl));
|
|
45218
45878
|
} catch {
|
|
45219
45879
|
return { kind: "unknown" };
|
|
45220
45880
|
}
|
|
@@ -45238,7 +45898,7 @@ function checkBuildStaleness(deps = {}) {
|
|
|
45238
45898
|
|
|
45239
45899
|
// src/lib/memory-links.ts
|
|
45240
45900
|
import { readFileSync as readFileSync28 } from "node:fs";
|
|
45241
|
-
import { relative as relative15, sep as
|
|
45901
|
+
import { relative as relative15, sep as sep8 } from "node:path";
|
|
45242
45902
|
var MEMORY_FILE_RE = /^(workspace-memory\.md|user-memory\.md|artists\/[^/]+\/memory\.md|memory\/[^/]+\.md|memory\/private\/[^/]+\.md)$/i;
|
|
45243
45903
|
function scanMemoryLinks(deps) {
|
|
45244
45904
|
const listFiles = deps.listFiles ?? ((r) => walkSubtreeFiles(r, isVcsInternal));
|
|
@@ -45251,7 +45911,7 @@ function scanMemoryLinks(deps) {
|
|
|
45251
45911
|
} catch {
|
|
45252
45912
|
return { scanned: 0, unreadable: [], dead: [] };
|
|
45253
45913
|
}
|
|
45254
|
-
const relPaths = absPaths.map((p) => relative15(root, p).split(
|
|
45914
|
+
const relPaths = absPaths.map((p) => relative15(root, p).split(sep8).join("/"));
|
|
45255
45915
|
const artists = buildArtistIndex(relPaths, root, (abs) => readFile(abs));
|
|
45256
45916
|
const dead = [];
|
|
45257
45917
|
const unreadable = [];
|
|
@@ -46317,7 +46977,7 @@ async function callVoiceGate(req) {
|
|
|
46317
46977
|
}
|
|
46318
46978
|
|
|
46319
46979
|
// src/lib/voice-gate/attempts.ts
|
|
46320
|
-
import { createHash as
|
|
46980
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
46321
46981
|
import {
|
|
46322
46982
|
mkdirSync as mkdirSync12,
|
|
46323
46983
|
readFileSync as readFileSync30,
|
|
@@ -46325,7 +46985,7 @@ import {
|
|
|
46325
46985
|
unlinkSync as unlinkSync9,
|
|
46326
46986
|
writeFileSync as writeFileSync9
|
|
46327
46987
|
} from "node:fs";
|
|
46328
|
-
import { join as
|
|
46988
|
+
import { join as join19 } from "node:path";
|
|
46329
46989
|
var MAX_REGENS = 2;
|
|
46330
46990
|
var ENTRY_TTL_MS = 24 * 60 * 60 * 1000;
|
|
46331
46991
|
var AttemptEntrySchema = exports_external.object({
|
|
@@ -46338,13 +46998,13 @@ var AttemptsFileSchema = exports_external.object({
|
|
|
46338
46998
|
entries: exports_external.record(exports_external.string(), AttemptEntrySchema)
|
|
46339
46999
|
});
|
|
46340
47000
|
function attemptsDir(workspaceSlug) {
|
|
46341
|
-
return
|
|
47001
|
+
return join19(plinthHome(), "_voice_gate", workspaceSlug);
|
|
46342
47002
|
}
|
|
46343
47003
|
function attemptsPath(workspaceSlug) {
|
|
46344
|
-
return
|
|
47004
|
+
return join19(attemptsDir(workspaceSlug), "attempts.json");
|
|
46345
47005
|
}
|
|
46346
47006
|
function attemptKey(identity) {
|
|
46347
|
-
return
|
|
47007
|
+
return createHash5("sha256").update(identity, "utf8").digest("hex").slice(0, 32);
|
|
46348
47008
|
}
|
|
46349
47009
|
function emptyFile() {
|
|
46350
47010
|
return { version: 1, entries: {} };
|
|
@@ -46516,7 +47176,7 @@ function denyUngated(detail) {
|
|
|
46516
47176
|
// src/lib/voice-gate/payload.ts
|
|
46517
47177
|
import { readFileSync as readFileSync31, statSync as statSync20 } from "node:fs";
|
|
46518
47178
|
import { homedir as homedir2 } from "node:os";
|
|
46519
|
-
import { isAbsolute as isAbsolute4, resolve as
|
|
47179
|
+
import { isAbsolute as isAbsolute4, resolve as resolve6 } from "node:path";
|
|
46520
47180
|
var MAX_BODY_BYTES = 256 * 1024;
|
|
46521
47181
|
var HELPER_BASENAME = "push_gmail_draft.py";
|
|
46522
47182
|
var DRAFT_FLAGS = ["--to", "--body-file", "--body-stdin"];
|
|
@@ -46710,13 +47370,13 @@ function applyCd(tokens, state) {
|
|
|
46710
47370
|
return { dir: expanded, known: true };
|
|
46711
47371
|
if (!state.known)
|
|
46712
47372
|
return state;
|
|
46713
|
-
return { dir:
|
|
47373
|
+
return { dir: resolve6(state.dir, expanded), known: true };
|
|
46714
47374
|
}
|
|
46715
47375
|
function expandHome(path5) {
|
|
46716
47376
|
if (path5 === "~")
|
|
46717
47377
|
return homedir2();
|
|
46718
47378
|
if (path5.startsWith("~/"))
|
|
46719
|
-
return
|
|
47379
|
+
return resolve6(homedir2(), path5.slice(2));
|
|
46720
47380
|
return path5;
|
|
46721
47381
|
}
|
|
46722
47382
|
function classifyHelperSegment(tokens, dirState, readBodyFile) {
|
|
@@ -46742,7 +47402,7 @@ function classifyHelperSegment(tokens, dirState, readBodyFile) {
|
|
|
46742
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.`
|
|
46743
47403
|
};
|
|
46744
47404
|
}
|
|
46745
|
-
const resolved = isAbsolute4(expanded) ? expanded :
|
|
47405
|
+
const resolved = isAbsolute4(expanded) ? expanded : resolve6(dirState.dir, expanded);
|
|
46746
47406
|
let body;
|
|
46747
47407
|
try {
|
|
46748
47408
|
body = readBodyFile(resolved);
|