@oxagen/cli 2.1.4-384 → 2.1.4-391
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/oxagen.mjs +1528 -653
- package/package.json +1 -1
package/oxagen.mjs
CHANGED
|
@@ -4767,7 +4767,8 @@ var init_envelope = __esm({
|
|
|
4767
4767
|
"daemon_down",
|
|
4768
4768
|
"http_hook_failed",
|
|
4769
4769
|
"otel_missing",
|
|
4770
|
-
"spool_overflow"
|
|
4770
|
+
"spool_overflow",
|
|
4771
|
+
"wal_ceiling"
|
|
4771
4772
|
];
|
|
4772
4773
|
INCIDENT_KINDS = [
|
|
4773
4774
|
"unobserved_session",
|
|
@@ -7375,8 +7376,8 @@ function candidatePaths(path2, context) {
|
|
|
7375
7376
|
const base2 = fold(lib.normalize(root)).replace(/\/+$/, "");
|
|
7376
7377
|
return resolved.startsWith(`${base2}/`) ? resolved.slice(base2.length + 1) : void 0;
|
|
7377
7378
|
};
|
|
7378
|
-
const
|
|
7379
|
-
if (
|
|
7379
|
+
const relative9 = cwd !== void 0 ? under(cwd) : void 0;
|
|
7380
|
+
if (relative9 !== void 0) out.push(relative9);
|
|
7380
7381
|
const fromHome = home !== void 0 ? under(home) : void 0;
|
|
7381
7382
|
if (fromHome !== void 0) out.push(`~/${fromHome}`);
|
|
7382
7383
|
return out;
|
|
@@ -15346,7 +15347,7 @@ import { readFileSync as readFileSync10 } from "node:fs";
|
|
|
15346
15347
|
import { dirname as dirname7, resolve as resolve2 } from "node:path";
|
|
15347
15348
|
import { fileURLToPath } from "node:url";
|
|
15348
15349
|
function readVersion() {
|
|
15349
|
-
if (true) return "2.1.4-
|
|
15350
|
+
if (true) return "2.1.4-391";
|
|
15350
15351
|
try {
|
|
15351
15352
|
const here = dirname7(fileURLToPath(import.meta.url));
|
|
15352
15353
|
const pkg = JSON.parse(
|
|
@@ -16982,6 +16983,7 @@ import {
|
|
|
16982
16983
|
appendFileSync as appendFileSync2,
|
|
16983
16984
|
closeSync as closeSync6,
|
|
16984
16985
|
fdatasyncSync,
|
|
16986
|
+
fstatSync,
|
|
16985
16987
|
fsyncSync as fsyncSync3,
|
|
16986
16988
|
openSync as openSync6,
|
|
16987
16989
|
existsSync as existsSync12,
|
|
@@ -16999,7 +17001,10 @@ function activityAt(event) {
|
|
|
16999
17001
|
const at = Date.parse(event.ts);
|
|
17000
17002
|
return Number.isFinite(at) ? at : Number.NEGATIVE_INFINITY;
|
|
17001
17003
|
}
|
|
17002
|
-
|
|
17004
|
+
function sizeOf(path2) {
|
|
17005
|
+
return statSync7(path2, { throwIfNoEntry: false })?.size ?? 0;
|
|
17006
|
+
}
|
|
17007
|
+
var BODY_READ_SLICE, BODY_DROP_SLICE_BYTES, BODY_DROP_SCANS, NEWLINE, EVENT_TAIL_WINDOW, WalRecoveryConflict, Wal;
|
|
17003
17008
|
var init_wal = __esm({
|
|
17004
17009
|
"../../packages/tacho/src/host/wal.ts"() {
|
|
17005
17010
|
"use strict";
|
|
@@ -17007,6 +17012,9 @@ var init_wal = __esm({
|
|
|
17007
17012
|
init_fs();
|
|
17008
17013
|
init_wal_index();
|
|
17009
17014
|
BODY_READ_SLICE = 32;
|
|
17015
|
+
BODY_DROP_SLICE_BYTES = 1024 * 1024;
|
|
17016
|
+
BODY_DROP_SCANS = 3;
|
|
17017
|
+
NEWLINE = 10;
|
|
17010
17018
|
EVENT_TAIL_WINDOW = 16 * 1024;
|
|
17011
17019
|
WalRecoveryConflict = class extends Error {
|
|
17012
17020
|
constructor(sessionUuid2, seq) {
|
|
@@ -17616,10 +17624,12 @@ ${lines.join("\n")}
|
|
|
17616
17624
|
* returns, and `bodiesOfSession` reports `body_index_unusable` only when
|
|
17617
17625
|
* that read also finds its index disagreeing with the file. Reaching this
|
|
17618
17626
|
* takes a file rewritten in place, at the same size, while each awaited
|
|
17619
|
-
* build ran
|
|
17620
|
-
*
|
|
17621
|
-
*
|
|
17622
|
-
*
|
|
17627
|
+
* build ran. The daemon's sweeps rewrite through a temp file and a rename.
|
|
17628
|
+
* `dropBodiesAsync` does write in place, but only the shipper calls it,
|
|
17629
|
+
* after this read has returned, and the shipper runs one drain at a time.
|
|
17630
|
+
* Shipping those events without bodies instead marked them shipped and lost
|
|
17631
|
+
* the stored content for good, and a one-off stall on a path that needs
|
|
17632
|
+
* outside tampering costs less than that.
|
|
17623
17633
|
*/
|
|
17624
17634
|
async bodiesForAsync(events) {
|
|
17625
17635
|
const found = /* @__PURE__ */ new Map();
|
|
@@ -17734,16 +17744,13 @@ ${lines.join("\n")}
|
|
|
17734
17744
|
* here. A body file with a second writer would need a tombstone instead,
|
|
17735
17745
|
* because a read-filter-rename loses a line appended between the read and
|
|
17736
17746
|
* the rename.
|
|
17747
|
+
*
|
|
17748
|
+
* This reads the whole body file on the synchronous path. The shipper
|
|
17749
|
+
* calls `dropBodiesAsync`, which uses this only as its last resort.
|
|
17737
17750
|
*/
|
|
17738
17751
|
dropBodies(events) {
|
|
17739
|
-
const wanted = /* @__PURE__ */ new Map();
|
|
17740
|
-
for (const event of events) {
|
|
17741
|
-
const idems = wanted.get(event.session_uuid) ?? /* @__PURE__ */ new Set();
|
|
17742
|
-
idems.add(event.event_id_idem);
|
|
17743
|
-
wanted.set(event.session_uuid, idems);
|
|
17744
|
-
}
|
|
17745
17752
|
let dropped = 0;
|
|
17746
|
-
for (const [session, idems] of
|
|
17753
|
+
for (const [session, idems] of _Wal.idemsBySession(events)) {
|
|
17747
17754
|
dropped += this.rewriteBodies(
|
|
17748
17755
|
session,
|
|
17749
17756
|
(stored) => stored !== void 0 && !idems.has(stored.event_id_idem)
|
|
@@ -17751,6 +17758,170 @@ ${lines.join("\n")}
|
|
|
17751
17758
|
}
|
|
17752
17759
|
return dropped;
|
|
17753
17760
|
}
|
|
17761
|
+
/**
|
|
17762
|
+
* Delete the stored bytes of these events' bodies without holding the
|
|
17763
|
+
* daemon's thread on a large file (ADR-231), and report how many lines
|
|
17764
|
+
* went. The shipper calls this when a proven mandate withdraws a body from
|
|
17765
|
+
* its batch.
|
|
17766
|
+
*
|
|
17767
|
+
* `dropBodies` reads the whole body file and rewrites it on the synchronous
|
|
17768
|
+
* path, and a long session's file holds gigabytes. This finds the withdrawn
|
|
17769
|
+
* lines with a scan that awaits every read. Then it overwrites each line in
|
|
17770
|
+
* place with spaces, a slice at a time, with a turn of the event loop
|
|
17771
|
+
* between slices. Every reader skips a line of spaces, so the body reads as
|
|
17772
|
+
* gone. The file keeps its size until `compact` removes it, and no copy of
|
|
17773
|
+
* it is written to a disk that may be nearly full.
|
|
17774
|
+
*
|
|
17775
|
+
* The scan's offsets can be stale by the time a slice runs. Hooks append
|
|
17776
|
+
* between the scan's reads, a failed append is cut back, and a narrowing
|
|
17777
|
+
* sweep can rewrite the file. So a slice reads each line again, in the same
|
|
17778
|
+
* synchronous stretch as the write, and overwrites it only when it is still
|
|
17779
|
+
* one whole stored body for one of these events. A line that is not is left
|
|
17780
|
+
* alone, and the session is scanned again. After `BODY_DROP_SCANS` scans
|
|
17781
|
+
* that each found a line out of place, the rest goes through `dropBodies`
|
|
17782
|
+
* on the synchronous path. Reaching that takes a rewrite of the file during
|
|
17783
|
+
* every scan.
|
|
17784
|
+
*
|
|
17785
|
+
* The scan finds every copy of a body, as `dropBodies` does. It does not
|
|
17786
|
+
* remove a torn line, which `dropBodies` does: a line still being appended
|
|
17787
|
+
* can look torn to an awaited read. `purgeBodiesOutsideMandate` removes torn
|
|
17788
|
+
* lines on a narrowing.
|
|
17789
|
+
*/
|
|
17790
|
+
async dropBodiesAsync(events) {
|
|
17791
|
+
let dropped = 0;
|
|
17792
|
+
for (const [session, idems] of _Wal.idemsBySession(events)) {
|
|
17793
|
+
let settled2 = false;
|
|
17794
|
+
for (let scan = 0; scan < BODY_DROP_SCANS && !settled2; scan += 1) {
|
|
17795
|
+
const pass2 = await this.blankBodies(session, idems);
|
|
17796
|
+
dropped += pass2.blanked;
|
|
17797
|
+
settled2 = !pass2.moved;
|
|
17798
|
+
}
|
|
17799
|
+
if (!settled2)
|
|
17800
|
+
dropped += this.dropBodies(
|
|
17801
|
+
events.filter((event) => event.session_uuid === session)
|
|
17802
|
+
);
|
|
17803
|
+
}
|
|
17804
|
+
return dropped;
|
|
17805
|
+
}
|
|
17806
|
+
/**
|
|
17807
|
+
* One scan of `dropBodiesAsync` over one session: find every line that
|
|
17808
|
+
* holds one of these bodies, then overwrite each line that still does.
|
|
17809
|
+
* `moved` says a line the scan found held something else by the time its
|
|
17810
|
+
* slice ran.
|
|
17811
|
+
*/
|
|
17812
|
+
async blankBodies(session, idems) {
|
|
17813
|
+
const path2 = this.bodyFileFor(session);
|
|
17814
|
+
if (!existsSync12(path2)) return { blanked: 0, moved: false };
|
|
17815
|
+
const found = [];
|
|
17816
|
+
try {
|
|
17817
|
+
for await (const line of readLinesFromAsync(path2)) {
|
|
17818
|
+
if (!line.terminated) continue;
|
|
17819
|
+
const stored = parseStoredBody(line.text);
|
|
17820
|
+
if (stored !== void 0 && idems.has(stored.event_id_idem))
|
|
17821
|
+
found.push({
|
|
17822
|
+
offset: line.offset,
|
|
17823
|
+
length: line.end - line.offset - 1
|
|
17824
|
+
});
|
|
17825
|
+
}
|
|
17826
|
+
} catch (error) {
|
|
17827
|
+
if (error.code === "ENOENT")
|
|
17828
|
+
return { blanked: 0, moved: false };
|
|
17829
|
+
throw error;
|
|
17830
|
+
}
|
|
17831
|
+
let blanked = 0;
|
|
17832
|
+
let moved = false;
|
|
17833
|
+
for (let next = 0; next < found.length; ) {
|
|
17834
|
+
if (next > 0) await new Promise((resolve19) => setImmediate(resolve19));
|
|
17835
|
+
const slice = this.blankSlice(path2, found, next, idems);
|
|
17836
|
+
if (slice === void 0) break;
|
|
17837
|
+
blanked += slice.blanked;
|
|
17838
|
+
moved ||= slice.moved;
|
|
17839
|
+
next = slice.next;
|
|
17840
|
+
}
|
|
17841
|
+
if (blanked > 0) this.bodyIndexes.invalidate(session);
|
|
17842
|
+
return { blanked, moved };
|
|
17843
|
+
}
|
|
17844
|
+
/**
|
|
17845
|
+
* One synchronous stretch of `blankBodies`: from `from`, overwrite each
|
|
17846
|
+
* found line that still holds one of these bodies, until the slice has
|
|
17847
|
+
* taken `BODY_DROP_SLICE_BYTES`. Nothing else can touch the file while it
|
|
17848
|
+
* runs. Answers undefined when the file is gone.
|
|
17849
|
+
*/
|
|
17850
|
+
blankSlice(path2, found, from, idems) {
|
|
17851
|
+
let fd2;
|
|
17852
|
+
try {
|
|
17853
|
+
fd2 = openSync6(path2, "r+");
|
|
17854
|
+
} catch (error) {
|
|
17855
|
+
if (error.code === "ENOENT") return void 0;
|
|
17856
|
+
throw error;
|
|
17857
|
+
}
|
|
17858
|
+
let blanked = 0;
|
|
17859
|
+
let moved = false;
|
|
17860
|
+
let next = from;
|
|
17861
|
+
try {
|
|
17862
|
+
const size = fstatSync(fd2).size;
|
|
17863
|
+
let taken = 0;
|
|
17864
|
+
while (next < found.length && taken < BODY_DROP_SLICE_BYTES) {
|
|
17865
|
+
const at = found[next];
|
|
17866
|
+
next += 1;
|
|
17867
|
+
taken += at.length;
|
|
17868
|
+
if (!_Wal.holdsBodyOf(fd2, size, at, idems)) {
|
|
17869
|
+
moved = true;
|
|
17870
|
+
continue;
|
|
17871
|
+
}
|
|
17872
|
+
_Wal.overwriteWithSpaces(fd2, at);
|
|
17873
|
+
blanked += 1;
|
|
17874
|
+
}
|
|
17875
|
+
if (blanked > 0) fdatasyncSync(fd2);
|
|
17876
|
+
} finally {
|
|
17877
|
+
closeSync6(fd2);
|
|
17878
|
+
}
|
|
17879
|
+
return { blanked, moved, next };
|
|
17880
|
+
}
|
|
17881
|
+
/**
|
|
17882
|
+
* Whether the bytes at `at` are still one whole stored body for one of
|
|
17883
|
+
* `idems`: the start of the file or a newline before them, a newline right
|
|
17884
|
+
* after them, and a line between that parses and names one of the events.
|
|
17885
|
+
* Costs a read of that one line.
|
|
17886
|
+
*/
|
|
17887
|
+
static holdsBodyOf(fd2, size, at, idems) {
|
|
17888
|
+
const start = at.offset === 0 ? 0 : at.offset - 1;
|
|
17889
|
+
const end = at.offset + at.length + 1;
|
|
17890
|
+
if (at.length <= 0 || end > size) return false;
|
|
17891
|
+
const buffer = Buffer.allocUnsafe(end - start);
|
|
17892
|
+
let filled = 0;
|
|
17893
|
+
while (filled < buffer.length) {
|
|
17894
|
+
const read2 = readSync3(
|
|
17895
|
+
fd2,
|
|
17896
|
+
buffer,
|
|
17897
|
+
filled,
|
|
17898
|
+
buffer.length - filled,
|
|
17899
|
+
start + filled
|
|
17900
|
+
);
|
|
17901
|
+
if (read2 <= 0) return false;
|
|
17902
|
+
filled += read2;
|
|
17903
|
+
}
|
|
17904
|
+
if (at.offset > 0 && buffer[0] !== NEWLINE) return false;
|
|
17905
|
+
if (buffer[buffer.length - 1] !== NEWLINE) return false;
|
|
17906
|
+
const stored = parseStoredBody(
|
|
17907
|
+
buffer.subarray(at.offset - start, buffer.length - 1).toString("utf8")
|
|
17908
|
+
);
|
|
17909
|
+
return stored !== void 0 && idems.has(stored.event_id_idem);
|
|
17910
|
+
}
|
|
17911
|
+
/** Overwrite the bytes at `at` with spaces, leaving its newline. */
|
|
17912
|
+
static overwriteWithSpaces(fd2, at) {
|
|
17913
|
+
const spaces = Buffer.alloc(Math.min(at.length, 64 * 1024), " ");
|
|
17914
|
+
let written = 0;
|
|
17915
|
+
while (written < at.length) {
|
|
17916
|
+
written += writeSync4(
|
|
17917
|
+
fd2,
|
|
17918
|
+
spaces,
|
|
17919
|
+
0,
|
|
17920
|
+
Math.min(spaces.length, at.length - written),
|
|
17921
|
+
at.offset + written
|
|
17922
|
+
);
|
|
17923
|
+
}
|
|
17924
|
+
}
|
|
17754
17925
|
/** Sessions that have a body file, whether or not they have an event file. */
|
|
17755
17926
|
sessionsWithBodies() {
|
|
17756
17927
|
const suffix = ".bodies.jsonl";
|
|
@@ -18134,20 +18305,75 @@ ${lines.join("\n")}
|
|
|
18134
18305
|
...oldest !== void 0 ? { oldestUnshippedAt: oldest } : {}
|
|
18135
18306
|
};
|
|
18136
18307
|
}
|
|
18308
|
+
/**
|
|
18309
|
+
* Every session with an event past its shipped cursor, and the bytes its
|
|
18310
|
+
* files hold.
|
|
18311
|
+
*
|
|
18312
|
+
* The WAL ceiling asks for this once a minute (ADR-261). It costs two `stat`
|
|
18313
|
+
* calls per session, plus the tail read `lastSeqOf` already keeps, so it
|
|
18314
|
+
* reads no event or body. The byte counts are whole files, shipped lines
|
|
18315
|
+
* included, because nothing this cheap says where a session's unshipped
|
|
18316
|
+
* bodies start.
|
|
18317
|
+
*/
|
|
18318
|
+
holdings() {
|
|
18319
|
+
const out = [];
|
|
18320
|
+
for (const session of this.sessions()) {
|
|
18321
|
+
const last = this.lastSeqOf(session);
|
|
18322
|
+
const through = this.shippedThrough(session);
|
|
18323
|
+
if (last <= through) continue;
|
|
18324
|
+
out.push({
|
|
18325
|
+
sessionUuid: session,
|
|
18326
|
+
shippedThrough: through,
|
|
18327
|
+
lastSeq: last,
|
|
18328
|
+
eventBytes: sizeOf(this.fileFor(session)),
|
|
18329
|
+
bodyBytes: sizeOf(this.bodyFileFor(session)),
|
|
18330
|
+
lastActivityAt: this.lastActivity.get(session) ?? Number.NEGATIVE_INFINITY
|
|
18331
|
+
});
|
|
18332
|
+
}
|
|
18333
|
+
return out;
|
|
18334
|
+
}
|
|
18335
|
+
/**
|
|
18336
|
+
* Remove one session's body file and its index, and answer how many bytes
|
|
18337
|
+
* went. Only the WAL ceiling calls this (ADR-261).
|
|
18338
|
+
*
|
|
18339
|
+
* The file is removed, not rewritten. `rewriteBodies` reads every line on
|
|
18340
|
+
* the daemon's only thread, and a session over the ceiling can hold
|
|
18341
|
+
* gigabytes, which ADR-231 rules out. The event file stays, so the chain
|
|
18342
|
+
* still verifies. Each event whose body went ships without it, and the
|
|
18343
|
+
* control plane records a `body_missing` gap for it.
|
|
18344
|
+
*
|
|
18345
|
+
* What each reader sees afterwards:
|
|
18346
|
+
*
|
|
18347
|
+
* - `bodiesFor` finds no file, so a batch read after this ships its events
|
|
18348
|
+
* with no bodies. A batch already read keeps the bodies it holds.
|
|
18349
|
+
* - An index build running for the session sees the generation move, and
|
|
18350
|
+
* keeps nothing.
|
|
18351
|
+
* - `appendRecovered` finds no stored body, so a journaled terminal batch
|
|
18352
|
+
* writes its own few bodies again.
|
|
18353
|
+
* - The session's next `append` starts a new body file.
|
|
18354
|
+
*
|
|
18355
|
+
* A removal that fails is reported, answers 0, and the next check tries
|
|
18356
|
+
* again. On Windows that happens while another reader holds the file open.
|
|
18357
|
+
*/
|
|
18358
|
+
dropSessionBodies(sessionUuid2) {
|
|
18359
|
+
const bytes = sizeOf(this.bodyFileFor(sessionUuid2));
|
|
18360
|
+
if (bytes === 0) return 0;
|
|
18361
|
+
return this.removeBodies(sessionUuid2) ? bytes : 0;
|
|
18362
|
+
}
|
|
18137
18363
|
/**
|
|
18138
18364
|
* Erase every stored body whose class `retention` does not cover, in every
|
|
18139
18365
|
* session this host holds, and answer how many were erased.
|
|
18140
18366
|
*
|
|
18141
|
-
* Why this exists beside `
|
|
18142
|
-
* the events in a drain's batch, which is every body the shipper
|
|
18143
|
-
* an unshipped event for. Two kinds of body sit outside that
|
|
18144
|
-
* whose event already shipped, since `markShipped` advanced the
|
|
18145
|
-
* it, and one in a session the drain is not looking at.
|
|
18146
|
-
* those only once their session is sealed, fully shipped,
|
|
18147
|
-
* the retention window, so a session that never seals kept
|
|
18148
|
-
* as the host ran, or for ever on a host that never came
|
|
18149
|
-
* walks every session and every stored line, so a
|
|
18150
|
-
* them.
|
|
18367
|
+
* Why this exists beside `dropBodiesAsync`. The shipper's drop reaches the
|
|
18368
|
+
* bodies of the events in a drain's batch, which is every body the shipper
|
|
18369
|
+
* still has an unshipped event for. Two kinds of body sit outside that
|
|
18370
|
+
* reach: one whose event already shipped, since `markShipped` advanced the
|
|
18371
|
+
* cursor past it, and one in a session the drain is not looking at.
|
|
18372
|
+
* `compact` frees those only once their session is sealed, fully shipped,
|
|
18373
|
+
* and older than the retention window, so a session that never seals kept
|
|
18374
|
+
* them for as long as the host ran, or for ever on a host that never came
|
|
18375
|
+
* back. This sweep walks every session and every stored line, so a
|
|
18376
|
+
* narrowing reaches all of them.
|
|
18151
18377
|
*
|
|
18152
18378
|
* The write is the one in `rewriteBodies`, which `dropBodies` uses as well:
|
|
18153
18379
|
* atomic, and safe because these files have one writer. The module header
|
|
@@ -18682,6 +18908,252 @@ var init_policy_mode = __esm({
|
|
|
18682
18908
|
}
|
|
18683
18909
|
});
|
|
18684
18910
|
|
|
18911
|
+
// ../../packages/tacho/src/host/wal-ceiling.ts
|
|
18912
|
+
import { statfsSync } from "node:fs";
|
|
18913
|
+
import { join as join16 } from "node:path";
|
|
18914
|
+
function freeBytesOn(dir) {
|
|
18915
|
+
try {
|
|
18916
|
+
const stats2 = statfsSync(dir);
|
|
18917
|
+
return stats2.bavail * stats2.bsize;
|
|
18918
|
+
} catch {
|
|
18919
|
+
return void 0;
|
|
18920
|
+
}
|
|
18921
|
+
}
|
|
18922
|
+
function isCount(value) {
|
|
18923
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
18924
|
+
}
|
|
18925
|
+
function isClock(value) {
|
|
18926
|
+
if (typeof value !== "object" || value === null) return false;
|
|
18927
|
+
const clock = value;
|
|
18928
|
+
const since = clock["since"];
|
|
18929
|
+
return Number.isSafeInteger(clock["shipped_through"]) && typeof since === "string" && Number.isFinite(Date.parse(since));
|
|
18930
|
+
}
|
|
18931
|
+
function clocksFrom(value) {
|
|
18932
|
+
const clocks = {};
|
|
18933
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
18934
|
+
return clocks;
|
|
18935
|
+
for (const [session, clock] of Object.entries(value))
|
|
18936
|
+
if (isClock(clock))
|
|
18937
|
+
clocks[session] = {
|
|
18938
|
+
shipped_through: clock.shipped_through,
|
|
18939
|
+
since: clock.since
|
|
18940
|
+
};
|
|
18941
|
+
return clocks;
|
|
18942
|
+
}
|
|
18943
|
+
function sameClocks(a, b5) {
|
|
18944
|
+
const keys = Object.keys(a);
|
|
18945
|
+
if (keys.length !== Object.keys(b5).length) return false;
|
|
18946
|
+
return keys.every((session) => {
|
|
18947
|
+
const other = b5[session];
|
|
18948
|
+
const clock = a[session];
|
|
18949
|
+
return other !== void 0 && clock !== void 0 && other.shipped_through === clock.shipped_through && other.since === clock.since;
|
|
18950
|
+
});
|
|
18951
|
+
}
|
|
18952
|
+
function isDrop(value) {
|
|
18953
|
+
if (typeof value !== "object" || value === null) return false;
|
|
18954
|
+
const drop = value;
|
|
18955
|
+
return typeof drop["session_uuid"] === "string" && isCount(drop["bytes"]) && typeof drop["shipped_through"] === "number" && typeof drop["last_seq"] === "number" && typeof drop["stalled_since"] === "string" && typeof drop["dropped_at"] === "string" && isCount(drop["stalled_bytes"]) && isCount(drop["ceiling_bytes"]);
|
|
18956
|
+
}
|
|
18957
|
+
function readWalCeilingState(walDir) {
|
|
18958
|
+
let raw;
|
|
18959
|
+
try {
|
|
18960
|
+
raw = readJsonFileIfExists(join16(walDir, STATE_FILE));
|
|
18961
|
+
} catch {
|
|
18962
|
+
return void 0;
|
|
18963
|
+
}
|
|
18964
|
+
if (typeof raw !== "object" || raw === null) return void 0;
|
|
18965
|
+
const state = raw;
|
|
18966
|
+
const checkedAt = state["checked_at"];
|
|
18967
|
+
const ceilingBytes = state["ceiling_bytes"];
|
|
18968
|
+
const stallGraceMs = state["stall_grace_ms"];
|
|
18969
|
+
const stalledBytes = state["stalled_bytes"];
|
|
18970
|
+
const stalledSessions = state["stalled_sessions"];
|
|
18971
|
+
const drops = state["drops"];
|
|
18972
|
+
if (state["schema"] !== STATE_SCHEMA || typeof checkedAt !== "string" || !isCount(ceilingBytes) || !isCount(stallGraceMs) || !isCount(stalledBytes) || !isCount(stalledSessions) || !Array.isArray(drops))
|
|
18973
|
+
return void 0;
|
|
18974
|
+
return {
|
|
18975
|
+
schema: STATE_SCHEMA,
|
|
18976
|
+
checked_at: checkedAt,
|
|
18977
|
+
ceiling_bytes: ceilingBytes,
|
|
18978
|
+
stall_grace_ms: stallGraceMs,
|
|
18979
|
+
stalled_bytes: stalledBytes,
|
|
18980
|
+
stalled_sessions: stalledSessions,
|
|
18981
|
+
drops: drops.filter(isDrop),
|
|
18982
|
+
stall_clocks: clocksFrom(state["stall_clocks"])
|
|
18983
|
+
};
|
|
18984
|
+
}
|
|
18985
|
+
function ceilingFor(fixed, free, stalled) {
|
|
18986
|
+
if (free === void 0 || !Number.isFinite(free)) return fixed;
|
|
18987
|
+
return Math.min(fixed, Math.floor((free + stalled) / 2));
|
|
18988
|
+
}
|
|
18989
|
+
var DEFAULT_WAL_CEILING, STATE_FILE, STATE_SCHEMA, DROPS_KEPT, WalCeiling;
|
|
18990
|
+
var init_wal_ceiling = __esm({
|
|
18991
|
+
"../../packages/tacho/src/host/wal-ceiling.ts"() {
|
|
18992
|
+
"use strict";
|
|
18993
|
+
init_fs();
|
|
18994
|
+
DEFAULT_WAL_CEILING = {
|
|
18995
|
+
ceilingBytes: 8 * 1024 ** 3,
|
|
18996
|
+
stallGraceMs: 60 * 6e4,
|
|
18997
|
+
checkEveryMs: 6e4,
|
|
18998
|
+
freeBytes: freeBytesOn
|
|
18999
|
+
};
|
|
19000
|
+
STATE_FILE = "ceiling.json";
|
|
19001
|
+
STATE_SCHEMA = "tacho.wal-ceiling.v1";
|
|
19002
|
+
DROPS_KEPT = 20;
|
|
19003
|
+
WalCeiling = class {
|
|
19004
|
+
constructor(wal, walDir, policy, keepDropsMs, log) {
|
|
19005
|
+
this.wal = wal;
|
|
19006
|
+
this.walDir = walDir;
|
|
19007
|
+
this.policy = policy;
|
|
19008
|
+
this.keepDropsMs = keepDropsMs;
|
|
19009
|
+
this.log = log;
|
|
19010
|
+
this.state = readWalCeilingState(walDir);
|
|
19011
|
+
for (const [session, clock] of Object.entries(
|
|
19012
|
+
this.state?.stall_clocks ?? {}
|
|
19013
|
+
))
|
|
19014
|
+
this.progress.set(session, {
|
|
19015
|
+
through: clock.shipped_through,
|
|
19016
|
+
since: Date.parse(clock.since)
|
|
19017
|
+
});
|
|
19018
|
+
}
|
|
19019
|
+
wal;
|
|
19020
|
+
walDir;
|
|
19021
|
+
policy;
|
|
19022
|
+
keepDropsMs;
|
|
19023
|
+
log;
|
|
19024
|
+
/**
|
|
19025
|
+
* Each waiting session's shipped cursor as the last check saw it, and when
|
|
19026
|
+
* it was first seen there.
|
|
19027
|
+
*
|
|
19028
|
+
* A clock whose cursor stood still between two checks is also written to
|
|
19029
|
+
* `ceiling.json`, and the constructor reads it back, so a restarted daemon
|
|
19030
|
+
* resumes the clock. A daemon that restarted more often than `stallGraceMs`
|
|
19031
|
+
* used to start every clock again each time, and never dropped anything.
|
|
19032
|
+
* A clock first seen by the last check before a restart is not written yet,
|
|
19033
|
+
* so a restart costs it at most one `checkEveryMs`.
|
|
19034
|
+
*/
|
|
19035
|
+
progress = /* @__PURE__ */ new Map();
|
|
19036
|
+
state;
|
|
19037
|
+
/** Set when the last write of `ceiling.json` failed, so the next check writes. */
|
|
19038
|
+
unsaved = false;
|
|
19039
|
+
lastCheckAt = Number.NEGATIVE_INFINITY;
|
|
19040
|
+
/** Whether a check is due at `now`. */
|
|
19041
|
+
due(now) {
|
|
19042
|
+
return now - this.lastCheckAt >= this.policy.checkEveryMs;
|
|
19043
|
+
}
|
|
19044
|
+
/**
|
|
19045
|
+
* One check, and the drops it made.
|
|
19046
|
+
*
|
|
19047
|
+
* `onDrop` runs right after each body file goes, in the same synchronous
|
|
19048
|
+
* stretch, so the daemon seals the frame that records the drop before
|
|
19049
|
+
* anything else runs. A frame that fails does not bring the bodies back:
|
|
19050
|
+
* the drop stands, and the daemon logs the failure.
|
|
19051
|
+
*/
|
|
19052
|
+
check(now, onDrop) {
|
|
19053
|
+
this.lastCheckAt = now;
|
|
19054
|
+
const holdings = this.wal.holdings();
|
|
19055
|
+
const waiting = /* @__PURE__ */ new Set();
|
|
19056
|
+
const clocks = {};
|
|
19057
|
+
for (const holding of holdings) {
|
|
19058
|
+
waiting.add(holding.sessionUuid);
|
|
19059
|
+
const known = this.progress.get(holding.sessionUuid);
|
|
19060
|
+
if (known === void 0 || known.through !== holding.shippedThrough) {
|
|
19061
|
+
this.progress.set(holding.sessionUuid, {
|
|
19062
|
+
through: holding.shippedThrough,
|
|
19063
|
+
since: now
|
|
19064
|
+
});
|
|
19065
|
+
continue;
|
|
19066
|
+
}
|
|
19067
|
+
clocks[holding.sessionUuid] = {
|
|
19068
|
+
shipped_through: known.through,
|
|
19069
|
+
since: new Date(known.since).toISOString()
|
|
19070
|
+
};
|
|
19071
|
+
}
|
|
19072
|
+
for (const session of [...this.progress.keys()])
|
|
19073
|
+
if (!waiting.has(session)) this.progress.delete(session);
|
|
19074
|
+
const stalled = holdings.map((holding) => ({
|
|
19075
|
+
holding,
|
|
19076
|
+
since: this.progress.get(holding.sessionUuid)?.since ?? now
|
|
19077
|
+
})).filter((entry2) => now - entry2.since >= this.policy.stallGraceMs);
|
|
19078
|
+
let held = 0;
|
|
19079
|
+
for (const { holding } of stalled)
|
|
19080
|
+
held += holding.eventBytes + holding.bodyBytes;
|
|
19081
|
+
const ceiling = ceilingFor(
|
|
19082
|
+
this.policy.ceilingBytes,
|
|
19083
|
+
this.policy.freeBytes(this.walDir),
|
|
19084
|
+
held
|
|
19085
|
+
);
|
|
19086
|
+
const drops = [];
|
|
19087
|
+
if (held > ceiling) {
|
|
19088
|
+
stalled.sort(
|
|
19089
|
+
(a, b5) => a.since - b5.since || a.holding.lastActivityAt - b5.holding.lastActivityAt || (a.holding.sessionUuid < b5.holding.sessionUuid ? -1 : 1)
|
|
19090
|
+
);
|
|
19091
|
+
for (const { holding, since } of stalled) {
|
|
19092
|
+
if (held <= ceiling) break;
|
|
19093
|
+
if (holding.bodyBytes === 0) continue;
|
|
19094
|
+
const bytes = this.wal.dropSessionBodies(holding.sessionUuid);
|
|
19095
|
+
if (bytes === 0) continue;
|
|
19096
|
+
const drop = {
|
|
19097
|
+
session_uuid: holding.sessionUuid,
|
|
19098
|
+
bytes,
|
|
19099
|
+
shipped_through: holding.shippedThrough,
|
|
19100
|
+
last_seq: holding.lastSeq,
|
|
19101
|
+
stalled_since: new Date(since).toISOString(),
|
|
19102
|
+
dropped_at: new Date(now).toISOString(),
|
|
19103
|
+
stalled_bytes: held,
|
|
19104
|
+
ceiling_bytes: ceiling
|
|
19105
|
+
};
|
|
19106
|
+
held -= bytes;
|
|
19107
|
+
drops.push(drop);
|
|
19108
|
+
try {
|
|
19109
|
+
onDrop(drop);
|
|
19110
|
+
} catch {
|
|
19111
|
+
}
|
|
19112
|
+
}
|
|
19113
|
+
}
|
|
19114
|
+
this.remember(now, ceiling, held, stalled.length, drops, clocks);
|
|
19115
|
+
return drops;
|
|
19116
|
+
}
|
|
19117
|
+
/**
|
|
19118
|
+
* Write what this check saw to `ceiling.json`, when it says something the
|
|
19119
|
+
* file does not. A host where no cursor stood still between two checks,
|
|
19120
|
+
* and nothing was dropped, writes no file at all.
|
|
19121
|
+
*/
|
|
19122
|
+
remember(now, ceiling, held, stalledSessions, drops, clocks) {
|
|
19123
|
+
const prior = this.state;
|
|
19124
|
+
const kept = [...prior?.drops ?? [], ...drops].filter((drop) => now - Date.parse(drop.dropped_at) < this.keepDropsMs).slice(-DROPS_KEPT);
|
|
19125
|
+
if (prior === void 0 && stalledSessions === 0 && kept.length === 0 && Object.keys(clocks).length === 0)
|
|
19126
|
+
return;
|
|
19127
|
+
const next = {
|
|
19128
|
+
schema: STATE_SCHEMA,
|
|
19129
|
+
checked_at: new Date(now).toISOString(),
|
|
19130
|
+
ceiling_bytes: ceiling,
|
|
19131
|
+
stall_grace_ms: this.policy.stallGraceMs,
|
|
19132
|
+
stalled_bytes: held,
|
|
19133
|
+
stalled_sessions: stalledSessions,
|
|
19134
|
+
drops: kept,
|
|
19135
|
+
stall_clocks: clocks
|
|
19136
|
+
};
|
|
19137
|
+
const changed = this.unsaved || prior === void 0 || prior.stalled_sessions !== next.stalled_sessions || prior.drops.length !== next.drops.length || prior.drops.at(-1)?.dropped_at !== next.drops.at(-1)?.dropped_at || !sameClocks(prior.stall_clocks, next.stall_clocks) || next.stalled_sessions > 0 && (prior.stalled_bytes !== next.stalled_bytes || prior.ceiling_bytes !== next.ceiling_bytes);
|
|
19138
|
+
this.state = next;
|
|
19139
|
+
if (!changed) return;
|
|
19140
|
+
try {
|
|
19141
|
+
writeSensitiveFileAtomic(
|
|
19142
|
+
join16(this.walDir, STATE_FILE),
|
|
19143
|
+
JSON.stringify(next)
|
|
19144
|
+
);
|
|
19145
|
+
this.unsaved = false;
|
|
19146
|
+
} catch (error) {
|
|
19147
|
+
this.unsaved = true;
|
|
19148
|
+
this.log(
|
|
19149
|
+
`WAL ceiling: could not write ${STATE_FILE}: ${error instanceof Error ? error.message : String(error)}`
|
|
19150
|
+
);
|
|
19151
|
+
}
|
|
19152
|
+
}
|
|
19153
|
+
};
|
|
19154
|
+
}
|
|
19155
|
+
});
|
|
19156
|
+
|
|
18685
19157
|
// ../../packages/tacho/src/cli/status.ts
|
|
18686
19158
|
import { existsSync as existsSync14 } from "node:fs";
|
|
18687
19159
|
import { dirname as dirname10 } from "node:path";
|
|
@@ -18828,6 +19300,7 @@ async function agentStatus(deps) {
|
|
|
18828
19300
|
host.host_enrollment_id
|
|
18829
19301
|
) : void 0;
|
|
18830
19302
|
const walStats = new Wal(deps.paths.wal).stats();
|
|
19303
|
+
const ceilingState = readWalCeilingState(deps.paths.wal);
|
|
18831
19304
|
const gateway = gatewayOf(daemon);
|
|
18832
19305
|
const routedHarnesses = host.harnesses.filter(isBrokerableHarness);
|
|
18833
19306
|
const baseUrlHarnesses = host.harnesses.filter(isModelRoutedHarness);
|
|
@@ -18924,12 +19397,49 @@ async function agentStatus(deps) {
|
|
|
18924
19397
|
wal: {
|
|
18925
19398
|
sessions: walStats.sessions,
|
|
18926
19399
|
unshipped: walStats.unshipped,
|
|
18927
|
-
...walStats.oldestUnshippedAt !== void 0 ? { oldest_unshipped_at: walStats.oldestUnshippedAt } : {}
|
|
19400
|
+
...walStats.oldestUnshippedAt !== void 0 ? { oldest_unshipped_at: walStats.oldestUnshippedAt } : {},
|
|
19401
|
+
...ceilingState !== void 0 ? {
|
|
19402
|
+
ceiling: {
|
|
19403
|
+
checked_at: ceilingState.checked_at,
|
|
19404
|
+
ceiling_bytes: ceilingState.ceiling_bytes,
|
|
19405
|
+
stall_grace_ms: ceilingState.stall_grace_ms,
|
|
19406
|
+
stalled_bytes: ceilingState.stalled_bytes,
|
|
19407
|
+
stalled_sessions: ceilingState.stalled_sessions,
|
|
19408
|
+
drops: ceilingState.drops
|
|
19409
|
+
}
|
|
19410
|
+
} : {}
|
|
18928
19411
|
},
|
|
18929
19412
|
...shipping !== void 0 ? { shipping } : {}
|
|
18930
19413
|
};
|
|
18931
19414
|
return report;
|
|
18932
19415
|
}
|
|
19416
|
+
function formatBytes(bytes) {
|
|
19417
|
+
if (bytes < 1024) return `${bytes} bytes`;
|
|
19418
|
+
if (bytes < 1024 ** 2) return `${(bytes / 1024).toFixed(1)} KiB`;
|
|
19419
|
+
if (bytes < 1024 ** 3) return `${(bytes / 1024 ** 2).toFixed(1)} MiB`;
|
|
19420
|
+
return `${(bytes / 1024 ** 3).toFixed(1)} GiB`;
|
|
19421
|
+
}
|
|
19422
|
+
function ceilingLines(ceiling) {
|
|
19423
|
+
const lines = [];
|
|
19424
|
+
if (ceiling.stalled_sessions > 0) {
|
|
19425
|
+
const minutes = Math.round(ceiling.stall_grace_ms / 6e4);
|
|
19426
|
+
const one = ceiling.stalled_sessions === 1;
|
|
19427
|
+
const who = `${ceiling.stalled_sessions} session${one ? " has" : "s have"} shipped nothing for at least ${minutes} minute${minutes === 1 ? "" : "s"} and ${one ? "holds" : "hold"} ${formatBytes(ceiling.stalled_bytes)}`;
|
|
19428
|
+
lines.push(
|
|
19429
|
+
ceiling.stalled_bytes > ceiling.ceiling_bytes ? `Ceiling OVER: ${who}, more than the ${formatBytes(ceiling.ceiling_bytes)} ceiling` : `Ceiling ${who} of the ${formatBytes(ceiling.ceiling_bytes)} ceiling`
|
|
19430
|
+
);
|
|
19431
|
+
}
|
|
19432
|
+
const newestFirst = [...ceiling.drops].reverse();
|
|
19433
|
+
for (const drop of newestFirst.slice(0, CEILING_DROPS_SHOWN))
|
|
19434
|
+
lines.push(
|
|
19435
|
+
`Dropped session ${drop.session_uuid} went over the WAL ceiling at ${drop.dropped_at}: ${formatBytes(drop.bytes)} of stored content removed, events ${drop.shipped_through + 1} to ${drop.last_seq} ship without it`
|
|
19436
|
+
);
|
|
19437
|
+
if (newestFirst.length > CEILING_DROPS_SHOWN)
|
|
19438
|
+
lines.push(
|
|
19439
|
+
` ${newestFirst.length - CEILING_DROPS_SHOWN} earlier drop${newestFirst.length - CEILING_DROPS_SHOWN === 1 ? "" : "s"} in \`oxagen agent status --json\``
|
|
19440
|
+
);
|
|
19441
|
+
return lines;
|
|
19442
|
+
}
|
|
18933
19443
|
function printStatus(report, deps) {
|
|
18934
19444
|
const h = report.host;
|
|
18935
19445
|
if (h === void 0) {
|
|
@@ -19061,12 +19571,14 @@ function printStatus(report, deps) {
|
|
|
19061
19571
|
deps.out(
|
|
19062
19572
|
`WAL ${wal.sessions} session files, ${wal.unshipped} events unshipped${wal.oldest_unshipped_at !== void 0 ? ` (oldest ${wal.oldest_unshipped_at})` : ""}`
|
|
19063
19573
|
);
|
|
19574
|
+
if (wal.ceiling !== void 0)
|
|
19575
|
+
for (const line of ceilingLines(wal.ceiling)) deps.out(line);
|
|
19064
19576
|
if (shipping !== void 0)
|
|
19065
19577
|
deps.out(
|
|
19066
19578
|
`Shipping ${shipping.healthy ? "ok" : "FAILING"}: ${shipping.detail}`
|
|
19067
19579
|
);
|
|
19068
19580
|
}
|
|
19069
|
-
var SHIPPING_STALL_MS, TIER_RANK;
|
|
19581
|
+
var SHIPPING_STALL_MS, TIER_RANK, CEILING_DROPS_SHOWN;
|
|
19070
19582
|
var init_status = __esm({
|
|
19071
19583
|
"../../packages/tacho/src/cli/status.ts"() {
|
|
19072
19584
|
"use strict";
|
|
@@ -19078,6 +19590,7 @@ var init_status = __esm({
|
|
|
19078
19590
|
init_settings_writer();
|
|
19079
19591
|
init_stella_writer();
|
|
19080
19592
|
init_wal();
|
|
19593
|
+
init_wal_ceiling();
|
|
19081
19594
|
init_agents();
|
|
19082
19595
|
init_wire();
|
|
19083
19596
|
init_deps();
|
|
@@ -19086,6 +19599,7 @@ var init_status = __esm({
|
|
|
19086
19599
|
init_policy_mode();
|
|
19087
19600
|
SHIPPING_STALL_MS = 10 * 6e4;
|
|
19088
19601
|
TIER_RANK = { observe: 0, harness: 1, gateway: 2 };
|
|
19602
|
+
CEILING_DROPS_SHOWN = 5;
|
|
19089
19603
|
}
|
|
19090
19604
|
});
|
|
19091
19605
|
|
|
@@ -19864,8 +20378,8 @@ function harnessFileProblems(harnesses, deps) {
|
|
|
19864
20378
|
if (harnesses.includes("codex"))
|
|
19865
20379
|
check2(deps.paths.codexHooks, deps.readCodexHooks, hooksShapeProblem);
|
|
19866
20380
|
if (harnesses.includes("cursor")) {
|
|
19867
|
-
const
|
|
19868
|
-
if (
|
|
20381
|
+
const relative9 = absoluteHookCommandProblem(deps.runtime.hookCommand);
|
|
20382
|
+
if (relative9 !== void 0) problems.push(relative9);
|
|
19869
20383
|
for (const path2 of deps.paths.cursorHooks)
|
|
19870
20384
|
check2(path2, () => deps.readCursorHooks(path2), cursorHooksShapeProblem);
|
|
19871
20385
|
}
|
|
@@ -22342,6 +22856,13 @@ function steeringContext(body2) {
|
|
|
22342
22856
|
tokens: clampU32(assembly.tokens + delivered)
|
|
22343
22857
|
};
|
|
22344
22858
|
}
|
|
22859
|
+
function steeringFactsOf(steering) {
|
|
22860
|
+
if (steering === void 0) return {};
|
|
22861
|
+
return {
|
|
22862
|
+
steering_tokens: steering.tokens,
|
|
22863
|
+
steering_tokens_basis: "estimated"
|
|
22864
|
+
};
|
|
22865
|
+
}
|
|
22345
22866
|
var REQUEST_FULL_DIGEST_ATTR, SYSTEM_CONTEXT_PARTS_OMITTED_ATTR, MEMORY_REQUESTS, LISTED_PER_TURN, U32_MAX, NAME_MAX, tokenSourceFacts, SystemContextMemory, SHARED_SYSTEM_CONTEXT_MEMORY, CONVERSATION_FIELDS2, STEERING_ASSEMBLY_PART, SystemContextTracker;
|
|
22346
22867
|
var init_system_context = __esm({
|
|
22347
22868
|
"../../packages/tacho/src/claude-code/system-context.ts"() {
|
|
@@ -22435,20 +22956,16 @@ var init_system_context = __esm({
|
|
|
22435
22956
|
* the frame's attrs, and `turn` a key that changes when the turn does.
|
|
22436
22957
|
*/
|
|
22437
22958
|
measure(content, attrs2, turn) {
|
|
22438
|
-
const facts = {};
|
|
22439
|
-
const steering = this.steering;
|
|
22440
|
-
if (steering !== void 0) {
|
|
22441
|
-
facts.steering_tokens = steering.tokens;
|
|
22442
|
-
facts.steering_tokens_basis = "estimated";
|
|
22443
|
-
}
|
|
22444
22959
|
const recorded = requestOf(content);
|
|
22445
22960
|
const resolved = recorded === void 0 ? void 0 : resolveRequest(recorded.request, this.memory);
|
|
22446
22961
|
if (recorded === void 0 || resolved === void 0)
|
|
22447
|
-
return this.checked(
|
|
22962
|
+
return this.checked(steeringFactsOf(this.steering), {}, () => {
|
|
22448
22963
|
});
|
|
22449
22964
|
const fullDigest = attrs2?.[REQUEST_FULL_DIGEST_ATTR];
|
|
22450
22965
|
const key = isSha256Digest(fullDigest) ? fullDigest : recorded.request[PRIOR_MEMBER] === void 0 ? digestBytes(recorded.text) : void 0;
|
|
22451
22966
|
if (key !== void 0) this.memory.set(key, resolved);
|
|
22967
|
+
const steering = resolved.tools.length > 0 ? this.steering : void 0;
|
|
22968
|
+
const facts = steeringFactsOf(steering);
|
|
22452
22969
|
const parts = [
|
|
22453
22970
|
...resolved.system,
|
|
22454
22971
|
...resolved.instructions,
|
|
@@ -22478,6 +22995,19 @@ var init_system_context = __esm({
|
|
|
22478
22995
|
if (this.listed.length > LISTED_PER_TURN) this.listed.shift();
|
|
22479
22996
|
});
|
|
22480
22997
|
}
|
|
22998
|
+
/**
|
|
22999
|
+
* The token sources of a model call whose request the recorder never saw:
|
|
23000
|
+
* the counted OTel or transcript row of a call the proxy did not carry
|
|
23001
|
+
* (#4493). Only the steering count is known without the request. The tool
|
|
23002
|
+
* definition count, the context frame count, and the system context stay
|
|
23003
|
+
* absent, never zero. Nothing changes on the tracker, so there is nothing
|
|
23004
|
+
* to commit. The caller asks only for a call that carries the session's
|
|
23005
|
+
* conversation, since a side call carries no steering.
|
|
23006
|
+
*/
|
|
23007
|
+
measureUnseen() {
|
|
23008
|
+
return this.checked(steeringFactsOf(this.steering), {}, () => {
|
|
23009
|
+
}).facts;
|
|
23010
|
+
}
|
|
22481
23011
|
/**
|
|
22482
23012
|
* Hand back facts the envelope accepts, or none. A body the envelope
|
|
22483
23013
|
* refuses loses its frame, so a measurement that fails the schema is
|
|
@@ -23841,6 +24371,10 @@ var init_transcript = __esm({
|
|
|
23841
24371
|
});
|
|
23842
24372
|
|
|
23843
24373
|
// ../../packages/tacho/src/claude-code/recorder.ts
|
|
24374
|
+
function onSessionConversation(querySource) {
|
|
24375
|
+
if (querySource === void 0) return false;
|
|
24376
|
+
return MAIN_CONVERSATION_QUERY_SOURCES.has(querySource) || querySource.startsWith("repl_main_thread:");
|
|
24377
|
+
}
|
|
23844
24378
|
function compact(value) {
|
|
23845
24379
|
const out = {};
|
|
23846
24380
|
for (const [key, member2] of Object.entries(value)) {
|
|
@@ -23917,7 +24451,7 @@ function inChainOrder(events) {
|
|
|
23917
24451
|
}
|
|
23918
24452
|
return out;
|
|
23919
24453
|
}
|
|
23920
|
-
var NO_SIGHTING, PROMPT_DUPLICATE_OF_ATTR, AFTER_STOP_ATTR, SUBAGENT_TYPE_AMBIGUOUS_ATTR, SessionRecorder;
|
|
24454
|
+
var NO_SIGHTING, MAIN_CONVERSATION_QUERY_SOURCES, PROMPT_DUPLICATE_OF_ATTR, AFTER_STOP_ATTR, SUBAGENT_TYPE_AMBIGUOUS_ATTR, SessionRecorder;
|
|
23921
24455
|
var init_recorder = __esm({
|
|
23922
24456
|
"../../packages/tacho/src/claude-code/recorder.ts"() {
|
|
23923
24457
|
"use strict";
|
|
@@ -23938,6 +24472,10 @@ var init_recorder = __esm({
|
|
|
23938
24472
|
init_transcript();
|
|
23939
24473
|
NO_SIGHTING = { attrs: {}, commit: () => {
|
|
23940
24474
|
} };
|
|
24475
|
+
MAIN_CONVERSATION_QUERY_SOURCES = /* @__PURE__ */ new Set([
|
|
24476
|
+
"repl_main_thread",
|
|
24477
|
+
"sdk"
|
|
24478
|
+
]);
|
|
23941
24479
|
PROMPT_DUPLICATE_OF_ATTR = "oxagen.prompt_duplicate_of";
|
|
23942
24480
|
AFTER_STOP_ATTR = "oxagen.after_stop";
|
|
23943
24481
|
SUBAGENT_TYPE_AMBIGUOUS_ATTR = "oxagen.subagent_type_ambiguous";
|
|
@@ -24740,6 +25278,24 @@ var init_recorder = __esm({
|
|
|
24740
25278
|
return { attrs: { [LLM_CALL_DUPLICATE_OF_ATTR]: verdict.of }, commit };
|
|
24741
25279
|
return { attrs: {}, commit };
|
|
24742
25280
|
}
|
|
25281
|
+
/**
|
|
25282
|
+
* The body of an OTel or transcript model call, with the token sources the
|
|
25283
|
+
* recorder knows without the call's request (#4493). Only the counted row,
|
|
25284
|
+
* the first sighting of its call, takes them. A stamped duplicate is never
|
|
25285
|
+
* summed, and the rollup joins a stamped proxy row back for the members the
|
|
25286
|
+
* counted row lacks. The steering count is the one source known without
|
|
25287
|
+
* the request, so the tool definitions and the system context stay absent
|
|
25288
|
+
* (ADR-062, amendment of 2026-10-02). A member the producer set itself
|
|
25289
|
+
* wins, as on a proxied call. Only a call on the session's own
|
|
25290
|
+
* conversation comes here: an OTel record whose `query_source` says so
|
|
25291
|
+
* ({@link onSessionConversation}), or a transcript `assistant` record,
|
|
25292
|
+
* since Claude Code writes no side call to the transcript.
|
|
25293
|
+
*/
|
|
25294
|
+
withUnseenRequestSources(body2, attrs2) {
|
|
25295
|
+
if (attrs2[LLM_CALL_DUPLICATE_OF_ATTR] !== void 0) return body2;
|
|
25296
|
+
const facts = this.systemContext.measureUnseen();
|
|
25297
|
+
return Object.keys(facts).length === 0 ? body2 : { ...facts, ...body2 };
|
|
25298
|
+
}
|
|
24743
25299
|
/**
|
|
24744
25300
|
* The attrs a `tool_call` carries, or undefined when the chain already
|
|
24745
25301
|
* holds this call and the row must not be sealed at all.
|
|
@@ -25149,7 +25705,7 @@ var init_recorder = __esm({
|
|
|
25149
25705
|
}
|
|
25150
25706
|
const event = this.seal(
|
|
25151
25707
|
draft.kind,
|
|
25152
|
-
draft.body,
|
|
25708
|
+
draft.kind === "llm_call" && draft.source === "otel_log" && onSessionConversation(draft.standard.context.query_source) ? this.withUnseenRequestSources(draft.body, duplicate) : draft.body,
|
|
25153
25709
|
{
|
|
25154
25710
|
ts: draft.ts,
|
|
25155
25711
|
source: draft.source,
|
|
@@ -25205,6 +25761,8 @@ var init_recorder = __esm({
|
|
|
25205
25761
|
body2 = withoutUsage(body2);
|
|
25206
25762
|
duplicate = { [LLM_CALL_DUPLICATE_OF_ATTR]: "transcript" };
|
|
25207
25763
|
}
|
|
25764
|
+
if (draft.kind === "llm_call")
|
|
25765
|
+
body2 = this.withUnseenRequestSources(body2, duplicate);
|
|
25208
25766
|
let content = draft.content;
|
|
25209
25767
|
if (this.isSealedPrompt(draft.kind, body2)) {
|
|
25210
25768
|
content = void 0;
|
|
@@ -26598,25 +27156,19 @@ async function runContained(command2, deps) {
|
|
|
26598
27156
|
return 1;
|
|
26599
27157
|
}
|
|
26600
27158
|
const token = deps.env[CONTAINED_GITHUB_TOKEN_ENV];
|
|
26601
|
-
|
|
26602
|
-
if (repository !== void 0 && (token === void 0 || token.length === 0)) {
|
|
27159
|
+
if (token !== void 0 && token.length > 0) {
|
|
26603
27160
|
deps.err(
|
|
26604
|
-
|
|
26605
|
-
);
|
|
26606
|
-
return 2;
|
|
26607
|
-
}
|
|
26608
|
-
if (token !== void 0 && token.length > 0 && repository === void 0) {
|
|
26609
|
-
deps.err(
|
|
26610
|
-
`${CONTAINED_GITHUB_TOKEN_ENV} is set; name its one repository with --github-repository owner/name.`
|
|
27161
|
+
`${CONTAINED_GITHUB_TOKEN_ENV} is no longer read. A contained run reaches GitHub through Oxagen's Git custody, which gets a token from the workspace's GitHub App for each request. Remove the variable and the step that mints it, and bind the repository to the workspace.`
|
|
26611
27162
|
);
|
|
26612
27163
|
return 2;
|
|
26613
27164
|
}
|
|
27165
|
+
const repository = command2.githubRepository;
|
|
26614
27166
|
const body2 = JSON.stringify({
|
|
26615
27167
|
workspace: command2.workspace ?? deps.cwd,
|
|
26616
27168
|
harness,
|
|
26617
27169
|
args: command2.args,
|
|
26618
27170
|
image,
|
|
26619
|
-
...repository !== void 0
|
|
27171
|
+
...repository !== void 0 ? { github: { repository } } : {}
|
|
26620
27172
|
});
|
|
26621
27173
|
let exitCode;
|
|
26622
27174
|
let failure2;
|
|
@@ -26936,11 +27488,11 @@ var init_move_commands = __esm({
|
|
|
26936
27488
|
|
|
26937
27489
|
// ../../packages/tacho/src/host/work-orders.ts
|
|
26938
27490
|
import { readdirSync as readdirSync9, rmSync as rmSync4 } from "node:fs";
|
|
26939
|
-
import { join as
|
|
27491
|
+
import { join as join17 } from "node:path";
|
|
26940
27492
|
function orderFile(paths, id) {
|
|
26941
27493
|
if (!WORK_ORDER_ID_PATTERN.test(id))
|
|
26942
27494
|
throw new Error(`${JSON.stringify(id)} is not a work order id`);
|
|
26943
|
-
return
|
|
27495
|
+
return join17(paths.workOrders, `${id}.json`);
|
|
26944
27496
|
}
|
|
26945
27497
|
function readWorkOrder(paths, id) {
|
|
26946
27498
|
let raw;
|
|
@@ -30756,135 +31308,27 @@ var init_configuration = __esm({
|
|
|
30756
31308
|
});
|
|
30757
31309
|
|
|
30758
31310
|
// ../../packages/tacho/src/contained/github.ts
|
|
30759
|
-
|
|
30760
|
-
request as httpRequest
|
|
30761
|
-
} from "node:http";
|
|
30762
|
-
import { request as httpsRequest } from "node:https";
|
|
30763
|
-
async function verifyRunGitHubToken(grant, fetch2, upstreams = GITHUB_UPSTREAMS) {
|
|
30764
|
-
const response = await fetch2(
|
|
30765
|
-
`${upstreams.api}/installation/repositories?per_page=2`,
|
|
30766
|
-
{
|
|
30767
|
-
method: "GET",
|
|
30768
|
-
headers: { ...API_HEADERS, authorization: `Bearer ${grant.token}` },
|
|
30769
|
-
signal: AbortSignal.timeout(15e3)
|
|
30770
|
-
}
|
|
30771
|
-
);
|
|
30772
|
-
if (!response.ok)
|
|
30773
|
-
throw new Error(
|
|
30774
|
-
`GitHub refused the run's installation token (${response.status}); mint a new one for this run`
|
|
30775
|
-
);
|
|
30776
|
-
const body2 = JSON.parse(await response.text());
|
|
30777
|
-
const only = body2.repositories?.[0]?.full_name;
|
|
30778
|
-
if (body2.total_count !== 1 || only === void 0 || only.toLowerCase() !== grant.repository.toLowerCase())
|
|
30779
|
-
throw new Error(
|
|
30780
|
-
`The run's GitHub token must reach ${grant.repository} and no other repository; mint it with repositories: [${grant.repository.split("/")[1]}]`
|
|
30781
|
-
);
|
|
30782
|
-
}
|
|
30783
|
-
async function revokeRunGitHubToken(token, fetch2, upstreams = GITHUB_UPSTREAMS) {
|
|
30784
|
-
const response = await fetch2(`${upstreams.api}/installation/token`, {
|
|
30785
|
-
method: "DELETE",
|
|
30786
|
-
headers: { ...API_HEADERS, authorization: `Bearer ${token}` },
|
|
30787
|
-
signal: AbortSignal.timeout(15e3)
|
|
30788
|
-
});
|
|
30789
|
-
if (response.status === 204) return "revoked";
|
|
30790
|
-
if (response.status === 401) return "already_invalid";
|
|
30791
|
-
throw new Error(`GitHub did not revoke the run's token (${response.status})`);
|
|
30792
|
-
}
|
|
30793
|
-
function gitHubTarget(path2, repository, upstreams = GITHUB_UPSTREAMS) {
|
|
30794
|
-
const wanted = repository.toLowerCase();
|
|
31311
|
+
function custodyGitPath(path2, repository) {
|
|
30795
31312
|
const git6 = GIT_ROUTE.exec(path2);
|
|
30796
|
-
if (git6)
|
|
30797
|
-
|
|
30798
|
-
|
|
30799
|
-
|
|
30800
|
-
return
|
|
30801
|
-
|
|
30802
|
-
url: `${upstreams.git}/${owner}/${repo}.git/${rest}`
|
|
30803
|
-
};
|
|
30804
|
-
}
|
|
30805
|
-
const api = API_ROUTE.exec(path2);
|
|
30806
|
-
if (api) {
|
|
30807
|
-
const [, owner, name, rest = "", query = ""] = api;
|
|
30808
|
-
if (`${owner}/${name}`.toLowerCase() !== wanted) return void 0;
|
|
30809
|
-
if (rest.split("/").some((segment) => segment === "." || segment === ".."))
|
|
30810
|
-
return void 0;
|
|
30811
|
-
return {
|
|
30812
|
-
kind: "api",
|
|
30813
|
-
url: `${upstreams.api}/repos/${owner}/${name}${rest}${query}`
|
|
30814
|
-
};
|
|
30815
|
-
}
|
|
30816
|
-
return void 0;
|
|
30817
|
-
}
|
|
30818
|
-
function forwardToGitHub(target2, token, incoming, outgoing) {
|
|
30819
|
-
const url = new URL(target2.url);
|
|
30820
|
-
const headers = {
|
|
30821
|
-
"user-agent": "oxagen-contained-launcher",
|
|
30822
|
-
authorization: target2.kind === "git" ? `Basic ${Buffer.from(`x-access-token:${token}`).toString("base64")}` : `Bearer ${token}`
|
|
30823
|
-
};
|
|
30824
|
-
for (const name of FORWARDED) {
|
|
30825
|
-
const value = incoming.headers[name];
|
|
30826
|
-
if (typeof value === "string") headers[name] = value;
|
|
30827
|
-
}
|
|
30828
|
-
const send4 = url.protocol === "https:" ? httpsRequest : httpRequest;
|
|
30829
|
-
const upstream = send4(
|
|
30830
|
-
url,
|
|
30831
|
-
{ method: incoming.method, headers, timeout: 12e4 },
|
|
30832
|
-
(response) => {
|
|
30833
|
-
const passed = {};
|
|
30834
|
-
for (const [name, value] of Object.entries(response.headers)) {
|
|
30835
|
-
if (value === void 0) continue;
|
|
30836
|
-
if (name === "set-cookie" || name === "connection") continue;
|
|
30837
|
-
passed[name] = value;
|
|
30838
|
-
}
|
|
30839
|
-
outgoing.writeHead(response.statusCode ?? 502, passed);
|
|
30840
|
-
response.pipe(outgoing);
|
|
30841
|
-
}
|
|
30842
|
-
);
|
|
30843
|
-
upstream.on("timeout", () => upstream.destroy(new Error("GitHub timed out")));
|
|
30844
|
-
upstream.on("error", () => {
|
|
30845
|
-
if (!outgoing.headersSent) {
|
|
30846
|
-
outgoing.writeHead(502, { "content-type": "application/json" });
|
|
30847
|
-
outgoing.end(JSON.stringify({ error: "GitHub could not be reached" }));
|
|
30848
|
-
} else outgoing.destroy();
|
|
30849
|
-
});
|
|
30850
|
-
outgoing.on("close", () => upstream.destroy());
|
|
30851
|
-
incoming.pipe(upstream);
|
|
31313
|
+
if (!git6) return void 0;
|
|
31314
|
+
const [, owner, name, rest] = git6;
|
|
31315
|
+
const repo = name.replace(/\.git$/, "");
|
|
31316
|
+
if (`${owner}/${repo}`.toLowerCase() !== repository.toLowerCase())
|
|
31317
|
+
return void 0;
|
|
31318
|
+
return `/github/${owner}/${repo}.git/${rest}`;
|
|
30852
31319
|
}
|
|
30853
|
-
var containedGitHubSchema,
|
|
31320
|
+
var containedGitHubSchema, SEGMENT, GIT_ROUTE;
|
|
30854
31321
|
var init_github2 = __esm({
|
|
30855
31322
|
"../../packages/tacho/src/contained/github.ts"() {
|
|
30856
31323
|
"use strict";
|
|
30857
31324
|
init_zod();
|
|
30858
31325
|
containedGitHubSchema = external_exports.object({
|
|
30859
|
-
repository: external_exports.string().regex(/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})\/[A-Za-z0-9._-]{1,100}$/).refine((value) => !/\/\.\.?$/.test(value), "Invalid repository name")
|
|
30860
|
-
/** Installation access tokens carry the `ghs_` prefix. */
|
|
30861
|
-
token: external_exports.string().regex(/^ghs_[A-Za-z0-9_]{20,255}$/)
|
|
31326
|
+
repository: external_exports.string().regex(/^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})\/[A-Za-z0-9._-]{1,100}$/).refine((value) => !/\/\.\.?$/.test(value), "Invalid repository name")
|
|
30862
31327
|
}).strict();
|
|
30863
|
-
GITHUB_UPSTREAMS = {
|
|
30864
|
-
api: "https://api.github.com",
|
|
30865
|
-
git: "https://github.com"
|
|
30866
|
-
};
|
|
30867
|
-
API_HEADERS = {
|
|
30868
|
-
accept: "application/vnd.github+json",
|
|
30869
|
-
"x-github-api-version": "2022-11-28",
|
|
30870
|
-
"user-agent": "oxagen-contained-launcher"
|
|
30871
|
-
};
|
|
30872
31328
|
SEGMENT = "[A-Za-z0-9_-][A-Za-z0-9._-]*";
|
|
30873
31329
|
GIT_ROUTE = new RegExp(
|
|
30874
31330
|
`^/github/git/(${SEGMENT})/(${SEGMENT})/(info/refs\\?service=git-(?:upload|receive)-pack|git-upload-pack|git-receive-pack)$`
|
|
30875
31331
|
);
|
|
30876
|
-
API_ROUTE = new RegExp(
|
|
30877
|
-
`^/github/api/repos/(${SEGMENT})/(${SEGMENT})((?:/${SEGMENT})*)(\\?[A-Za-z0-9_.,=&%+-]*)?$`
|
|
30878
|
-
);
|
|
30879
|
-
FORWARDED = [
|
|
30880
|
-
"accept",
|
|
30881
|
-
"accept-encoding",
|
|
30882
|
-
"content-type",
|
|
30883
|
-
"content-length",
|
|
30884
|
-
"content-encoding",
|
|
30885
|
-
"git-protocol",
|
|
30886
|
-
"x-github-api-version"
|
|
30887
|
-
];
|
|
30888
31332
|
}
|
|
30889
31333
|
});
|
|
30890
31334
|
|
|
@@ -30962,17 +31406,38 @@ function containedBridgeHandler(options) {
|
|
|
30962
31406
|
);
|
|
30963
31407
|
return;
|
|
30964
31408
|
}
|
|
30965
|
-
|
|
30966
|
-
|
|
30967
|
-
|
|
30968
|
-
|
|
30969
|
-
|
|
30970
|
-
|
|
30971
|
-
if (
|
|
30972
|
-
options.
|
|
30973
|
-
|
|
31409
|
+
const github = options.github;
|
|
31410
|
+
const target2 = github === void 0 ? void 0 : custodyGitPath(path2, github.repository);
|
|
31411
|
+
if (github !== void 0 && target2 !== void 0) {
|
|
31412
|
+
const lease = github.lease();
|
|
31413
|
+
const body2 = lease.body;
|
|
31414
|
+
const token = lease.status === 200 ? body2?.token : void 0;
|
|
31415
|
+
if (typeof token !== "string") {
|
|
31416
|
+
options.githubRefused?.(path2);
|
|
31417
|
+
response.writeHead(403, {
|
|
31418
|
+
"content-type": "text/plain",
|
|
31419
|
+
"cache-control": "no-store"
|
|
31420
|
+
});
|
|
31421
|
+
response.end(
|
|
31422
|
+
`Oxagen issued no GitHub credential for this run. ${typeof body2?.error === "string" ? body2.error : "Check the session and the host's enrollment."}`
|
|
31423
|
+
);
|
|
30974
31424
|
return;
|
|
30975
31425
|
}
|
|
31426
|
+
try {
|
|
31427
|
+
const headers = {
|
|
31428
|
+
authorization: `Basic ${Buffer.from(`oxagen:${token}`).toString("base64")}`
|
|
31429
|
+
};
|
|
31430
|
+
for (const name of GIT_HEADERS) {
|
|
31431
|
+
const value = request3.headers[name];
|
|
31432
|
+
if (typeof value === "string") headers[name] = value;
|
|
31433
|
+
}
|
|
31434
|
+
request3.headers = headers;
|
|
31435
|
+
request3.url = target2;
|
|
31436
|
+
await github.handle(request3, response);
|
|
31437
|
+
} finally {
|
|
31438
|
+
github.release(token);
|
|
31439
|
+
}
|
|
31440
|
+
return;
|
|
30976
31441
|
}
|
|
30977
31442
|
options.refused(path2);
|
|
30978
31443
|
send(response, 403, {
|
|
@@ -31010,16 +31475,23 @@ async function startContainedBridge(options) {
|
|
|
31010
31475
|
}
|
|
31011
31476
|
};
|
|
31012
31477
|
}
|
|
31478
|
+
var GIT_HEADERS;
|
|
31013
31479
|
var init_bridge = __esm({
|
|
31014
31480
|
"../../packages/tacho/src/contained/bridge.ts"() {
|
|
31015
31481
|
"use strict";
|
|
31016
31482
|
init_github2();
|
|
31483
|
+
GIT_HEADERS = [
|
|
31484
|
+
"content-type",
|
|
31485
|
+
"content-encoding",
|
|
31486
|
+
"git-protocol",
|
|
31487
|
+
"user-agent"
|
|
31488
|
+
];
|
|
31017
31489
|
}
|
|
31018
31490
|
});
|
|
31019
31491
|
|
|
31020
31492
|
// ../../packages/tacho/src/contained/workspace.ts
|
|
31021
31493
|
import { lstatSync as lstatSync5, readFileSync as readFileSync14, readdirSync as readdirSync10, realpathSync as realpathSync2 } from "node:fs";
|
|
31022
|
-
import { isAbsolute, join as
|
|
31494
|
+
import { isAbsolute, join as join18, relative, resolve as resolve6 } from "node:path";
|
|
31023
31495
|
function within(root, path2) {
|
|
31024
31496
|
const rel = relative(root, path2);
|
|
31025
31497
|
return rel === "" || !rel.startsWith("..") && !isAbsolute(rel);
|
|
@@ -31050,7 +31522,7 @@ function validateContainedWorkspace(workspace, sessionDirectory, mountInfo = rea
|
|
|
31050
31522
|
throw new Error(
|
|
31051
31523
|
"Remove local credential files from the contained checkout before launch"
|
|
31052
31524
|
);
|
|
31053
|
-
const path2 =
|
|
31525
|
+
const path2 = join18(directory, entry2);
|
|
31054
31526
|
const stat5 = lstatSync5(path2);
|
|
31055
31527
|
if (stat5.isSymbolicLink()) {
|
|
31056
31528
|
let target2;
|
|
@@ -31204,7 +31676,7 @@ import {
|
|
|
31204
31676
|
writeFileSync as writeFileSync2
|
|
31205
31677
|
} from "node:fs";
|
|
31206
31678
|
import { tmpdir } from "node:os";
|
|
31207
|
-
import { isAbsolute as isAbsolute2, join as
|
|
31679
|
+
import { isAbsolute as isAbsolute2, join as join19, relative as relative2 } from "node:path";
|
|
31208
31680
|
import { promisify } from "node:util";
|
|
31209
31681
|
async function launchContainedAgent(options) {
|
|
31210
31682
|
validateContainedArguments(options.request.harness, options.request.args);
|
|
@@ -31237,7 +31709,7 @@ async function launchContainedAgent(options) {
|
|
|
31237
31709
|
if (digest6 === void 0)
|
|
31238
31710
|
throw new Error("The operator's contained image is not installed");
|
|
31239
31711
|
const sessionId = `contained-${randomBytes8(16).toString("hex")}`;
|
|
31240
|
-
const directory = mkdtempSync(
|
|
31712
|
+
const directory = mkdtempSync(join19(tmpdir(), "oxagen-contained-"));
|
|
31241
31713
|
chmodSync6(directory, 448);
|
|
31242
31714
|
let prepared;
|
|
31243
31715
|
let containerCreated = false;
|
|
@@ -31258,7 +31730,7 @@ async function launchContainedAgent(options) {
|
|
|
31258
31730
|
for (const [name2, contents] of entries2) {
|
|
31259
31731
|
if (!/^[a-z0-9.-]+$/.test(name2))
|
|
31260
31732
|
throw new Error("Invalid contained configuration filename");
|
|
31261
|
-
writeFileSync2(
|
|
31733
|
+
writeFileSync2(join19(directory, name2), contents, {
|
|
31262
31734
|
mode: 256,
|
|
31263
31735
|
flag: "wx"
|
|
31264
31736
|
});
|
|
@@ -31337,7 +31809,7 @@ var init_launcher = __esm({
|
|
|
31337
31809
|
});
|
|
31338
31810
|
|
|
31339
31811
|
// ../../packages/tacho/src/contained/runner.ts
|
|
31340
|
-
import { join as
|
|
31812
|
+
import { join as join20 } from "node:path";
|
|
31341
31813
|
function containedLaunchEndpoint(host) {
|
|
31342
31814
|
const ingest = new URL(host.endpoints.ingest);
|
|
31343
31815
|
if (!ingest.pathname.endsWith("/tacho/events"))
|
|
@@ -31348,211 +31820,214 @@ function containedLaunchEndpoint(host) {
|
|
|
31348
31820
|
}
|
|
31349
31821
|
function createContainedRunner(options) {
|
|
31350
31822
|
const launched = /* @__PURE__ */ new Set();
|
|
31823
|
+
const repositories = /* @__PURE__ */ new Map();
|
|
31351
31824
|
const active2 = /* @__PURE__ */ new Map();
|
|
31352
31825
|
return {
|
|
31353
31826
|
launched: (harnessSessionId) => launched.has(harnessSessionId),
|
|
31827
|
+
githubRepository: (harnessSessionId) => repositories.get(harnessSessionId),
|
|
31354
31828
|
stop: (uuid) => active2.get(uuid)?.abort(),
|
|
31355
31829
|
stopAll: () => {
|
|
31356
31830
|
for (const controller of active2.values()) controller.abort();
|
|
31357
31831
|
},
|
|
31358
31832
|
run: async (raw, output, signal) => {
|
|
31359
31833
|
const input = containedRunRequestSchema.parse(raw);
|
|
31834
|
+
const host = options.host();
|
|
31835
|
+
if (host.host_status !== "active" || host.revoked_at !== null || Date.parse(host.expires_at) <= Date.now())
|
|
31836
|
+
throw new Error("This enrollment cannot start a contained run");
|
|
31837
|
+
if (!host.gateway_api_key)
|
|
31838
|
+
throw new Error(
|
|
31839
|
+
"Re-enroll this runner to obtain a daemon gateway credential"
|
|
31840
|
+
);
|
|
31841
|
+
const credential = options.issueCredential(input.harness);
|
|
31842
|
+
if (credential.status !== 200)
|
|
31843
|
+
throw new Error(
|
|
31844
|
+
"The daemon must hold this harness's model credential before containment can start"
|
|
31845
|
+
);
|
|
31846
|
+
const repository = input.github?.repository;
|
|
31847
|
+
const controller = new AbortController();
|
|
31848
|
+
const abort = () => controller.abort();
|
|
31849
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
31850
|
+
if (signal?.aborted) abort();
|
|
31851
|
+
let sessionUuid2;
|
|
31852
|
+
let launchedSessionId;
|
|
31853
|
+
const session = (id) => {
|
|
31854
|
+
const found = options.registry.get(id);
|
|
31855
|
+
if (!found) throw new Error("Contained session was not recorded");
|
|
31856
|
+
return found;
|
|
31857
|
+
};
|
|
31360
31858
|
try {
|
|
31361
|
-
|
|
31362
|
-
|
|
31363
|
-
|
|
31364
|
-
|
|
31365
|
-
|
|
31366
|
-
|
|
31367
|
-
|
|
31368
|
-
|
|
31369
|
-
|
|
31370
|
-
|
|
31371
|
-
|
|
31372
|
-
|
|
31373
|
-
|
|
31374
|
-
|
|
31375
|
-
|
|
31376
|
-
|
|
31377
|
-
|
|
31378
|
-
|
|
31379
|
-
|
|
31380
|
-
|
|
31381
|
-
|
|
31382
|
-
|
|
31383
|
-
|
|
31384
|
-
|
|
31385
|
-
|
|
31386
|
-
|
|
31387
|
-
|
|
31388
|
-
|
|
31389
|
-
|
|
31390
|
-
|
|
31391
|
-
|
|
31392
|
-
|
|
31393
|
-
|
|
31394
|
-
|
|
31395
|
-
|
|
31396
|
-
|
|
31397
|
-
|
|
31398
|
-
|
|
31399
|
-
|
|
31400
|
-
|
|
31401
|
-
|
|
31402
|
-
|
|
31403
|
-
|
|
31404
|
-
|
|
31405
|
-
|
|
31406
|
-
|
|
31407
|
-
|
|
31408
|
-
|
|
31409
|
-
|
|
31410
|
-
|
|
31411
|
-
|
|
31412
|
-
|
|
31413
|
-
|
|
31414
|
-
|
|
31415
|
-
|
|
31416
|
-
|
|
31417
|
-
|
|
31418
|
-
|
|
31419
|
-
|
|
31420
|
-
|
|
31421
|
-
|
|
31422
|
-
|
|
31423
|
-
|
|
31424
|
-
|
|
31425
|
-
|
|
31426
|
-
|
|
31427
|
-
|
|
31428
|
-
|
|
31429
|
-
record: (call) => options.record([
|
|
31430
|
-
started.recorder.sealCollectorEvent("tool_call", {
|
|
31431
|
-
tool_name: call.toolName,
|
|
31432
|
-
tool_source: "mcp",
|
|
31433
|
-
tool_status: call.status,
|
|
31434
|
-
tool_duration_ms: call.durationMs
|
|
31435
|
-
})
|
|
31436
|
-
])
|
|
31437
|
-
});
|
|
31438
|
-
const bridge = await startContainedBridge({
|
|
31439
|
-
socketPath: join19(directory, "bridge.sock"),
|
|
31859
|
+
return await launchContainedAgent({
|
|
31860
|
+
image: input.image,
|
|
31861
|
+
request: input,
|
|
31862
|
+
output,
|
|
31863
|
+
signal: controller.signal,
|
|
31864
|
+
prepare: async ({ sessionId, directory, workspace }) => {
|
|
31865
|
+
launched.add(sessionId);
|
|
31866
|
+
launchedSessionId = sessionId;
|
|
31867
|
+
if (repository !== void 0)
|
|
31868
|
+
repositories.set(sessionId, repository);
|
|
31869
|
+
await options.hook({
|
|
31870
|
+
harness: input.harness,
|
|
31871
|
+
payload: {
|
|
31872
|
+
hook_event_name: "SessionStart",
|
|
31873
|
+
session_id: sessionId,
|
|
31874
|
+
cwd: workspace,
|
|
31875
|
+
source: "startup"
|
|
31876
|
+
}
|
|
31877
|
+
});
|
|
31878
|
+
const started = session(sessionId);
|
|
31879
|
+
sessionUuid2 = started.recorder.sessionUuid;
|
|
31880
|
+
active2.set(sessionUuid2, controller);
|
|
31881
|
+
const gateway = createMcpGateway({
|
|
31882
|
+
attribution: () => {
|
|
31883
|
+
const current = options.host();
|
|
31884
|
+
if (current.host_status !== "active" || !current.gateway_api_key)
|
|
31885
|
+
return void 0;
|
|
31886
|
+
return {
|
|
31887
|
+
organizationId: current.organization_id,
|
|
31888
|
+
workspaceId: current.workspace_id,
|
|
31889
|
+
orgSlug: current.org_slug,
|
|
31890
|
+
workspaceSlug: current.workspace_slug,
|
|
31891
|
+
apiKey: current.gateway_api_key,
|
|
31892
|
+
hostEnrollmentId: current.host_enrollment_id,
|
|
31893
|
+
chainSessionUuid: started.recorder.sessionUuid,
|
|
31894
|
+
chainGenesisHash: options.genesis(
|
|
31895
|
+
started.recorder.sessionUuid
|
|
31896
|
+
)
|
|
31897
|
+
};
|
|
31898
|
+
},
|
|
31899
|
+
endpoint: mcpEndpointFor(options.host()),
|
|
31900
|
+
fetch: options.fetch,
|
|
31901
|
+
bundle: () => options.host().bundle,
|
|
31902
|
+
log: options.log,
|
|
31903
|
+
record: (call) => options.record([
|
|
31904
|
+
started.recorder.sealCollectorEvent("tool_call", {
|
|
31905
|
+
tool_name: call.toolName,
|
|
31906
|
+
tool_source: "mcp",
|
|
31907
|
+
tool_status: call.status,
|
|
31908
|
+
tool_duration_ms: call.durationMs
|
|
31909
|
+
})
|
|
31910
|
+
])
|
|
31911
|
+
});
|
|
31912
|
+
const bridge = await startContainedBridge({
|
|
31913
|
+
socketPath: join20(directory, "bridge.sock"),
|
|
31914
|
+
sessionId,
|
|
31915
|
+
workspace,
|
|
31916
|
+
harness: input.harness,
|
|
31917
|
+
modelPort: options.modelPort(),
|
|
31918
|
+
issueCredential: () => {
|
|
31919
|
+
const answer = options.issueCredential(input.harness);
|
|
31920
|
+
if (answer.status !== 200)
|
|
31921
|
+
throw new Error("Credential custody unavailable");
|
|
31922
|
+
return answer.body.token;
|
|
31923
|
+
},
|
|
31924
|
+
model: (request3, response) => options.model.handle(request3, response),
|
|
31925
|
+
hook: options.hook,
|
|
31926
|
+
mcp: (body2) => gateway.handle(body2, {
|
|
31440
31927
|
sessionId,
|
|
31441
|
-
|
|
31442
|
-
|
|
31443
|
-
|
|
31444
|
-
|
|
31445
|
-
|
|
31446
|
-
|
|
31447
|
-
|
|
31448
|
-
|
|
31449
|
-
|
|
31450
|
-
|
|
31451
|
-
|
|
31452
|
-
mcp: (body2) => gateway.handle(body2, {
|
|
31453
|
-
sessionId,
|
|
31454
|
-
enrollmentId: options.host().host_enrollment_id
|
|
31455
|
-
}),
|
|
31456
|
-
...input.github ? { github: input.github } : {},
|
|
31457
|
-
forwarded: (method, path2) => options.record([
|
|
31458
|
-
started.recorder.sealCollectorEvent("policy_decision", {
|
|
31459
|
-
policy_decision: "allow",
|
|
31460
|
-
policy_source: "bundle",
|
|
31461
|
-
policy_reason_code: "contained_github_route",
|
|
31462
|
-
tool_name: `${method} ${path2.split("?")[0] ?? ""}`.slice(
|
|
31463
|
-
0,
|
|
31464
|
-
256
|
|
31465
|
-
)
|
|
31466
|
-
})
|
|
31467
|
-
]),
|
|
31468
|
-
refused: (path2) => options.record([
|
|
31469
|
-
started.recorder.sealCollectorEvent("policy_decision", {
|
|
31470
|
-
policy_decision: "deny",
|
|
31471
|
-
policy_source: "bundle",
|
|
31472
|
-
policy_reason_code: "contained_gateway_route",
|
|
31473
|
-
tool_name: path2.split("?")[0]?.slice(0, 256) ?? "unknown"
|
|
31474
|
-
})
|
|
31475
|
-
])
|
|
31476
|
-
});
|
|
31477
|
-
return {
|
|
31478
|
-
files: containedConfiguration(
|
|
31479
|
-
input.harness,
|
|
31480
|
-
input.github?.repository
|
|
31481
|
-
),
|
|
31482
|
-
close: bridge.close
|
|
31483
|
-
};
|
|
31484
|
-
},
|
|
31485
|
-
measured: async (sessionId, measurement) => {
|
|
31486
|
-
const started = session(sessionId);
|
|
31487
|
-
const genesis = options.genesis(started.recorder.sessionUuid);
|
|
31488
|
-
if (!genesis)
|
|
31489
|
-
throw new Error("Contained session has no recorded genesis");
|
|
31490
|
-
const current = options.host();
|
|
31491
|
-
const response = await options.fetch(
|
|
31492
|
-
containedLaunchEndpoint(current),
|
|
31493
|
-
{
|
|
31494
|
-
method: "POST",
|
|
31495
|
-
headers: {
|
|
31496
|
-
authorization: `Bearer ${current.gateway_api_key}`,
|
|
31497
|
-
"content-type": "application/json"
|
|
31498
|
-
},
|
|
31499
|
-
body: JSON.stringify({
|
|
31500
|
-
host_enrollment_id: current.host_enrollment_id,
|
|
31501
|
-
session_uuid: started.recorder.sessionUuid,
|
|
31502
|
-
genesis_hash: genesis,
|
|
31503
|
-
measurement
|
|
31928
|
+
enrollmentId: options.host().host_enrollment_id
|
|
31929
|
+
}),
|
|
31930
|
+
// The lease is keyed by this launcher's own session, never by
|
|
31931
|
+
// a working directory or a port, neither of which the
|
|
31932
|
+
// container shares with the host (ADR-254).
|
|
31933
|
+
...repository !== void 0 ? {
|
|
31934
|
+
github: {
|
|
31935
|
+
repository,
|
|
31936
|
+
lease: () => options.github.issueForSession({
|
|
31937
|
+
session: started.recorder.sessionUuid,
|
|
31938
|
+
repository
|
|
31504
31939
|
}),
|
|
31505
|
-
|
|
31940
|
+
handle: options.github.handle,
|
|
31941
|
+
release: options.github.release
|
|
31506
31942
|
}
|
|
31943
|
+
} : {},
|
|
31944
|
+
githubRefused: (path2) => options.record([
|
|
31945
|
+
started.recorder.sealCollectorEvent("policy_decision", {
|
|
31946
|
+
policy_decision: "deny",
|
|
31947
|
+
policy_source: "kernel",
|
|
31948
|
+
policy_reason_code: "contained_github_custody",
|
|
31949
|
+
tool_name: path2.split("?")[0]?.slice(0, 256) ?? "unknown"
|
|
31950
|
+
})
|
|
31951
|
+
]),
|
|
31952
|
+
refused: (path2) => options.record([
|
|
31953
|
+
started.recorder.sealCollectorEvent("policy_decision", {
|
|
31954
|
+
policy_decision: "deny",
|
|
31955
|
+
policy_source: "bundle",
|
|
31956
|
+
policy_reason_code: "contained_gateway_route",
|
|
31957
|
+
tool_name: path2.split("?")[0]?.slice(0, 256) ?? "unknown"
|
|
31958
|
+
})
|
|
31959
|
+
])
|
|
31960
|
+
});
|
|
31961
|
+
return {
|
|
31962
|
+
files: containedConfiguration(input.harness, repository),
|
|
31963
|
+
close: bridge.close
|
|
31964
|
+
};
|
|
31965
|
+
},
|
|
31966
|
+
measured: async (sessionId, measurement) => {
|
|
31967
|
+
const started = session(sessionId);
|
|
31968
|
+
const genesis = options.genesis(started.recorder.sessionUuid);
|
|
31969
|
+
if (!genesis)
|
|
31970
|
+
throw new Error("Contained session has no recorded genesis");
|
|
31971
|
+
const current = options.host();
|
|
31972
|
+
const response = await options.fetch(
|
|
31973
|
+
containedLaunchEndpoint(current),
|
|
31974
|
+
{
|
|
31975
|
+
method: "POST",
|
|
31976
|
+
headers: {
|
|
31977
|
+
authorization: `Bearer ${current.gateway_api_key}`,
|
|
31978
|
+
"content-type": "application/json"
|
|
31979
|
+
},
|
|
31980
|
+
body: JSON.stringify({
|
|
31981
|
+
host_enrollment_id: current.host_enrollment_id,
|
|
31982
|
+
session_uuid: started.recorder.sessionUuid,
|
|
31983
|
+
genesis_hash: genesis,
|
|
31984
|
+
measurement
|
|
31985
|
+
}),
|
|
31986
|
+
signal: AbortSignal.timeout(3e4)
|
|
31987
|
+
}
|
|
31988
|
+
);
|
|
31989
|
+
if (!response.ok)
|
|
31990
|
+
throw new Error(
|
|
31991
|
+
`Contained launch registration failed (${response.status}); the agent was not started`
|
|
31507
31992
|
);
|
|
31508
|
-
|
|
31509
|
-
|
|
31510
|
-
|
|
31511
|
-
|
|
31512
|
-
|
|
31513
|
-
|
|
31514
|
-
"
|
|
31515
|
-
|
|
31516
|
-
|
|
31517
|
-
|
|
31518
|
-
|
|
31519
|
-
|
|
31520
|
-
|
|
31521
|
-
attrs: {
|
|
31522
|
-
"oxagen.containment.profile": measurement.profile,
|
|
31523
|
-
"oxagen.containment.image": measurement.imageDigest,
|
|
31524
|
-
"oxagen.containment.configuration": measurement.configurationDigest
|
|
31525
|
-
}
|
|
31993
|
+
options.record([
|
|
31994
|
+
started.recorder.sealCollectorEvent(
|
|
31995
|
+
"policy_decision",
|
|
31996
|
+
{
|
|
31997
|
+
policy_decision: "allow",
|
|
31998
|
+
policy_source: "kernel",
|
|
31999
|
+
policy_reason_code: "contained_launch_registered"
|
|
32000
|
+
},
|
|
32001
|
+
{
|
|
32002
|
+
attrs: {
|
|
32003
|
+
"oxagen.containment.profile": measurement.profile,
|
|
32004
|
+
"oxagen.containment.image": measurement.imageDigest,
|
|
32005
|
+
"oxagen.containment.configuration": measurement.configurationDigest
|
|
31526
32006
|
}
|
|
31527
|
-
)
|
|
31528
|
-
]);
|
|
31529
|
-
},
|
|
31530
|
-
sealed: async (sessionId, exitCode) => {
|
|
31531
|
-
await options.hook({
|
|
31532
|
-
harness: input.harness,
|
|
31533
|
-
payload: {
|
|
31534
|
-
hook_event_name: "SessionEnd",
|
|
31535
|
-
session_id: sessionId,
|
|
31536
|
-
cwd: input.workspace,
|
|
31537
|
-
reason: "other",
|
|
31538
|
-
exit_code: exitCode
|
|
31539
32007
|
}
|
|
31540
|
-
|
|
31541
|
-
|
|
31542
|
-
}
|
|
31543
|
-
|
|
31544
|
-
|
|
31545
|
-
|
|
31546
|
-
|
|
31547
|
-
|
|
32008
|
+
)
|
|
32009
|
+
]);
|
|
32010
|
+
},
|
|
32011
|
+
sealed: async (sessionId, exitCode) => {
|
|
32012
|
+
await options.hook({
|
|
32013
|
+
harness: input.harness,
|
|
32014
|
+
payload: {
|
|
32015
|
+
hook_event_name: "SessionEnd",
|
|
32016
|
+
session_id: sessionId,
|
|
32017
|
+
cwd: input.workspace,
|
|
32018
|
+
reason: "other",
|
|
32019
|
+
exit_code: exitCode
|
|
32020
|
+
}
|
|
32021
|
+
});
|
|
32022
|
+
}
|
|
32023
|
+
});
|
|
31548
32024
|
} finally {
|
|
31549
|
-
|
|
31550
|
-
|
|
31551
|
-
|
|
31552
|
-
|
|
31553
|
-
|
|
31554
|
-
|
|
31555
|
-
);
|
|
32025
|
+
signal?.removeEventListener("abort", abort);
|
|
32026
|
+
if (sessionUuid2) active2.delete(sessionUuid2);
|
|
32027
|
+
if (launchedSessionId) {
|
|
32028
|
+
launched.delete(launchedSessionId);
|
|
32029
|
+
repositories.delete(launchedSessionId);
|
|
32030
|
+
}
|
|
31556
32031
|
}
|
|
31557
32032
|
}
|
|
31558
32033
|
};
|
|
@@ -31573,7 +32048,10 @@ var init_runner = __esm({
|
|
|
31573
32048
|
harness: external_exports.enum(["claude-code", "codex"]),
|
|
31574
32049
|
args: external_exports.array(external_exports.string().max(65536)).max(128),
|
|
31575
32050
|
image: external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9/_.:@-]{0,255}$/),
|
|
31576
|
-
/**
|
|
32051
|
+
/**
|
|
32052
|
+
* Optional: the one repository the run may reach, through the daemon's
|
|
32053
|
+
* Git custody (ADR-254). The request carries no token.
|
|
32054
|
+
*/
|
|
31577
32055
|
github: containedGitHubSchema.optional()
|
|
31578
32056
|
}).strict();
|
|
31579
32057
|
}
|
|
@@ -31581,7 +32059,7 @@ var init_runner = __esm({
|
|
|
31581
32059
|
|
|
31582
32060
|
// ../../packages/tacho/src/collector/detector.ts
|
|
31583
32061
|
import { promises as fs } from "node:fs";
|
|
31584
|
-
import { basename as basename4, join as
|
|
32062
|
+
import { basename as basename4, join as join21 } from "node:path";
|
|
31585
32063
|
async function eachLimited(items, limit, task) {
|
|
31586
32064
|
let next = 0;
|
|
31587
32065
|
const workers = Array.from(
|
|
@@ -31607,7 +32085,7 @@ async function scanProject(dir) {
|
|
|
31607
32085
|
await eachLimited(names, SCAN_CONCURRENCY, async (name) => {
|
|
31608
32086
|
const match = SESSION_FILE.exec(name);
|
|
31609
32087
|
if (match === null) return;
|
|
31610
|
-
const path2 =
|
|
32088
|
+
const path2 = join21(dir, name);
|
|
31611
32089
|
try {
|
|
31612
32090
|
const st = await fs.stat(path2);
|
|
31613
32091
|
out.push({ sessionId: match[1], path: path2, mtimeMs: st.mtimeMs });
|
|
@@ -31648,7 +32126,7 @@ var init_detector = __esm({
|
|
|
31648
32126
|
continue;
|
|
31649
32127
|
}
|
|
31650
32128
|
await eachLimited(names, SCAN_CONCURRENCY, async (name) => {
|
|
31651
|
-
const dir =
|
|
32129
|
+
const dir = join21(root, name);
|
|
31652
32130
|
try {
|
|
31653
32131
|
const st = await fs.stat(dir);
|
|
31654
32132
|
if (st.isDirectory()) dirs.push({ dir, mtimeMs: st.mtimeMs });
|
|
@@ -31874,7 +32352,7 @@ var init_detector = __esm({
|
|
|
31874
32352
|
transcript_path: transcript.path,
|
|
31875
32353
|
transcript_mtime: new Date(transcript.mtimeMs).toISOString(),
|
|
31876
32354
|
claude_pids: processes.map((p) => p.pid),
|
|
31877
|
-
project: basename4(
|
|
32355
|
+
project: basename4(join21(transcript.path, ".."))
|
|
31878
32356
|
}
|
|
31879
32357
|
})
|
|
31880
32358
|
);
|
|
@@ -32247,7 +32725,7 @@ import {
|
|
|
32247
32725
|
rm,
|
|
32248
32726
|
unlink
|
|
32249
32727
|
} from "node:fs/promises";
|
|
32250
|
-
import { dirname as dirname13, join as
|
|
32728
|
+
import { dirname as dirname13, join as join22 } from "node:path";
|
|
32251
32729
|
async function statOf(absolutePath) {
|
|
32252
32730
|
try {
|
|
32253
32731
|
const info = await lstat(absolutePath);
|
|
@@ -32287,7 +32765,7 @@ async function contentHash(absolutePath, kind, keep) {
|
|
|
32287
32765
|
if (keep !== void 0) {
|
|
32288
32766
|
try {
|
|
32289
32767
|
await mkdir(keep.dir, { recursive: true, mode: 448 });
|
|
32290
|
-
const temp2 =
|
|
32768
|
+
const temp2 = join22(keep.dir, `.partial-${randomUUID3()}`);
|
|
32291
32769
|
copy = {
|
|
32292
32770
|
temp: temp2,
|
|
32293
32771
|
handle: await open3(temp2, "wx", keep.executable ? 448 : 384)
|
|
@@ -32331,7 +32809,7 @@ async function settleCopy(temp, name) {
|
|
|
32331
32809
|
if (temp === void 0) return;
|
|
32332
32810
|
if (name !== void 0)
|
|
32333
32811
|
try {
|
|
32334
|
-
await rename(temp,
|
|
32812
|
+
await rename(temp, join22(dirname13(temp), name));
|
|
32335
32813
|
return;
|
|
32336
32814
|
} catch {
|
|
32337
32815
|
}
|
|
@@ -32347,7 +32825,7 @@ async function copiedBytes(dir) {
|
|
|
32347
32825
|
let total2 = 0;
|
|
32348
32826
|
for (const name of names) {
|
|
32349
32827
|
try {
|
|
32350
|
-
total2 += (await lstat(
|
|
32828
|
+
total2 += (await lstat(join22(dir, name))).size;
|
|
32351
32829
|
} catch {
|
|
32352
32830
|
}
|
|
32353
32831
|
}
|
|
@@ -32363,7 +32841,7 @@ async function removeCopiesOutside(root, live) {
|
|
|
32363
32841
|
const keep = new Set(live());
|
|
32364
32842
|
await Promise.all(
|
|
32365
32843
|
names.filter((name) => !keep.has(name)).map(
|
|
32366
|
-
(name) => rm(
|
|
32844
|
+
(name) => rm(join22(root, name), { recursive: true, force: true }).catch(
|
|
32367
32845
|
() => void 0
|
|
32368
32846
|
)
|
|
32369
32847
|
)
|
|
@@ -32471,7 +32949,7 @@ async function contributionOf(exec4, cwd, root, repoRelative, entry2, copies) {
|
|
|
32471
32949
|
let copy = null;
|
|
32472
32950
|
if (entry2 !== null) {
|
|
32473
32951
|
if (copies === void 0 || !COPY_NAME.test(entry2[0])) return void 0;
|
|
32474
|
-
copy =
|
|
32952
|
+
copy = join22(copies, entry2[0]);
|
|
32475
32953
|
const kept = await statOf(copy);
|
|
32476
32954
|
if (kept === void 0 || kept === "absent" || kept.kind !== "file")
|
|
32477
32955
|
return void 0;
|
|
@@ -32799,7 +33277,7 @@ var init_session_changes = __esm({
|
|
|
32799
33277
|
|
|
32800
33278
|
// ../../packages/tacho/src/collector/worktree-snapshot.ts
|
|
32801
33279
|
import { lstat as lstat2 } from "node:fs/promises";
|
|
32802
|
-
import { join as
|
|
33280
|
+
import { join as join23 } from "node:path";
|
|
32803
33281
|
function headerPath(prefix, path2) {
|
|
32804
33282
|
const name = `${prefix}${path2}`;
|
|
32805
33283
|
let quoted2 = false;
|
|
@@ -32874,7 +33352,7 @@ async function worktreeFingerprint(status2, root) {
|
|
|
32874
33352
|
const path2 = statusPath(record);
|
|
32875
33353
|
if (path2 === null) return "";
|
|
32876
33354
|
try {
|
|
32877
|
-
const info = await lstat2(
|
|
33355
|
+
const info = await lstat2(join23(root, path2));
|
|
32878
33356
|
return `${info.size}:${info.mtimeMs}:${info.ctimeMs}`;
|
|
32879
33357
|
} catch {
|
|
32880
33358
|
return "absent";
|
|
@@ -32980,7 +33458,7 @@ async function readWorktreeSnapshot(exec4, cwd, baseline, measured) {
|
|
|
32980
33458
|
}
|
|
32981
33459
|
let present;
|
|
32982
33460
|
try {
|
|
32983
|
-
present = (await lstat2(
|
|
33461
|
+
present = (await lstat2(join23(root, path2))).isFile();
|
|
32984
33462
|
} catch {
|
|
32985
33463
|
present = false;
|
|
32986
33464
|
}
|
|
@@ -33081,10 +33559,10 @@ var init_worktree_snapshot = __esm({
|
|
|
33081
33559
|
});
|
|
33082
33560
|
|
|
33083
33561
|
// ../../packages/tacho/src/collector/git-lane.ts
|
|
33084
|
-
import { join as
|
|
33562
|
+
import { join as join24 } from "node:path";
|
|
33085
33563
|
function copiesDirOf(root, session) {
|
|
33086
33564
|
const uuid = session.recorder.sessionUuid;
|
|
33087
|
-
return /^[0-9a-f-]{36}$/i.test(uuid) ?
|
|
33565
|
+
return /^[0-9a-f-]{36}$/i.test(uuid) ? join24(root, uuid) : void 0;
|
|
33088
33566
|
}
|
|
33089
33567
|
function holdsBaseline(session) {
|
|
33090
33568
|
return session.baselineCommit !== void 0 || Object.keys(session.baselines ?? {}).length > 0;
|
|
@@ -34227,7 +34705,11 @@ async function gitPushBasis(input, record, deps) {
|
|
|
34227
34705
|
if (deps.pushCredentialBasis === void 0)
|
|
34228
34706
|
return TACHO_CREDENTIAL_HARNESS_HELD;
|
|
34229
34707
|
try {
|
|
34230
|
-
return await deps.pushCredentialBasis(
|
|
34708
|
+
return await deps.pushCredentialBasis(
|
|
34709
|
+
command2,
|
|
34710
|
+
record.cwd ?? input.cwd,
|
|
34711
|
+
record.harnessSessionId
|
|
34712
|
+
);
|
|
34231
34713
|
} catch {
|
|
34232
34714
|
return TACHO_CREDENTIAL_HARNESS_HELD;
|
|
34233
34715
|
}
|
|
@@ -35451,15 +35933,41 @@ function createGithubProxy(deps) {
|
|
|
35451
35933
|
const fetchUpstream = deps.fetch ?? globalThis.fetch;
|
|
35452
35934
|
function live(lease) {
|
|
35453
35935
|
const host = deps.host();
|
|
35454
|
-
if (
|
|
35936
|
+
if (
|
|
35937
|
+
// `tacho github configure` turns this on for a configured checkout.
|
|
35938
|
+
// A contained run opts in by naming its repository at launch instead.
|
|
35939
|
+
lease.launcher !== true && host.github_broker_enabled !== true || host.host_status !== "active" || !Number.isFinite(Date.parse(host.expires_at)) || Date.parse(host.expires_at) <= deps.now() || lease.expires <= deps.now()
|
|
35940
|
+
)
|
|
35455
35941
|
return void 0;
|
|
35456
35942
|
const session = deps.registry.byUuid(lease.session);
|
|
35457
|
-
return session && !session.sealed && !session.pendingTerminal && session.control.paused == null && session.control.cancelled == null && receiptMatches(
|
|
35943
|
+
return session && !session.sealed && !session.pendingTerminal && session.control.paused == null && session.control.cancelled == null && (lease.launcher === true || receiptMatches(
|
|
35458
35944
|
host,
|
|
35459
35945
|
lease.repository,
|
|
35460
35946
|
session.cwd,
|
|
35461
35947
|
deps.registry.agentOf(session).harness
|
|
35462
|
-
) ? session : void 0;
|
|
35948
|
+
)) ? session : void 0;
|
|
35949
|
+
}
|
|
35950
|
+
function validRepository(value) {
|
|
35951
|
+
return typeof value === "string" && REPO.test(value) && ![".", ".."].includes(value.split("/")[1] ?? "");
|
|
35952
|
+
}
|
|
35953
|
+
function grant(fields, host) {
|
|
35954
|
+
const token = `oxgit_${randomBytes9(32).toString("base64url")}`;
|
|
35955
|
+
const lease = {
|
|
35956
|
+
...fields,
|
|
35957
|
+
id: `rt_${randomBytes9(10).toString("hex")}`,
|
|
35958
|
+
repository: fields.repository.toLowerCase(),
|
|
35959
|
+
expires: Math.min(deps.now() + LIFE_MS, Date.parse(host.expires_at))
|
|
35960
|
+
};
|
|
35961
|
+
if (!live(lease))
|
|
35962
|
+
return {
|
|
35963
|
+
status: 403,
|
|
35964
|
+
body: { error: "The session or enrollment is not active" }
|
|
35965
|
+
};
|
|
35966
|
+
leases.set(hash(token), lease);
|
|
35967
|
+
return {
|
|
35968
|
+
status: 200,
|
|
35969
|
+
body: { token, expires_at: new Date(lease.expires).toISOString() }
|
|
35970
|
+
};
|
|
35463
35971
|
}
|
|
35464
35972
|
function receiptMatches(host, repository, cwd, harness) {
|
|
35465
35973
|
return cwd !== void 0 && (host.github_repositories ?? []).some(
|
|
@@ -35472,14 +35980,14 @@ function createGithubProxy(deps) {
|
|
|
35472
35980
|
status: 400,
|
|
35473
35981
|
body: { error: "A GitHub lease request must be an object" }
|
|
35474
35982
|
};
|
|
35475
|
-
for (const [key,
|
|
35983
|
+
for (const [key, lease] of leases) if (!live(lease)) leases.delete(key);
|
|
35476
35984
|
const host = deps.host();
|
|
35477
35985
|
if (host.github_broker_enabled !== true || host.host_status !== "active")
|
|
35478
35986
|
return {
|
|
35479
35987
|
status: 403,
|
|
35480
35988
|
body: { error: "GitHub custody is not enabled on this host" }
|
|
35481
35989
|
};
|
|
35482
|
-
if (
|
|
35990
|
+
if (!validRepository(input.repository) || typeof input.cwd !== "string" || typeof input.harness !== "string" || !isWrappedHarness(input.harness))
|
|
35483
35991
|
return {
|
|
35484
35992
|
status: 400,
|
|
35485
35993
|
body: {
|
|
@@ -35503,24 +36011,39 @@ function createGithubProxy(deps) {
|
|
|
35503
36011
|
error: "GitHub custody needs exactly one live session in this working directory"
|
|
35504
36012
|
}
|
|
35505
36013
|
};
|
|
35506
|
-
|
|
35507
|
-
|
|
35508
|
-
|
|
35509
|
-
|
|
35510
|
-
|
|
35511
|
-
|
|
35512
|
-
|
|
35513
|
-
|
|
35514
|
-
|
|
36014
|
+
return grant(
|
|
36015
|
+
{
|
|
36016
|
+
repository: input.repository,
|
|
36017
|
+
session: matches[0].recorder.sessionUuid
|
|
36018
|
+
},
|
|
36019
|
+
host
|
|
36020
|
+
);
|
|
36021
|
+
}
|
|
36022
|
+
function issueForSession(input) {
|
|
36023
|
+
for (const [key, lease] of leases) if (!live(lease)) leases.delete(key);
|
|
36024
|
+
const host = deps.host();
|
|
36025
|
+
if (host.host_status !== "active")
|
|
35515
36026
|
return {
|
|
35516
36027
|
status: 403,
|
|
35517
|
-
body: { error: "
|
|
36028
|
+
body: { error: "This host's enrollment is not active" }
|
|
35518
36029
|
};
|
|
35519
|
-
|
|
35520
|
-
|
|
35521
|
-
|
|
35522
|
-
|
|
35523
|
-
|
|
36030
|
+
if (!validRepository(input.repository))
|
|
36031
|
+
return {
|
|
36032
|
+
status: 400,
|
|
36033
|
+
body: { error: "Name the GitHub repository as owner/name" }
|
|
36034
|
+
};
|
|
36035
|
+
if (leases.size >= MAX_LEASES)
|
|
36036
|
+
return {
|
|
36037
|
+
status: 409,
|
|
36038
|
+
body: { error: "Too many GitHub run credentials are open on this host" }
|
|
36039
|
+
};
|
|
36040
|
+
return grant(
|
|
36041
|
+
{ repository: input.repository, session: input.session, launcher: true },
|
|
36042
|
+
host
|
|
36043
|
+
);
|
|
36044
|
+
}
|
|
36045
|
+
function release2(token) {
|
|
36046
|
+
leases.delete(hash(token));
|
|
35524
36047
|
}
|
|
35525
36048
|
async function handle(req, res) {
|
|
35526
36049
|
const token = bearer(req);
|
|
@@ -35758,7 +36281,7 @@ function createGithubProxy(deps) {
|
|
|
35758
36281
|
}
|
|
35759
36282
|
}
|
|
35760
36283
|
}
|
|
35761
|
-
return { issue, handle };
|
|
36284
|
+
return { issue, issueForSession, release: release2, handle };
|
|
35762
36285
|
}
|
|
35763
36286
|
var LIFE_MS, MAX_LEASES, MAX_REQUEST_BYTES, REPO, MAX_REFUSAL_CHARS, REFUSED;
|
|
35764
36287
|
var init_github_proxy = __esm({
|
|
@@ -35866,7 +36389,7 @@ var init_hook_queues = __esm({
|
|
|
35866
36389
|
});
|
|
35867
36390
|
|
|
35868
36391
|
// ../../packages/tacho/src/collector/memory-capture/memory-reader.ts
|
|
35869
|
-
import { isAbsolute as isAbsolute5, join as
|
|
36392
|
+
import { isAbsolute as isAbsolute5, join as join25, sep as sep2 } from "node:path";
|
|
35870
36393
|
function claudeCodeLocation(projectsDir, memoryDir) {
|
|
35871
36394
|
return {
|
|
35872
36395
|
harness: "claude-code",
|
|
@@ -35878,13 +36401,13 @@ function claudeCodeLocation(projectsDir, memoryDir) {
|
|
|
35878
36401
|
}
|
|
35879
36402
|
function claudeCodeMemoryLocations(configDir, projectDirs = []) {
|
|
35880
36403
|
const locations = [
|
|
35881
|
-
claudeCodeLocation(() =>
|
|
35882
|
-
claudeCodeLocation(() =>
|
|
36404
|
+
claudeCodeLocation(() => join25(configDir, "projects"), "memory"),
|
|
36405
|
+
claudeCodeLocation(() => join25(configDir, "agent-memory"), "")
|
|
35883
36406
|
];
|
|
35884
36407
|
for (const dir of projectDirs.slice(0, MEMORY_PROJECT_DIRS_MAX))
|
|
35885
36408
|
locations.push(
|
|
35886
|
-
claudeCodeLocation(() =>
|
|
35887
|
-
claudeCodeLocation(() =>
|
|
36409
|
+
claudeCodeLocation(() => join25(dir, ".claude", "agent-memory"), ""),
|
|
36410
|
+
claudeCodeLocation(() => join25(dir, ".claude", "agent-memory-local"), "")
|
|
35888
36411
|
);
|
|
35889
36412
|
return locations;
|
|
35890
36413
|
}
|
|
@@ -36063,13 +36586,13 @@ function createMemoryReader(deps) {
|
|
|
36063
36586
|
const projects = await list(top);
|
|
36064
36587
|
let complete = projects.complete;
|
|
36065
36588
|
for (const project2 of projects.names) {
|
|
36066
|
-
const dir = location.memoryDir === "" ?
|
|
36589
|
+
const dir = location.memoryDir === "" ? join25(top, project2) : join25(top, project2, location.memoryDir);
|
|
36067
36590
|
const files2 = await list(dir);
|
|
36068
36591
|
if (!files2.complete) complete = false;
|
|
36069
36592
|
for (const name of files2.names) {
|
|
36070
36593
|
if (!name.endsWith(location.extension)) continue;
|
|
36071
36594
|
if (location.skip.includes(name)) continue;
|
|
36072
|
-
const path2 =
|
|
36595
|
+
const path2 = join25(dir, name);
|
|
36073
36596
|
const file = await readAt2(location.harness, path2);
|
|
36074
36597
|
if (file.kind === "absent" || file.kind === "empty") continue;
|
|
36075
36598
|
paths.push(path2);
|
|
@@ -36155,8 +36678,8 @@ var init_memory_reader = __esm({
|
|
|
36155
36678
|
MEMORY_TYPE_PATTERN = /^[a-z][a-z0-9_-]{0,31}$/;
|
|
36156
36679
|
MEMORY_PROJECT_DIRS_MAX = 200;
|
|
36157
36680
|
HARNESS_MEMORY_LOCATIONS = [
|
|
36158
|
-
claudeCodeLocation((home) =>
|
|
36159
|
-
claudeCodeLocation((home) =>
|
|
36681
|
+
claudeCodeLocation((home) => join25(home, ".claude", "projects"), "memory"),
|
|
36682
|
+
claudeCodeLocation((home) => join25(home, ".claude", "agent-memory"), "")
|
|
36160
36683
|
];
|
|
36161
36684
|
FRONTMATTER = /^---[ \t]*\r?\n(?:([\s\S]*?)\r?\n)?---[ \t]*(?:\r?\n|$)/;
|
|
36162
36685
|
FRONTMATTER_LINE = /^([ \t]*)([A-Za-z_][\w-]*)[ \t]*:[ \t]*(.*)$/;
|
|
@@ -36635,7 +37158,7 @@ var init_memory_upload = __esm({
|
|
|
36635
37158
|
});
|
|
36636
37159
|
|
|
36637
37160
|
// ../../packages/tacho/src/collector/memory-capture/memory-uses.ts
|
|
36638
|
-
import { basename as basename5, dirname as dirname15, isAbsolute as isAbsolute6, join as
|
|
37161
|
+
import { basename as basename5, dirname as dirname15, isAbsolute as isAbsolute6, join as join26, resolve as resolve9 } from "node:path";
|
|
36639
37162
|
function memoryFileOf(path2, locations, home) {
|
|
36640
37163
|
if (!isAbsolute6(path2)) return void 0;
|
|
36641
37164
|
const file = resolve9(path2);
|
|
@@ -36653,7 +37176,7 @@ function memoryFileOf(path2, locations, home) {
|
|
|
36653
37176
|
return void 0;
|
|
36654
37177
|
}
|
|
36655
37178
|
function pathOf(word, cwd, home) {
|
|
36656
|
-
const expanded = /^(?:~|\$HOME|\$\{HOME\})\//.test(word) ?
|
|
37179
|
+
const expanded = /^(?:~|\$HOME|\$\{HOME\})\//.test(word) ? join26(home, word.slice(word.indexOf("/") + 1)) : word;
|
|
36657
37180
|
if (isAbsolute6(expanded)) return expanded;
|
|
36658
37181
|
if (cwd !== void 0 && isAbsolute6(cwd)) return resolve9(cwd, expanded);
|
|
36659
37182
|
return void 0;
|
|
@@ -36932,7 +37455,7 @@ ${use.path}`;
|
|
|
36932
37455
|
|
|
36933
37456
|
// ../../packages/tacho/src/collector/memory-capture/stella-store.ts
|
|
36934
37457
|
import { createRequire as createRequire3 } from "node:module";
|
|
36935
|
-
import { dirname as dirname16, isAbsolute as isAbsolute7, join as
|
|
37458
|
+
import { dirname as dirname16, isAbsolute as isAbsolute7, join as join27, resolve as resolve10 } from "node:path";
|
|
36936
37459
|
function sqlite2() {
|
|
36937
37460
|
sqliteModule2 ??= createRequire3(import.meta.url)(
|
|
36938
37461
|
"node:sqlite"
|
|
@@ -37035,7 +37558,7 @@ async function stellaStoreOf(dir, exists) {
|
|
|
37035
37558
|
if (!isAbsolute7(dir)) return void 0;
|
|
37036
37559
|
let at = resolve10(dir);
|
|
37037
37560
|
for (let depth = 0; depth < WORKSPACE_SEARCH_DEPTH; depth += 1) {
|
|
37038
|
-
const candidate =
|
|
37561
|
+
const candidate = join27(at, STELLA_CONTEXT_DB);
|
|
37039
37562
|
if (await exists(candidate)) return candidate;
|
|
37040
37563
|
const up = dirname16(at);
|
|
37041
37564
|
if (up === at) return void 0;
|
|
@@ -37048,7 +37571,7 @@ var init_stella_store = __esm({
|
|
|
37048
37571
|
"../../packages/tacho/src/collector/memory-capture/stella-store.ts"() {
|
|
37049
37572
|
"use strict";
|
|
37050
37573
|
init_memory_reader();
|
|
37051
|
-
STELLA_CONTEXT_DB =
|
|
37574
|
+
STELLA_CONTEXT_DB = join27(".stella", "private", "context.db");
|
|
37052
37575
|
STELLA_MEMORIES_VIEW = "export_memories_v1";
|
|
37053
37576
|
STELLA_USES_VIEW = "export_memory_uses_v1";
|
|
37054
37577
|
STELLA_USES_PER_READ = 5e3;
|
|
@@ -37627,7 +38150,7 @@ var init_cloud_link = __esm({
|
|
|
37627
38150
|
});
|
|
37628
38151
|
|
|
37629
38152
|
// ../../packages/tacho/src/collector/local-servers/digest.ts
|
|
37630
|
-
import { join as
|
|
38153
|
+
import { join as join28 } from "node:path";
|
|
37631
38154
|
function objectOf(value) {
|
|
37632
38155
|
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
|
|
37633
38156
|
}
|
|
@@ -37652,7 +38175,7 @@ function npmNameSegment(name) {
|
|
|
37652
38175
|
return name.startsWith("@") ? `@${encodeURIComponent(name.slice(1))}` : encodeURIComponent(name);
|
|
37653
38176
|
}
|
|
37654
38177
|
async function whichOnPath(command2, pathValue, search) {
|
|
37655
|
-
const candidates = command2.includes("/") || command2.includes("\\") ? [command2] : (pathValue ?? "").split(search.delimiter).filter((dir) => dir.length > 0).map((dir) =>
|
|
38178
|
+
const candidates = command2.includes("/") || command2.includes("\\") ? [command2] : (pathValue ?? "").split(search.delimiter).filter((dir) => dir.length > 0).map((dir) => join28(dir, command2));
|
|
37656
38179
|
for (const candidate of candidates) {
|
|
37657
38180
|
for (const extension of search.extensions) {
|
|
37658
38181
|
if (await search.isExecutable(candidate + extension)) return candidate + extension;
|
|
@@ -38498,7 +39021,7 @@ var init_machine = __esm({
|
|
|
38498
39021
|
});
|
|
38499
39022
|
|
|
38500
39023
|
// ../../packages/tacho/src/collector/push-basis.ts
|
|
38501
|
-
import { resolve as resolve11 } from "node:path";
|
|
39024
|
+
import { isAbsolute as isAbsolute8, relative as relative4, resolve as resolve11 } from "node:path";
|
|
38502
39025
|
function gitPushTarget(command2) {
|
|
38503
39026
|
const tokens = tokenizeSimpleCommand(command2);
|
|
38504
39027
|
if (tokens === void 0 || tokens[0] !== "git") return void 0;
|
|
@@ -38538,6 +39061,8 @@ function gitPushTarget(command2) {
|
|
|
38538
39061
|
return { chdir, ...remote !== void 0 ? { remote } : {} };
|
|
38539
39062
|
}
|
|
38540
39063
|
async function pushCredentialBasis(command2, cwd, deps) {
|
|
39064
|
+
if (deps.containedRepository !== void 0)
|
|
39065
|
+
return containedPushBasis(command2, cwd, deps.containedRepository, deps);
|
|
38541
39066
|
const receipts = deps.receipts();
|
|
38542
39067
|
if (cwd === void 0 || receipts.length === 0)
|
|
38543
39068
|
return TACHO_CREDENTIAL_HARNESS_HELD;
|
|
@@ -38550,6 +39075,25 @@ async function pushCredentialBasis(command2, cwd, deps) {
|
|
|
38550
39075
|
const urls = await pushUrls(dir, remote, deps);
|
|
38551
39076
|
return urls.length > 0 && urls.every((url) => url === receipt.url) ? TACHO_CREDENTIAL_GATEWAY_BROKERED : TACHO_CREDENTIAL_HARNESS_HELD;
|
|
38552
39077
|
}
|
|
39078
|
+
function githubRepositoryOf(url) {
|
|
39079
|
+
const match = /^https:\/\/github\.com\/([A-Za-z0-9-]+\/[A-Za-z0-9._-]+?)(?:\.git)?$/.exec(
|
|
39080
|
+
url
|
|
39081
|
+
);
|
|
39082
|
+
return match?.[1]?.toLowerCase();
|
|
39083
|
+
}
|
|
39084
|
+
async function containedPushBasis(command2, cwd, repository, deps) {
|
|
39085
|
+
const target2 = gitPushTarget(command2);
|
|
39086
|
+
if (cwd === void 0 || target2 === void 0)
|
|
39087
|
+
return TACHO_CREDENTIAL_HARNESS_HELD;
|
|
39088
|
+
const dir = target2.chdir.reduce((from, to) => resolve11(from, to), cwd);
|
|
39089
|
+
const inside2 = relative4(cwd, dir);
|
|
39090
|
+
if (inside2.startsWith("..") || isAbsolute8(inside2))
|
|
39091
|
+
return TACHO_CREDENTIAL_HARNESS_HELD;
|
|
39092
|
+
const remote = target2.remote ?? await defaultPushRemote(dir, deps);
|
|
39093
|
+
const urls = await pushUrls(dir, remote, deps);
|
|
39094
|
+
const wanted = repository.toLowerCase();
|
|
39095
|
+
return urls.length > 0 && urls.every((url) => githubRepositoryOf(url) === wanted) ? TACHO_CREDENTIAL_GATEWAY_BROKERED : TACHO_CREDENTIAL_HARNESS_HELD;
|
|
39096
|
+
}
|
|
38553
39097
|
async function gitOut(dir, args, deps) {
|
|
38554
39098
|
const result2 = await deps.execAsync("git", ["-C", dir, ...args]);
|
|
38555
39099
|
return result2.status === 0 ? result2.stdout.trim() : void 0;
|
|
@@ -38625,7 +39169,7 @@ var init_codec = __esm({
|
|
|
38625
39169
|
import { createHash as createHash12 } from "node:crypto";
|
|
38626
39170
|
import { mkdir as mkdir2, readdir as readdir2, readFile as readFile2, rm as rm2, writeFile } from "node:fs/promises";
|
|
38627
39171
|
import { homedir as homedir5 } from "node:os";
|
|
38628
|
-
import { dirname as dirname17, join as
|
|
39172
|
+
import { dirname as dirname17, join as join29 } from "node:path";
|
|
38629
39173
|
function envDir(env, key) {
|
|
38630
39174
|
const value = env[key];
|
|
38631
39175
|
return value === void 0 || value.trim() === "" ? null : value;
|
|
@@ -38633,13 +39177,13 @@ function envDir(env, key) {
|
|
|
38633
39177
|
function skillsRoot(harness, env = process.env, home = homedir5()) {
|
|
38634
39178
|
switch (harness) {
|
|
38635
39179
|
case "claude-code":
|
|
38636
|
-
return
|
|
39180
|
+
return join29(envDir(env, "CLAUDE_CONFIG_DIR") ?? join29(home, ".claude"), "skills");
|
|
38637
39181
|
case "codex": {
|
|
38638
39182
|
const codexHome = envDir(env, "CODEX_HOME");
|
|
38639
|
-
return codexHome === null ?
|
|
39183
|
+
return codexHome === null ? join29(home, ".agents", "skills") : join29(codexHome, "skills");
|
|
38640
39184
|
}
|
|
38641
39185
|
case "stella":
|
|
38642
|
-
return
|
|
39186
|
+
return join29(envDir(env, "STELLA_HOME") ?? join29(home, ".stella"), "skills");
|
|
38643
39187
|
case "cursor":
|
|
38644
39188
|
case "claude-desktop":
|
|
38645
39189
|
return null;
|
|
@@ -38692,7 +39236,7 @@ async function readMarker(folder) {
|
|
|
38692
39236
|
}
|
|
38693
39237
|
if (!entries2.includes(SESSION_MARKER)) return { state: "foreign" };
|
|
38694
39238
|
try {
|
|
38695
|
-
const parsed = JSON.parse(await readFile2(
|
|
39239
|
+
const parsed = JSON.parse(await readFile2(join29(folder, SESSION_MARKER), "utf8"));
|
|
38696
39240
|
return isMarker(parsed) ? { state: "ours", marker: parsed } : { state: "foreign" };
|
|
38697
39241
|
} catch {
|
|
38698
39242
|
return { state: "foreign" };
|
|
@@ -38707,15 +39251,15 @@ function liveSessions(marker, now) {
|
|
|
38707
39251
|
return live;
|
|
38708
39252
|
}
|
|
38709
39253
|
async function writeMarker(folder, marker) {
|
|
38710
|
-
await writeFile(
|
|
39254
|
+
await writeFile(join29(folder, SESSION_MARKER), `${JSON.stringify(marker, null, 2)}
|
|
38711
39255
|
`);
|
|
38712
39256
|
}
|
|
38713
39257
|
async function writeSkill(folder, skill) {
|
|
38714
39258
|
await rm2(folder, { recursive: true, force: true });
|
|
38715
39259
|
await mkdir2(folder, { recursive: true });
|
|
38716
|
-
await writeFile(
|
|
39260
|
+
await writeFile(join29(folder, "SKILL.md"), skillMarkdown(skill));
|
|
38717
39261
|
for (const file of skill.files) {
|
|
38718
|
-
const target2 =
|
|
39262
|
+
const target2 = join29(folder, file.path);
|
|
38719
39263
|
await mkdir2(dirname17(target2), { recursive: true });
|
|
38720
39264
|
await writeFile(target2, file.content);
|
|
38721
39265
|
}
|
|
@@ -38743,7 +39287,7 @@ async function placeSkills(root, sessionId, skills, now = /* @__PURE__ */ new Da
|
|
|
38743
39287
|
result2.warnings.push(refusal);
|
|
38744
39288
|
continue;
|
|
38745
39289
|
}
|
|
38746
|
-
const folder =
|
|
39290
|
+
const folder = join29(root, skill.name);
|
|
38747
39291
|
if (taken.has(skill.name)) {
|
|
38748
39292
|
result2.skipped.push(skill.name);
|
|
38749
39293
|
result2.warnings.push(
|
|
@@ -38801,7 +39345,7 @@ async function removeSkills(root, sessionId, now = /* @__PURE__ */ new Date()) {
|
|
|
38801
39345
|
throw error;
|
|
38802
39346
|
}
|
|
38803
39347
|
for (const name of names.sort(compareText)) {
|
|
38804
|
-
const folder =
|
|
39348
|
+
const folder = join29(root, name);
|
|
38805
39349
|
const found = await readMarker(folder);
|
|
38806
39350
|
if (found.state !== "ours") continue;
|
|
38807
39351
|
const sessions = liveSessions(found.marker, now);
|
|
@@ -40041,10 +40585,10 @@ var init_model_usage = __esm({
|
|
|
40041
40585
|
// ../../packages/tacho/src/collector/model-proxy.ts
|
|
40042
40586
|
import { createHash as createHash14 } from "node:crypto";
|
|
40043
40587
|
import {
|
|
40044
|
-
request as
|
|
40588
|
+
request as httpRequest,
|
|
40045
40589
|
Agent as HttpAgent
|
|
40046
40590
|
} from "node:http";
|
|
40047
|
-
import { Agent as HttpsAgent, request as
|
|
40591
|
+
import { Agent as HttpsAgent, request as httpsRequest } from "node:https";
|
|
40048
40592
|
import {
|
|
40049
40593
|
gunzipSync,
|
|
40050
40594
|
brotliDecompressSync,
|
|
@@ -40226,7 +40770,7 @@ function createModelProxy(deps) {
|
|
|
40226
40770
|
for (const call of calls) held += call.reserved;
|
|
40227
40771
|
return held;
|
|
40228
40772
|
}
|
|
40229
|
-
function
|
|
40773
|
+
function ceilingFor2(route, model, requestBytes, json2, hasSession) {
|
|
40230
40774
|
const { budget, model_prices: prices } = deps.policy().bundle;
|
|
40231
40775
|
if (budget.mode !== "enforced") return 0;
|
|
40232
40776
|
const limited = hasSession && budget.session_limit_usd !== void 0 || budget.daily_limit_usd !== void 0;
|
|
@@ -40593,7 +41137,7 @@ function createModelProxy(deps) {
|
|
|
40593
41137
|
resolve19(outcome);
|
|
40594
41138
|
};
|
|
40595
41139
|
try {
|
|
40596
|
-
upstream = (secure ?
|
|
41140
|
+
upstream = (secure ? httpsRequest : httpRequest)({
|
|
40597
41141
|
protocol: target2.protocol,
|
|
40598
41142
|
hostname: target2.hostname,
|
|
40599
41143
|
port: target2.port.length > 0 ? Number(target2.port) : secure ? 443 : 80,
|
|
@@ -40929,7 +41473,7 @@ function createModelProxy(deps) {
|
|
|
40929
41473
|
let abortReason;
|
|
40930
41474
|
let upstreamReq;
|
|
40931
41475
|
const entry2 = {
|
|
40932
|
-
reserved: metered ?
|
|
41476
|
+
reserved: metered ? ceilingFor2(
|
|
40933
41477
|
route,
|
|
40934
41478
|
askedModel,
|
|
40935
41479
|
requestTextBytes,
|
|
@@ -41358,7 +41902,7 @@ function createModelProxy(deps) {
|
|
|
41358
41902
|
);
|
|
41359
41903
|
};
|
|
41360
41904
|
const openUpstream = (fresh) => {
|
|
41361
|
-
const created = (secure ?
|
|
41905
|
+
const created = (secure ? httpsRequest : httpRequest)({
|
|
41362
41906
|
protocol: target2.protocol,
|
|
41363
41907
|
hostname: target2.hostname,
|
|
41364
41908
|
port: target2.port.length > 0 ? Number(target2.port) : secure ? 443 : 80,
|
|
@@ -42066,7 +42610,7 @@ var init_server = __esm({
|
|
|
42066
42610
|
|
|
42067
42611
|
// ../../packages/tacho/src/collector/spool.ts
|
|
42068
42612
|
import { existsSync as existsSync19, readFileSync as readFileSync16 } from "node:fs";
|
|
42069
|
-
import { join as
|
|
42613
|
+
import { join as join30 } from "node:path";
|
|
42070
42614
|
function sessionOwnedElsewhere(error) {
|
|
42071
42615
|
return error.status === 403 && error.body.includes(SESSION_OWNED_ELSEWHERE);
|
|
42072
42616
|
}
|
|
@@ -42226,7 +42770,7 @@ var init_spool = __esm({
|
|
|
42226
42770
|
* gone for good.
|
|
42227
42771
|
*/
|
|
42228
42772
|
stash(event, reason3, body2) {
|
|
42229
|
-
const path2 =
|
|
42773
|
+
const path2 = join30(
|
|
42230
42774
|
this.options.quarantineDir,
|
|
42231
42775
|
`${event.session_uuid}-${String(event.seq).padStart(8, "0")}.json`
|
|
42232
42776
|
);
|
|
@@ -42244,7 +42788,7 @@ var init_spool = __esm({
|
|
|
42244
42788
|
}
|
|
42245
42789
|
/** Add a body to a quarantine record that was written without one. */
|
|
42246
42790
|
stashBodyBeside(event, body2) {
|
|
42247
|
-
const path2 =
|
|
42791
|
+
const path2 = join30(
|
|
42248
42792
|
this.options.quarantineDir,
|
|
42249
42793
|
`${event.session_uuid}-${String(event.seq).padStart(8, "0")}.json`
|
|
42250
42794
|
);
|
|
@@ -42373,7 +42917,7 @@ var init_spool = __esm({
|
|
|
42373
42917
|
if (event !== void 0) withdrawn.push(event);
|
|
42374
42918
|
}
|
|
42375
42919
|
if (retention.proven && withdrawn.length > 0) {
|
|
42376
|
-
const dropped = this.options.wal.
|
|
42920
|
+
const dropped = await this.options.wal.dropBodiesAsync(withdrawn);
|
|
42377
42921
|
if (dropped > 0)
|
|
42378
42922
|
this.options.log(
|
|
42379
42923
|
`retention: dropped ${String(dropped)} body(ies) the mandate no longer covers`
|
|
@@ -42653,13 +43197,13 @@ var init_spool = __esm({
|
|
|
42653
43197
|
|
|
42654
43198
|
// ../../packages/tacho/src/collector/transcript-tailer.ts
|
|
42655
43199
|
import { promises as fs2 } from "node:fs";
|
|
42656
|
-
import { basename as basename6, join as
|
|
43200
|
+
import { basename as basename6, join as join31 } from "node:path";
|
|
42657
43201
|
function hasTranscriptNormalizer(session) {
|
|
42658
43202
|
return session.harness === void 0 || TRANSCRIPT_NORMALIZED_HARNESSES.has(session.harness);
|
|
42659
43203
|
}
|
|
42660
43204
|
function subagentDirOf(transcriptPath) {
|
|
42661
43205
|
if (!transcriptPath.endsWith(".jsonl")) return void 0;
|
|
42662
|
-
return
|
|
43206
|
+
return join31(transcriptPath.slice(0, -".jsonl".length), "subagents");
|
|
42663
43207
|
}
|
|
42664
43208
|
function subagentIdOf(path2) {
|
|
42665
43209
|
return /^agent-(.+)\.jsonl$/.exec(basename6(path2))?.[1];
|
|
@@ -43179,11 +43723,11 @@ var init_transcript_tailer = __esm({
|
|
|
43179
43723
|
* those were 3,634 of 5,059 subagent transcripts.
|
|
43180
43724
|
*/
|
|
43181
43725
|
async subagentTranscripts(dir) {
|
|
43182
|
-
const paths = (await this.listDir(dir)).map((name) =>
|
|
43183
|
-
const workflows =
|
|
43726
|
+
const paths = (await this.listDir(dir)).map((name) => join31(dir, name));
|
|
43727
|
+
const workflows = join31(dir, "workflows");
|
|
43184
43728
|
for (const workflow of await this.listDir(workflows)) {
|
|
43185
|
-
const at =
|
|
43186
|
-
for (const name of await this.listDir(at)) paths.push(
|
|
43729
|
+
const at = join31(workflows, workflow);
|
|
43730
|
+
for (const name of await this.listDir(at)) paths.push(join31(at, name));
|
|
43187
43731
|
}
|
|
43188
43732
|
return paths.filter((path2) => subagentIdOf(path2) !== void 0).sort();
|
|
43189
43733
|
}
|
|
@@ -43468,7 +44012,7 @@ import {
|
|
|
43468
44012
|
} from "node:fs";
|
|
43469
44013
|
import { readdir as readdir3, readFile as readFile3, stat as stat2 } from "node:fs/promises";
|
|
43470
44014
|
import { homedir as homedir7, hostname as osHostname2 } from "node:os";
|
|
43471
|
-
import { dirname as dirname18, join as
|
|
44015
|
+
import { dirname as dirname18, join as join32 } from "node:path";
|
|
43472
44016
|
import { execFile as execFile3, spawnSync as spawnSync5 } from "node:child_process";
|
|
43473
44017
|
function defaultExec(command2, args) {
|
|
43474
44018
|
const result2 = spawnSync5(command2, args, {
|
|
@@ -43984,6 +44528,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
43984
44528
|
};
|
|
43985
44529
|
}
|
|
43986
44530
|
let launchedContained = () => false;
|
|
44531
|
+
let containedGitHubRepository = () => void 0;
|
|
43987
44532
|
function policy() {
|
|
43988
44533
|
const current = host;
|
|
43989
44534
|
return {
|
|
@@ -43996,7 +44541,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
43996
44541
|
controlReachable: lastControlAt !== void 0 && now() - lastControlAt < 2 * timers.bundleRefreshMs
|
|
43997
44542
|
};
|
|
43998
44543
|
}
|
|
43999
|
-
const bodyPurgeOwedPath =
|
|
44544
|
+
const bodyPurgeOwedPath = join32(paths.wal, "body-purge-owed");
|
|
44000
44545
|
function markBodyPurgeOwed(retention, dropped) {
|
|
44001
44546
|
try {
|
|
44002
44547
|
ensureDir(paths.wal);
|
|
@@ -44646,7 +45191,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
44646
45191
|
let sessionId;
|
|
44647
45192
|
try {
|
|
44648
45193
|
const file = JSON.parse(
|
|
44649
|
-
readFileSync17(
|
|
45194
|
+
readFileSync17(join32(paths.spool, name), "utf8")
|
|
44650
45195
|
);
|
|
44651
45196
|
const named = file.payload?.session_id;
|
|
44652
45197
|
sessionId = typeof named === "string" ? named : void 0;
|
|
@@ -44696,10 +45241,14 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
44696
45241
|
now,
|
|
44697
45242
|
// Both reads hold this hook's session queue, and both answer no
|
|
44698
45243
|
// answer once `stop` begins (`hookExecAsync`).
|
|
44699
|
-
pushCredentialBasis: (command2, cwd) =>
|
|
44700
|
-
|
|
44701
|
-
|
|
44702
|
-
|
|
45244
|
+
pushCredentialBasis: (command2, cwd, harnessSessionId) => {
|
|
45245
|
+
const containedRepository = containedGitHubRepository(harnessSessionId);
|
|
45246
|
+
return pushCredentialBasis(command2, cwd, {
|
|
45247
|
+
receipts: () => readHostFile(paths.hostFile)?.github_repositories ?? [],
|
|
45248
|
+
...containedRepository !== void 0 ? { containedRepository } : {},
|
|
45249
|
+
execAsync: hookExecAsync
|
|
45250
|
+
});
|
|
45251
|
+
},
|
|
44703
45252
|
repositoryRemote: (cwd) => readRepositoryRemote(hookExecAsync, cwd),
|
|
44704
45253
|
cedar: loadCedarRuntime,
|
|
44705
45254
|
skills,
|
|
@@ -44786,7 +45335,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
44786
45335
|
function setAsideConflictingTerminal(uuid, pending, conflict) {
|
|
44787
45336
|
const name = `${uuid}-terminal-conflict-${String(conflict.seq).padStart(8, "0")}.json`;
|
|
44788
45337
|
writeSensitiveFileAtomic(
|
|
44789
|
-
|
|
45338
|
+
join32(paths.quarantine, name),
|
|
44790
45339
|
JSON.stringify(
|
|
44791
45340
|
{
|
|
44792
45341
|
reason: conflict.message,
|
|
@@ -44865,8 +45414,8 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
44865
45414
|
function moveToFailedSpool(path2, name, reason3) {
|
|
44866
45415
|
log(`spool file ${name} moved to spool/failed/: ${reason3}`);
|
|
44867
45416
|
try {
|
|
44868
|
-
ensureDir(
|
|
44869
|
-
renameSync5(path2,
|
|
45417
|
+
ensureDir(join32(paths.spool, "failed"));
|
|
45418
|
+
renameSync5(path2, join32(paths.spool, "failed", name));
|
|
44870
45419
|
} catch (error) {
|
|
44871
45420
|
log(
|
|
44872
45421
|
`spool file ${name} could not be moved to spool/failed/: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -44915,7 +45464,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
44915
45464
|
continue;
|
|
44916
45465
|
}
|
|
44917
45466
|
reads += 1;
|
|
44918
|
-
const path2 =
|
|
45467
|
+
const path2 = join32(paths.spool, name);
|
|
44919
45468
|
let file;
|
|
44920
45469
|
try {
|
|
44921
45470
|
file = JSON.parse(readFileSync17(path2, "utf8"));
|
|
@@ -45128,7 +45677,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
45128
45677
|
let requested;
|
|
45129
45678
|
try {
|
|
45130
45679
|
const file = JSON.parse(
|
|
45131
|
-
await readFile3(
|
|
45680
|
+
await readFile3(join32(paths.spool, name), "utf8")
|
|
45132
45681
|
);
|
|
45133
45682
|
const payload = file.payload;
|
|
45134
45683
|
requested = payload?.hook_event_name === "PreToolUse" && typeof payload.tool_use_id === "string" ? payload.tool_use_id : void 0;
|
|
@@ -45311,6 +45860,23 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
45311
45860
|
port: options.modelProxyPort ?? (options.port === 0 ? 0 : modelProxyPortFor(host)),
|
|
45312
45861
|
log
|
|
45313
45862
|
});
|
|
45863
|
+
const githubProxy = createGithubProxy({
|
|
45864
|
+
host: () => {
|
|
45865
|
+
const current = readHostFile(paths.hostFile);
|
|
45866
|
+
return {
|
|
45867
|
+
...host,
|
|
45868
|
+
github_broker_enabled: current?.github_broker_enabled === true,
|
|
45869
|
+
github_repositories: current?.github_repositories ?? []
|
|
45870
|
+
};
|
|
45871
|
+
},
|
|
45872
|
+
policy,
|
|
45873
|
+
refreshBundle,
|
|
45874
|
+
registry: registry2,
|
|
45875
|
+
controlFetch: options.fetch ?? globalThis.fetch,
|
|
45876
|
+
now,
|
|
45877
|
+
record,
|
|
45878
|
+
log
|
|
45879
|
+
});
|
|
45314
45880
|
const contained = createContainedRunner({
|
|
45315
45881
|
host: () => host,
|
|
45316
45882
|
registry: registry2,
|
|
@@ -45341,10 +45907,12 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
45341
45907
|
log
|
|
45342
45908
|
}
|
|
45343
45909
|
),
|
|
45910
|
+
github: githubProxy,
|
|
45344
45911
|
fetch: options.fetch ?? ((input, init) => fetch(input, init)),
|
|
45345
45912
|
log
|
|
45346
45913
|
});
|
|
45347
45914
|
launchedContained = contained.launched;
|
|
45915
|
+
containedGitHubRepository = contained.githubRepository;
|
|
45348
45916
|
function interruptModelCalls(commands) {
|
|
45349
45917
|
for (const command2 of commands) {
|
|
45350
45918
|
const cuts = command2.command === "pause" || command2.command === "cancel" || command2.command === "kill" || command2.command === "steer" && command2.delivery_mode === "interrupt";
|
|
@@ -45409,23 +45977,6 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
45409
45977
|
for (const refusal of session.recorder.takeOtelRefusals())
|
|
45410
45978
|
log(`OTel record not sealed for session ${sessionId}: ${refusal}`);
|
|
45411
45979
|
}
|
|
45412
|
-
const githubProxy = createGithubProxy({
|
|
45413
|
-
host: () => {
|
|
45414
|
-
const current = readHostFile(paths.hostFile);
|
|
45415
|
-
return {
|
|
45416
|
-
...host,
|
|
45417
|
-
github_broker_enabled: current?.github_broker_enabled === true,
|
|
45418
|
-
github_repositories: current?.github_repositories ?? []
|
|
45419
|
-
};
|
|
45420
|
-
},
|
|
45421
|
-
policy,
|
|
45422
|
-
refreshBundle,
|
|
45423
|
-
registry: registry2,
|
|
45424
|
-
controlFetch: options.fetch ?? globalThis.fetch,
|
|
45425
|
-
now,
|
|
45426
|
-
record,
|
|
45427
|
-
log
|
|
45428
|
-
});
|
|
45429
45980
|
const api = {
|
|
45430
45981
|
runContained: contained.run,
|
|
45431
45982
|
githubLease: (input) => githubProxy.issue(input),
|
|
@@ -45648,7 +46199,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
45648
46199
|
let removed = 0;
|
|
45649
46200
|
for (const name of readdirSync11(paths.quarantine)) {
|
|
45650
46201
|
if (!name.endsWith(".json")) continue;
|
|
45651
|
-
const file =
|
|
46202
|
+
const file = join32(paths.quarantine, name);
|
|
45652
46203
|
try {
|
|
45653
46204
|
if (at - statSync9(file).mtimeMs < retainMs) continue;
|
|
45654
46205
|
unlinkSync12(file);
|
|
@@ -45665,6 +46216,42 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
45665
46216
|
let lastCompact = 0;
|
|
45666
46217
|
const COMPACT_EVERY_MS = 60 * 6e4;
|
|
45667
46218
|
const COMPACT_RETRY_MS = 6e4;
|
|
46219
|
+
const walCeiling = new WalCeiling(
|
|
46220
|
+
wal,
|
|
46221
|
+
paths.wal,
|
|
46222
|
+
{ ...DEFAULT_WAL_CEILING, ...options.walCeiling },
|
|
46223
|
+
timers.walRetainMs,
|
|
46224
|
+
log
|
|
46225
|
+
);
|
|
46226
|
+
function recordCeilingDrop(drop) {
|
|
46227
|
+
const mark = hostRecorder.markChain();
|
|
46228
|
+
try {
|
|
46229
|
+
record([
|
|
46230
|
+
hostRecorder.sealCollectorEvent("telemetry_gap", {
|
|
46231
|
+
gap_cause: "wal_ceiling",
|
|
46232
|
+
// How long the session went without shipping, capped at what the
|
|
46233
|
+
// column holds.
|
|
46234
|
+
gap_duration_ms: Math.min(
|
|
46235
|
+
Math.max(
|
|
46236
|
+
0,
|
|
46237
|
+
Date.parse(drop.dropped_at) - Date.parse(drop.stalled_since)
|
|
46238
|
+
),
|
|
46239
|
+
4294967295
|
|
46240
|
+
),
|
|
46241
|
+
incident_evidence: { ...drop }
|
|
46242
|
+
})
|
|
46243
|
+
]);
|
|
46244
|
+
} catch (error) {
|
|
46245
|
+
hostRecorder.rollbackChain(mark);
|
|
46246
|
+
log(
|
|
46247
|
+
`WAL ceiling: removed the stored bodies of session ${drop.session_uuid}, but could not record it on the daemon chain: ${error instanceof Error ? error.message : String(error)}`
|
|
46248
|
+
);
|
|
46249
|
+
return;
|
|
46250
|
+
}
|
|
46251
|
+
log(
|
|
46252
|
+
`WAL ceiling: removed ${drop.bytes} bytes of stored bodies from session ${drop.session_uuid}, which has shipped nothing since ${drop.stalled_since}; events ${drop.shipped_through + 1} to ${drop.last_seq} ship without their bodies`
|
|
46253
|
+
);
|
|
46254
|
+
}
|
|
45668
46255
|
retryOwedBodyPurge();
|
|
45669
46256
|
let gitLane;
|
|
45670
46257
|
function startGitReads() {
|
|
@@ -45811,6 +46398,11 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
45811
46398
|
});
|
|
45812
46399
|
await stage("acks", () => sendAcks());
|
|
45813
46400
|
void startGitReads();
|
|
46401
|
+
await stage("wal ceiling", () => {
|
|
46402
|
+
if (!walCeiling.due(now())) return;
|
|
46403
|
+
if (queues.busy(hostRecord.harnessSessionId)) return;
|
|
46404
|
+
walCeiling.check(now(), recordCeilingDrop);
|
|
46405
|
+
});
|
|
45814
46406
|
await stage("compact", () => {
|
|
45815
46407
|
if (now() - lastCompact < COMPACT_EVERY_MS) return;
|
|
45816
46408
|
lastCompact = now();
|
|
@@ -45904,7 +46496,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
45904
46496
|
let memoryTimer;
|
|
45905
46497
|
if (options.listen ?? true) {
|
|
45906
46498
|
const codexMemories = createCodexMemoryStore({
|
|
45907
|
-
path:
|
|
46499
|
+
path: join32(dirname18(paths.codexHooks), CODEX_MEMORY_STORE_FILE),
|
|
45908
46500
|
stat: (path2) => stat2(path2),
|
|
45909
46501
|
log
|
|
45910
46502
|
});
|
|
@@ -46045,6 +46637,7 @@ var init_daemon = __esm({
|
|
|
46045
46637
|
init_process_scan();
|
|
46046
46638
|
init_retention();
|
|
46047
46639
|
init_wal();
|
|
46640
|
+
init_wal_ceiling();
|
|
46048
46641
|
init_work_orders();
|
|
46049
46642
|
init_ids();
|
|
46050
46643
|
init_timestamp();
|
|
@@ -46467,7 +47060,7 @@ var init_schema = __esm({
|
|
|
46467
47060
|
import {
|
|
46468
47061
|
closeSync as closeSync7,
|
|
46469
47062
|
constants as constants3,
|
|
46470
|
-
fstatSync,
|
|
47063
|
+
fstatSync as fstatSync2,
|
|
46471
47064
|
lstatSync as lstatSync6,
|
|
46472
47065
|
mkdirSync as mkdirSync7,
|
|
46473
47066
|
openSync as openSync7,
|
|
@@ -46475,8 +47068,8 @@ import {
|
|
|
46475
47068
|
realpathSync as realpathSync4,
|
|
46476
47069
|
writeFileSync as writeFileSync5
|
|
46477
47070
|
} from "node:fs";
|
|
46478
|
-
import { dirname as dirname19, join as
|
|
46479
|
-
function bundlePath(root,
|
|
47071
|
+
import { dirname as dirname19, join as join33, resolve as resolve12 } from "node:path";
|
|
47072
|
+
function bundlePath(root, relative9, create2 = false) {
|
|
46480
47073
|
const absolute = resolve12(root);
|
|
46481
47074
|
if (create2) mkdirSync7(absolute, { recursive: true, mode: 448 });
|
|
46482
47075
|
if (lstatSync6(absolute).isSymbolicLink() || !lstatSync6(absolute).isDirectory()) {
|
|
@@ -46484,9 +47077,9 @@ function bundlePath(root, relative8, create2 = false) {
|
|
|
46484
47077
|
}
|
|
46485
47078
|
const base2 = realpathSync4(absolute);
|
|
46486
47079
|
let current = base2;
|
|
46487
|
-
const parts =
|
|
47080
|
+
const parts = relative9.split("/");
|
|
46488
47081
|
for (let i2 = 0; i2 < parts.length; i2++) {
|
|
46489
|
-
current =
|
|
47082
|
+
current = join33(current, parts[i2]);
|
|
46490
47083
|
try {
|
|
46491
47084
|
const stat5 = lstatSync6(current);
|
|
46492
47085
|
if (stat5.isSymbolicLink() || i2 < parts.length - 1 && !stat5.isDirectory()) {
|
|
@@ -46503,11 +47096,11 @@ function bundlePath(root, relative8, create2 = false) {
|
|
|
46503
47096
|
}
|
|
46504
47097
|
return current;
|
|
46505
47098
|
}
|
|
46506
|
-
function readBounded(root,
|
|
46507
|
-
const path2 = bundlePath(root,
|
|
47099
|
+
function readBounded(root, relative9, limit = ARP_MAX_BLOB_BYTES) {
|
|
47100
|
+
const path2 = bundlePath(root, relative9);
|
|
46508
47101
|
const fd2 = openSync7(path2, constants3.O_RDONLY | constants3.O_NOFOLLOW);
|
|
46509
47102
|
try {
|
|
46510
|
-
const stat5 =
|
|
47103
|
+
const stat5 = fstatSync2(fd2);
|
|
46511
47104
|
if (!stat5.isFile() || stat5.size > limit)
|
|
46512
47105
|
throw new Error(
|
|
46513
47106
|
"ARP file exceeds its size limit or is not a regular file"
|
|
@@ -46526,8 +47119,8 @@ function readBounded(root, relative8, limit = ARP_MAX_BLOB_BYTES) {
|
|
|
46526
47119
|
closeSync7(fd2);
|
|
46527
47120
|
}
|
|
46528
47121
|
}
|
|
46529
|
-
function writeNew(root,
|
|
46530
|
-
const path2 = bundlePath(root,
|
|
47122
|
+
function writeNew(root, relative9, bytes) {
|
|
47123
|
+
const path2 = bundlePath(root, relative9, true);
|
|
46531
47124
|
const fd2 = openSync7(
|
|
46532
47125
|
path2,
|
|
46533
47126
|
constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | constants3.O_NOFOLLOW,
|
|
@@ -47356,7 +47949,7 @@ import { randomUUID as randomUUID4 } from "node:crypto";
|
|
|
47356
47949
|
import {
|
|
47357
47950
|
closeSync as closeSync8,
|
|
47358
47951
|
constants as constants4,
|
|
47359
|
-
fstatSync as
|
|
47952
|
+
fstatSync as fstatSync3,
|
|
47360
47953
|
lstatSync as lstatSync7,
|
|
47361
47954
|
mkdirSync as mkdirSync8,
|
|
47362
47955
|
openSync as openSync8,
|
|
@@ -47365,14 +47958,14 @@ import {
|
|
|
47365
47958
|
rmSync as rmSync7,
|
|
47366
47959
|
writeFileSync as writeFileSync6
|
|
47367
47960
|
} from "node:fs";
|
|
47368
|
-
import { dirname as dirname20, isAbsolute as
|
|
47961
|
+
import { dirname as dirname20, isAbsolute as isAbsolute9, join as join34, relative as relative5, resolve as resolve13, sep as sep3 } from "node:path";
|
|
47369
47962
|
function fail2(message) {
|
|
47370
47963
|
throw new Error(`ARP: ${message}`);
|
|
47371
47964
|
}
|
|
47372
47965
|
function readRegular(path2, limit) {
|
|
47373
47966
|
const fd2 = openSync8(path2, constants4.O_RDONLY | constants4.O_NOFOLLOW);
|
|
47374
47967
|
try {
|
|
47375
|
-
const before =
|
|
47968
|
+
const before = fstatSync3(fd2);
|
|
47376
47969
|
if (!before.isFile() || before.size > limit)
|
|
47377
47970
|
fail2("Input is not a bounded regular file.");
|
|
47378
47971
|
const bytes = Buffer.alloc(before.size);
|
|
@@ -47384,7 +47977,7 @@ function readRegular(path2, limit) {
|
|
|
47384
47977
|
}
|
|
47385
47978
|
if (readSync5(fd2, Buffer.alloc(1), 0, 1, offset) !== 0)
|
|
47386
47979
|
fail2("Input grew while it was read.");
|
|
47387
|
-
const after =
|
|
47980
|
+
const after = fstatSync3(fd2);
|
|
47388
47981
|
if (bytes.length > limit || before.size !== after.size || before.mtimeMs !== after.mtimeMs || before.ctimeMs !== after.ctimeMs) {
|
|
47389
47982
|
fail2(
|
|
47390
47983
|
"Input changed while it was read. Stop its writer and capture again."
|
|
@@ -47403,12 +47996,12 @@ function rejectSecrets(bytes) {
|
|
|
47403
47996
|
}
|
|
47404
47997
|
}
|
|
47405
47998
|
function within2(root, path2) {
|
|
47406
|
-
const rel =
|
|
47407
|
-
return rel === "" || !
|
|
47999
|
+
const rel = relative5(root, path2);
|
|
48000
|
+
return rel === "" || !isAbsolute9(rel) && rel !== ".." && !rel.startsWith(`..${sep3}`);
|
|
47408
48001
|
}
|
|
47409
48002
|
function newPath(path2) {
|
|
47410
48003
|
const full = resolve13(path2);
|
|
47411
|
-
return
|
|
48004
|
+
return join34(
|
|
47412
48005
|
realpathSync5(dirname20(full)),
|
|
47413
48006
|
full.slice(dirname20(full).length + 1)
|
|
47414
48007
|
);
|
|
@@ -47424,7 +48017,7 @@ function sourcePath(root, path2) {
|
|
|
47424
48017
|
}
|
|
47425
48018
|
let current = root;
|
|
47426
48019
|
for (const part2 of path2.split("/")) {
|
|
47427
|
-
current =
|
|
48020
|
+
current = join34(current, part2);
|
|
47428
48021
|
if (lstatSync7(current).isSymbolicLink())
|
|
47429
48022
|
fail2("Symlinks require a resource adapter.");
|
|
47430
48023
|
}
|
|
@@ -47677,10 +48270,10 @@ function prepareCheckpoint(options) {
|
|
|
47677
48270
|
});
|
|
47678
48271
|
mkdirSync8(destination, { mode: 448 });
|
|
47679
48272
|
try {
|
|
47680
|
-
const restored =
|
|
48273
|
+
const restored = join34(destination, "workspace");
|
|
47681
48274
|
mkdirSync8(restored, { mode: 448 });
|
|
47682
48275
|
for (const { entry: entry2, bytes } of files2) {
|
|
47683
|
-
const path2 =
|
|
48276
|
+
const path2 = join34(restored, entry2.path);
|
|
47684
48277
|
if (entry2.kind === "directory")
|
|
47685
48278
|
mkdirSync8(path2, { recursive: true, mode: 448 });
|
|
47686
48279
|
else {
|
|
@@ -47692,9 +48285,9 @@ function prepareCheckpoint(options) {
|
|
|
47692
48285
|
});
|
|
47693
48286
|
}
|
|
47694
48287
|
}
|
|
47695
|
-
const promptDir =
|
|
48288
|
+
const promptDir = join34(restored, ".arp");
|
|
47696
48289
|
mkdirSync8(promptDir, { mode: 448 });
|
|
47697
|
-
const promptFile =
|
|
48290
|
+
const promptFile = join34(promptDir, "handoff.json");
|
|
47698
48291
|
const prompt = {
|
|
47699
48292
|
checkpoint_digest: checkpointDigest,
|
|
47700
48293
|
task: task.request,
|
|
@@ -47711,7 +48304,7 @@ function prepareCheckpoint(options) {
|
|
|
47711
48304
|
flag: "wx",
|
|
47712
48305
|
mode: 384
|
|
47713
48306
|
});
|
|
47714
|
-
const reportPath =
|
|
48307
|
+
const reportPath = join34(destination, "report.json");
|
|
47715
48308
|
writeFileSync6(
|
|
47716
48309
|
reportPath,
|
|
47717
48310
|
jcs({
|
|
@@ -48128,7 +48721,7 @@ function buildTachoProgram(options = {}) {
|
|
|
48128
48721
|
"The repository root to mount at /workspace (default: the current directory)"
|
|
48129
48722
|
).option(
|
|
48130
48723
|
"--github-repository <owner/name>",
|
|
48131
|
-
"The one repository the run may
|
|
48724
|
+
"The one repository the run may fetch and push, through Oxagen's Git custody. The workspace must have it bound."
|
|
48132
48725
|
).argument("<agent>", "claude or codex").argument("[args...]", "Arguments for the agent, after --").action(
|
|
48133
48726
|
async (agent, args, opts) => {
|
|
48134
48727
|
const controller = new AbortController();
|
|
@@ -48235,7 +48828,7 @@ var init_package = __esm({
|
|
|
48235
48828
|
"package.json"() {
|
|
48236
48829
|
package_default = {
|
|
48237
48830
|
name: "@oxagen/cli",
|
|
48238
|
-
version: "2.1.4-
|
|
48831
|
+
version: "2.1.4-391",
|
|
48239
48832
|
description: "Oxagen governance CLI \u2014 spend, lineage, grounding, credentials, and audit (agentic coding lives in the stella CLI)",
|
|
48240
48833
|
type: "module",
|
|
48241
48834
|
main: "./dist/index.js",
|
|
@@ -48320,10 +48913,10 @@ var init_retired = __esm({
|
|
|
48320
48913
|
|
|
48321
48914
|
// src/lib/atomic-write.ts
|
|
48322
48915
|
import { writeFileSync as writeFileSync7, renameSync as renameSync6, unlinkSync as unlinkSync14, existsSync as existsSync21 } from "node:fs";
|
|
48323
|
-
import { dirname as dirname21, join as
|
|
48916
|
+
import { dirname as dirname21, join as join35 } from "node:path";
|
|
48324
48917
|
function atomicWriteFileSync(path2, data) {
|
|
48325
48918
|
const dir = dirname21(path2);
|
|
48326
|
-
const tmp =
|
|
48919
|
+
const tmp = join35(
|
|
48327
48920
|
dir,
|
|
48328
48921
|
`.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`
|
|
48329
48922
|
);
|
|
@@ -48345,7 +48938,7 @@ var init_atomic_write = __esm({
|
|
|
48345
48938
|
|
|
48346
48939
|
// src/lib/config.ts
|
|
48347
48940
|
import { homedir as homedir8 } from "os";
|
|
48348
|
-
import { join as
|
|
48941
|
+
import { join as join36 } from "path";
|
|
48349
48942
|
import { readFileSync as readFileSync20, mkdirSync as mkdirSync9, existsSync as existsSync22 } from "fs";
|
|
48350
48943
|
function getConfigDir() {
|
|
48351
48944
|
return CONFIG_DIR;
|
|
@@ -48396,8 +48989,8 @@ var CONFIG_DIR, CONFIG_FILE;
|
|
|
48396
48989
|
var init_config = __esm({
|
|
48397
48990
|
"src/lib/config.ts"() {
|
|
48398
48991
|
init_atomic_write();
|
|
48399
|
-
CONFIG_DIR =
|
|
48400
|
-
CONFIG_FILE =
|
|
48992
|
+
CONFIG_DIR = join36(homedir8(), ".config", "oxagen");
|
|
48993
|
+
CONFIG_FILE = join36(CONFIG_DIR, "config.json");
|
|
48401
48994
|
}
|
|
48402
48995
|
});
|
|
48403
48996
|
|
|
@@ -48429,16 +49022,16 @@ import {
|
|
|
48429
49022
|
writeFile as writeFile2
|
|
48430
49023
|
} from "node:fs/promises";
|
|
48431
49024
|
import { homedir as homedir9 } from "node:os";
|
|
48432
|
-
import { join as
|
|
49025
|
+
import { join as join37 } from "node:path";
|
|
48433
49026
|
function isDebugEnabled() {
|
|
48434
49027
|
const v = process.env[DEBUG_ENV];
|
|
48435
49028
|
return v === "1" || v === "true";
|
|
48436
49029
|
}
|
|
48437
49030
|
function logsDir() {
|
|
48438
|
-
return
|
|
49031
|
+
return join37(homedir9(), ".oxagen", "logs");
|
|
48439
49032
|
}
|
|
48440
49033
|
function debugLogFile() {
|
|
48441
|
-
return
|
|
49034
|
+
return join37(logsDir(), "cli.output");
|
|
48442
49035
|
}
|
|
48443
49036
|
function sanitize(value, depth = 0) {
|
|
48444
49037
|
if (value === null || value === void 0) return value;
|
|
@@ -51459,9 +52052,9 @@ var init_git = __esm({
|
|
|
51459
52052
|
|
|
51460
52053
|
// ../../packages/steering-freshness/src/cache.ts
|
|
51461
52054
|
import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
|
|
51462
|
-
import { dirname as dirname22, join as
|
|
52055
|
+
import { dirname as dirname22, join as join38 } from "node:path";
|
|
51463
52056
|
function stampPath(gitCommonDir) {
|
|
51464
|
-
return
|
|
52057
|
+
return join38(gitCommonDir, "oxagen", "steering-freshness.json");
|
|
51465
52058
|
}
|
|
51466
52059
|
async function readFetchStamp(gitCommonDir, io = defaultIo) {
|
|
51467
52060
|
try {
|
|
@@ -51515,24 +52108,24 @@ var init_cache = __esm({
|
|
|
51515
52108
|
// ../../packages/steering-freshness/src/hooks.ts
|
|
51516
52109
|
import { mkdir as mkdir5, readFile as readFile7, writeFile as writeFile5 } from "node:fs/promises";
|
|
51517
52110
|
import { homedir as homedir10 } from "node:os";
|
|
51518
|
-
import { dirname as dirname23, join as
|
|
52111
|
+
import { dirname as dirname23, join as join39 } from "node:path";
|
|
51519
52112
|
function hookCommand(harness) {
|
|
51520
52113
|
return `oxagen steering gate --harness ${harness}`;
|
|
51521
52114
|
}
|
|
51522
52115
|
function hookConfigPath(projectRoot, harness, env = process.env, home = homedir10()) {
|
|
51523
52116
|
switch (harness) {
|
|
51524
52117
|
case "claude-code":
|
|
51525
|
-
return
|
|
52118
|
+
return join39(projectRoot, ".claude", "settings.json");
|
|
51526
52119
|
case "codex":
|
|
51527
|
-
return
|
|
52120
|
+
return join39(env["CODEX_HOME"] ?? join39(home, ".codex"), "hooks.json");
|
|
51528
52121
|
case "cursor":
|
|
51529
|
-
return
|
|
52122
|
+
return join39(home, ".cursor", "hooks.json");
|
|
51530
52123
|
case "stella":
|
|
51531
|
-
return
|
|
52124
|
+
return join39(env["STELLA_HOME"] ?? join39(home, ".stella"), "stella.toml");
|
|
51532
52125
|
}
|
|
51533
52126
|
}
|
|
51534
52127
|
function stellaJsonPath(env, home) {
|
|
51535
|
-
return
|
|
52128
|
+
return join39(env["STELLA_HOME"] ?? join39(home, ".stella"), "settings.json");
|
|
51536
52129
|
}
|
|
51537
52130
|
function isRecord7(v) {
|
|
51538
52131
|
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
@@ -52261,7 +52854,7 @@ var init_policy = __esm({
|
|
|
52261
52854
|
// ../../packages/steering-freshness/src/settings.ts
|
|
52262
52855
|
import { readFile as readFile8 } from "node:fs/promises";
|
|
52263
52856
|
import { homedir as homedir11 } from "node:os";
|
|
52264
|
-
import { join as
|
|
52857
|
+
import { join as join40 } from "node:path";
|
|
52265
52858
|
async function readLayer(scope, path2, read2) {
|
|
52266
52859
|
let text4;
|
|
52267
52860
|
try {
|
|
@@ -52313,14 +52906,14 @@ function parseLayer(scope, path2, text4) {
|
|
|
52313
52906
|
}
|
|
52314
52907
|
async function loadSteeringSettings({
|
|
52315
52908
|
projectRoot,
|
|
52316
|
-
userSettingsPath =
|
|
52909
|
+
userSettingsPath = join40(homedir11(), USER_SETTINGS_RELATIVE),
|
|
52317
52910
|
read: read2 = readFile8,
|
|
52318
52911
|
workspacePolicy = null
|
|
52319
52912
|
}) {
|
|
52320
52913
|
const targets = [
|
|
52321
52914
|
["user", userSettingsPath],
|
|
52322
|
-
["project",
|
|
52323
|
-
["local",
|
|
52915
|
+
["project", join40(projectRoot, PROJECT_DIR_NAME, PROJECT_SETTINGS_FILE)],
|
|
52916
|
+
["local", join40(projectRoot, PROJECT_DIR_NAME, LOCAL_SETTINGS_FILE)]
|
|
52324
52917
|
];
|
|
52325
52918
|
const layers = [];
|
|
52326
52919
|
const warnings = [];
|
|
@@ -52368,7 +52961,7 @@ var init_settings = __esm({
|
|
|
52368
52961
|
"use strict";
|
|
52369
52962
|
init_git();
|
|
52370
52963
|
init_policy();
|
|
52371
|
-
USER_SETTINGS_RELATIVE =
|
|
52964
|
+
USER_SETTINGS_RELATIVE = join40(
|
|
52372
52965
|
".config",
|
|
52373
52966
|
"oxagen",
|
|
52374
52967
|
"settings.json"
|
|
@@ -52381,7 +52974,7 @@ var init_settings = __esm({
|
|
|
52381
52974
|
|
|
52382
52975
|
// ../../packages/steering-freshness/src/check.ts
|
|
52383
52976
|
import { lstat as lstat3 } from "node:fs/promises";
|
|
52384
|
-
import { isAbsolute as
|
|
52977
|
+
import { isAbsolute as isAbsolute10, join as join41, resolve as resolve14 } from "node:path";
|
|
52385
52978
|
function publishedCommits(platform) {
|
|
52386
52979
|
if (platform.headCommits && platform.headCommits.length > 0)
|
|
52387
52980
|
return platform.headCommits;
|
|
@@ -52473,7 +53066,7 @@ async function checkSteeringFreshness(opts) {
|
|
|
52473
53066
|
);
|
|
52474
53067
|
}
|
|
52475
53068
|
const commonDir = allowNetwork ? await gitOrNull(repoCtx, "rev-parse", "--git-common-dir") : null;
|
|
52476
|
-
const stampDir = commonDir ?
|
|
53069
|
+
const stampDir = commonDir ? isAbsolute10(commonDir) ? commonDir : resolve14(root, commonDir) : null;
|
|
52477
53070
|
const stamp = stampDir ? await readFetchStamp(stampDir, cacheIo) : null;
|
|
52478
53071
|
const remoteContactDue = allowNetwork && shouldContactRemote(stamp, policy.fetchIntervalSeconds, now());
|
|
52479
53072
|
const branch = policy.branch ?? await defaultBranch(networkCtx(repoCtx), policy.remote, {
|
|
@@ -52695,7 +53288,7 @@ async function absentFromDisk(root, paths) {
|
|
|
52695
53288
|
const flags = await Promise.all(
|
|
52696
53289
|
paths.map(async (path2) => {
|
|
52697
53290
|
try {
|
|
52698
|
-
await lstat3(
|
|
53291
|
+
await lstat3(join41(root, path2));
|
|
52699
53292
|
return false;
|
|
52700
53293
|
} catch {
|
|
52701
53294
|
return true;
|
|
@@ -53348,9 +53941,9 @@ import {
|
|
|
53348
53941
|
rmSync as rmSync8,
|
|
53349
53942
|
writeFileSync as writeFileSync8
|
|
53350
53943
|
} from "node:fs";
|
|
53351
|
-
import { join as
|
|
53944
|
+
import { join as join42 } from "node:path";
|
|
53352
53945
|
function workspaceLinkPath(cwd) {
|
|
53353
|
-
return
|
|
53946
|
+
return join42(cwd, ".oxagen", "workspace.json");
|
|
53354
53947
|
}
|
|
53355
53948
|
function readWorkspaceLink(cwd) {
|
|
53356
53949
|
const filePath = workspaceLinkPath(cwd);
|
|
@@ -53367,7 +53960,7 @@ function readWorkspaceLink(cwd) {
|
|
|
53367
53960
|
}
|
|
53368
53961
|
}
|
|
53369
53962
|
function writeWorkspaceLink(cwd, link) {
|
|
53370
|
-
const dir =
|
|
53963
|
+
const dir = join42(cwd, ".oxagen");
|
|
53371
53964
|
mkdirSync10(dir, { recursive: true });
|
|
53372
53965
|
writeFileSync8(workspaceLinkPath(cwd), JSON.stringify(link, null, 2), "utf8");
|
|
53373
53966
|
}
|
|
@@ -53393,7 +53986,7 @@ __export(steering_exports, {
|
|
|
53393
53986
|
});
|
|
53394
53987
|
import { execFileSync } from "node:child_process";
|
|
53395
53988
|
import { existsSync as existsSync24, realpathSync as realpathSync6 } from "node:fs";
|
|
53396
|
-
import { dirname as dirname24, join as
|
|
53989
|
+
import { dirname as dirname24, join as join43, normalize, parse as parsePath } from "node:path";
|
|
53397
53990
|
function findProjectRoot(start) {
|
|
53398
53991
|
const { root } = parsePath(start);
|
|
53399
53992
|
const rawGitRoot = gitRootOr(start);
|
|
@@ -53402,7 +53995,7 @@ function findProjectRoot(start) {
|
|
|
53402
53995
|
if (gitRoot !== null) return gitRoot;
|
|
53403
53996
|
let dir = from;
|
|
53404
53997
|
for (; ; ) {
|
|
53405
|
-
if (existsSync24(
|
|
53998
|
+
if (existsSync24(join43(dir, PROJECT_DIR_NAME))) return dir;
|
|
53406
53999
|
if (dir === root) return from;
|
|
53407
54000
|
const parent = dirname24(dir);
|
|
53408
54001
|
if (parent === dir) return from;
|
|
@@ -64334,7 +64927,7 @@ var init_record = __esm({
|
|
|
64334
64927
|
external_exports.object({
|
|
64335
64928
|
source: external_exports.enum(["proposal", "run", "import"]),
|
|
64336
64929
|
uri: external_exports.string(),
|
|
64337
|
-
agent: external_exports.string().optional().describe("The agent that proposed the record with
|
|
64930
|
+
agent: external_exports.string().optional().describe("The agent that proposed the record with propose_steering."),
|
|
64338
64931
|
memories: external_exports.array(provenanceMemorySchema).min(1).optional().describe(
|
|
64339
64932
|
"The memories the curator cited for the record. Required when source is run."
|
|
64340
64933
|
)
|
|
@@ -68748,14 +69341,14 @@ var init_memory_client = __esm({
|
|
|
68748
69341
|
|
|
68749
69342
|
// src/lib/markdown-import.ts
|
|
68750
69343
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
68751
|
-
import { basename as basename7, dirname as dirname25, isAbsolute as
|
|
69344
|
+
import { basename as basename7, dirname as dirname25, isAbsolute as isAbsolute11, relative as relative6, resolve as resolve15, sep as sep4 } from "node:path";
|
|
68752
69345
|
function inside(rel) {
|
|
68753
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
69346
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute11(rel);
|
|
68754
69347
|
}
|
|
68755
69348
|
function importFilename(path2, folder) {
|
|
68756
|
-
let rel =
|
|
69349
|
+
let rel = relative6(process.cwd(), path2);
|
|
68757
69350
|
if (!inside(rel) && folder !== void 0) {
|
|
68758
|
-
rel =
|
|
69351
|
+
rel = relative6(dirname25(resolve15(folder)), resolve15(path2));
|
|
68759
69352
|
}
|
|
68760
69353
|
const name = inside(rel) ? rel.split(sep4).join("/") : basename7(path2);
|
|
68761
69354
|
return name.length > 256 ? basename7(path2).slice(-256) : name;
|
|
@@ -68973,7 +69566,7 @@ __export(steering_import_exports, {
|
|
|
68973
69566
|
handleSteeringImport: () => handleSteeringImport
|
|
68974
69567
|
});
|
|
68975
69568
|
import { readdir as readdir4, realpath as realpath2, stat as stat4 } from "node:fs/promises";
|
|
68976
|
-
import { extname, join as
|
|
69569
|
+
import { extname, join as join44 } from "node:path";
|
|
68977
69570
|
function byName(a, b5) {
|
|
68978
69571
|
return a.name < b5.name ? -1 : 1;
|
|
68979
69572
|
}
|
|
@@ -69001,7 +69594,7 @@ async function findMarkdownFiles(paths) {
|
|
|
69001
69594
|
}
|
|
69002
69595
|
entries2.sort(byName);
|
|
69003
69596
|
for (const entry2 of entries2) {
|
|
69004
|
-
const path2 =
|
|
69597
|
+
const path2 = join44(dir, entry2.name);
|
|
69005
69598
|
if (entry2.isDirectory()) {
|
|
69006
69599
|
if (entry2.name.startsWith(".") || entry2.name === "node_modules") continue;
|
|
69007
69600
|
await walk(path2, folder);
|
|
@@ -69071,6 +69664,268 @@ var init_steering_import = __esm({
|
|
|
69071
69664
|
}
|
|
69072
69665
|
});
|
|
69073
69666
|
|
|
69667
|
+
// src/commands/steering-findings.ts
|
|
69668
|
+
var steering_findings_exports = {};
|
|
69669
|
+
__export(steering_findings_exports, {
|
|
69670
|
+
PROPOSAL_STATUS_WORDS: () => PROPOSAL_STATUS_WORDS,
|
|
69671
|
+
STEERING_FINDINGS_CAPABILITIES: () => STEERING_FINDINGS_CAPABILITIES,
|
|
69672
|
+
apiRefusal: () => apiRefusal,
|
|
69673
|
+
reportApiFailure: () => reportApiFailure,
|
|
69674
|
+
steeringFindings: () => steeringFindings,
|
|
69675
|
+
usageError: () => usageError
|
|
69676
|
+
});
|
|
69677
|
+
function isRecord9(value) {
|
|
69678
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
69679
|
+
}
|
|
69680
|
+
function textOrNull(value) {
|
|
69681
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
69682
|
+
}
|
|
69683
|
+
function apiRefusal(err2) {
|
|
69684
|
+
const message = errorMessage(err2);
|
|
69685
|
+
const start = message.indexOf("{");
|
|
69686
|
+
const end = message.lastIndexOf("}");
|
|
69687
|
+
if (start >= 0 && end > start) {
|
|
69688
|
+
try {
|
|
69689
|
+
const body2 = JSON.parse(message.slice(start, end + 1));
|
|
69690
|
+
const error = isRecord9(body2) && isRecord9(body2.error) ? body2.error : null;
|
|
69691
|
+
const said = error === null ? null : textOrNull(error.message);
|
|
69692
|
+
if (error !== null && said !== null) {
|
|
69693
|
+
return {
|
|
69694
|
+
code: textOrNull(error.code),
|
|
69695
|
+
reason: textOrNull(error.reason),
|
|
69696
|
+
message: said
|
|
69697
|
+
};
|
|
69698
|
+
}
|
|
69699
|
+
} catch {
|
|
69700
|
+
}
|
|
69701
|
+
}
|
|
69702
|
+
return { code: null, reason: null, message };
|
|
69703
|
+
}
|
|
69704
|
+
function reportApiFailure(out, writer, err2, nextSteps = {}) {
|
|
69705
|
+
const refusal = apiRefusal(err2);
|
|
69706
|
+
out.error(refusal.message, refusal.reason ?? refusal.code ?? "api");
|
|
69707
|
+
if (out.isJson || refusal.reason === null) return;
|
|
69708
|
+
const next = nextSteps[refusal.reason];
|
|
69709
|
+
if (next !== void 0) writer.writeErr(next);
|
|
69710
|
+
}
|
|
69711
|
+
function usageError(writer, message, line) {
|
|
69712
|
+
writer.writeErr(`error: ${message}`);
|
|
69713
|
+
writer.writeErr(`usage: ${line}`);
|
|
69714
|
+
process.exitCode = 2;
|
|
69715
|
+
}
|
|
69716
|
+
function plural(count7, one, many) {
|
|
69717
|
+
return `${count7} ${count7 === 1 ? one : many}`;
|
|
69718
|
+
}
|
|
69719
|
+
function findingRow(finding) {
|
|
69720
|
+
const pr = finding.pull_request;
|
|
69721
|
+
const proposal = finding.proposal;
|
|
69722
|
+
return [
|
|
69723
|
+
finding.id,
|
|
69724
|
+
finding.kind,
|
|
69725
|
+
`${finding.path}:${finding.line}`,
|
|
69726
|
+
finding.record.label ?? finding.record.lineage,
|
|
69727
|
+
`#${pr.number} ${pr.state}`,
|
|
69728
|
+
proposal === null ? "none" : `${proposal.id} (${PROPOSAL_STATUS_WORDS[proposal.status]})`
|
|
69729
|
+
];
|
|
69730
|
+
}
|
|
69731
|
+
async function steeringFindings(opts = {}, writer = stdoutWriter) {
|
|
69732
|
+
const out = createOutput({ json: opts.json }, writer);
|
|
69733
|
+
let result2;
|
|
69734
|
+
try {
|
|
69735
|
+
result2 = await apiGetOrThrow(
|
|
69736
|
+
"repository/findings"
|
|
69737
|
+
);
|
|
69738
|
+
} catch (err2) {
|
|
69739
|
+
reportApiFailure(out, writer, err2);
|
|
69740
|
+
return;
|
|
69741
|
+
}
|
|
69742
|
+
if (out.isJson) {
|
|
69743
|
+
out.data(result2);
|
|
69744
|
+
return;
|
|
69745
|
+
}
|
|
69746
|
+
const repositories = result2.repositories.filter((r) => r.findings.length > 0);
|
|
69747
|
+
if (repositories.length === 0) {
|
|
69748
|
+
writer.write(
|
|
69749
|
+
"No findings. The Oxagen check found no statement in a linked repository's instruction files that repeats or contradicts a steering record."
|
|
69750
|
+
);
|
|
69751
|
+
return;
|
|
69752
|
+
}
|
|
69753
|
+
let total2 = 0;
|
|
69754
|
+
for (const [index, repository] of repositories.entries()) {
|
|
69755
|
+
if (index > 0) writer.write("");
|
|
69756
|
+
writer.write(`${repository.full_name} (${repository.provider})`);
|
|
69757
|
+
printTable(
|
|
69758
|
+
["FINDING", "KIND", "FILE", "RECORD", "PULL REQUEST", "PROPOSAL"],
|
|
69759
|
+
repository.findings.map(findingRow),
|
|
69760
|
+
writer
|
|
69761
|
+
);
|
|
69762
|
+
total2 += repository.findings.length;
|
|
69763
|
+
}
|
|
69764
|
+
writer.write("");
|
|
69765
|
+
writer.write(
|
|
69766
|
+
`${plural(total2, "finding", "findings")} in ${plural(repositories.length, "repository", "repositories")}.`
|
|
69767
|
+
);
|
|
69768
|
+
const promotable = repositories.some(
|
|
69769
|
+
(r) => r.findings.some((f) => f.kind === "contradiction" && f.proposal === null)
|
|
69770
|
+
);
|
|
69771
|
+
if (promotable) {
|
|
69772
|
+
writer.write(
|
|
69773
|
+
"Promote a contradiction to a proposal with `oxagen steering promote <finding-id>`."
|
|
69774
|
+
);
|
|
69775
|
+
}
|
|
69776
|
+
}
|
|
69777
|
+
var STEERING_FINDINGS_CAPABILITIES, PROPOSAL_STATUS_WORDS;
|
|
69778
|
+
var init_steering_findings = __esm({
|
|
69779
|
+
"src/commands/steering-findings.ts"() {
|
|
69780
|
+
init_api();
|
|
69781
|
+
init_capture_writer();
|
|
69782
|
+
init_output();
|
|
69783
|
+
STEERING_FINDINGS_CAPABILITIES = [
|
|
69784
|
+
"list_code_repository_findings"
|
|
69785
|
+
];
|
|
69786
|
+
PROPOSAL_STATUS_WORDS = {
|
|
69787
|
+
proposed: "waiting for its steering PR",
|
|
69788
|
+
pr_open: "steering PR open",
|
|
69789
|
+
checks_running: "checks running",
|
|
69790
|
+
checks_passed: "checks passed",
|
|
69791
|
+
checks_failed: "checks failed",
|
|
69792
|
+
merged: "merged",
|
|
69793
|
+
rejected: "rejected"
|
|
69794
|
+
};
|
|
69795
|
+
}
|
|
69796
|
+
});
|
|
69797
|
+
|
|
69798
|
+
// src/commands/steering-promote.ts
|
|
69799
|
+
var steering_promote_exports = {};
|
|
69800
|
+
__export(steering_promote_exports, {
|
|
69801
|
+
STEERING_PROMOTE_CAPABILITIES: () => STEERING_PROMOTE_CAPABILITIES,
|
|
69802
|
+
steeringPromote: () => steeringPromote
|
|
69803
|
+
});
|
|
69804
|
+
async function steeringPromote(findingId, opts = {}, writer = stdoutWriter) {
|
|
69805
|
+
const id = findingId.trim();
|
|
69806
|
+
if (!FINDING_ID.test(id)) {
|
|
69807
|
+
usageError(
|
|
69808
|
+
writer,
|
|
69809
|
+
`expected a finding id that starts with crf_, got ${JSON.stringify(findingId)}. Run \`oxagen steering findings\` to list them.`,
|
|
69810
|
+
USAGE
|
|
69811
|
+
);
|
|
69812
|
+
return;
|
|
69813
|
+
}
|
|
69814
|
+
const out = createOutput({ json: opts.json }, writer);
|
|
69815
|
+
let result2;
|
|
69816
|
+
try {
|
|
69817
|
+
result2 = await apiPostOrThrow(
|
|
69818
|
+
"repository/findings/promote",
|
|
69819
|
+
{ finding_id: id }
|
|
69820
|
+
);
|
|
69821
|
+
} catch (err2) {
|
|
69822
|
+
reportApiFailure(out, writer, err2, NEXT_STEPS);
|
|
69823
|
+
return;
|
|
69824
|
+
}
|
|
69825
|
+
if (out.isJson) {
|
|
69826
|
+
out.data(result2);
|
|
69827
|
+
return;
|
|
69828
|
+
}
|
|
69829
|
+
writer.write(`Opened proposal ${result2.proposal_id} for record ${result2.lineage}.`);
|
|
69830
|
+
const pr = result2.pull_request;
|
|
69831
|
+
writer.write(
|
|
69832
|
+
pr === null ? "Steering PR: none yet" : `Steering PR: #${pr.number} ${pr.url}`
|
|
69833
|
+
);
|
|
69834
|
+
writer.write(`Status: ${PROPOSAL_STATUS_WORDS[result2.status]}`);
|
|
69835
|
+
writer.write("Nothing steers until a person merges the steering PR.");
|
|
69836
|
+
}
|
|
69837
|
+
var STEERING_PROMOTE_CAPABILITIES, FINDING_ID, USAGE, NEXT_STEPS;
|
|
69838
|
+
var init_steering_promote = __esm({
|
|
69839
|
+
"src/commands/steering-promote.ts"() {
|
|
69840
|
+
init_api();
|
|
69841
|
+
init_capture_writer();
|
|
69842
|
+
init_output();
|
|
69843
|
+
init_steering_findings();
|
|
69844
|
+
STEERING_PROMOTE_CAPABILITIES = [
|
|
69845
|
+
"promote_instruction_to_steering"
|
|
69846
|
+
];
|
|
69847
|
+
FINDING_ID = /^crf_[0-9A-Za-z]+$/;
|
|
69848
|
+
USAGE = "oxagen steering promote <finding-id> [--json]";
|
|
69849
|
+
NEXT_STEPS = {
|
|
69850
|
+
finding_resolved: "Run `oxagen steering findings` to see the statements that still match a record.",
|
|
69851
|
+
already_proposed: "Run `oxagen steering findings` to see the open proposal and its steering PR.",
|
|
69852
|
+
lineage_pr_open: "Merge or close the PR that is open on the record, then promote the finding again."
|
|
69853
|
+
};
|
|
69854
|
+
}
|
|
69855
|
+
});
|
|
69856
|
+
|
|
69857
|
+
// src/commands/steering-restore-block.ts
|
|
69858
|
+
var steering_restore_block_exports = {};
|
|
69859
|
+
__export(steering_restore_block_exports, {
|
|
69860
|
+
STEERING_RESTORE_BLOCK_CAPABILITIES: () => STEERING_RESTORE_BLOCK_CAPABILITIES,
|
|
69861
|
+
managedBlockFile: () => managedBlockFile,
|
|
69862
|
+
steeringRestoreBlock: () => steeringRestoreBlock
|
|
69863
|
+
});
|
|
69864
|
+
function managedBlockFile(path2) {
|
|
69865
|
+
const name = path2.trim().replace(/^\.\//, "").toLowerCase();
|
|
69866
|
+
const files2 = Object.keys(MANAGED_BLOCK_FILES);
|
|
69867
|
+
return files2.find((file) => file.toLowerCase() === name) ?? null;
|
|
69868
|
+
}
|
|
69869
|
+
async function steeringRestoreBlock(proposalId, path2, opts = {}, writer = stdoutWriter) {
|
|
69870
|
+
const id = proposalId.trim();
|
|
69871
|
+
if (!PROPOSAL_ID2.test(id)) {
|
|
69872
|
+
usageError(
|
|
69873
|
+
writer,
|
|
69874
|
+
`expected a proposal id that starts with prp_, got ${JSON.stringify(proposalId)}`,
|
|
69875
|
+
USAGE2
|
|
69876
|
+
);
|
|
69877
|
+
return;
|
|
69878
|
+
}
|
|
69879
|
+
const file = managedBlockFile(path2);
|
|
69880
|
+
if (file === null) {
|
|
69881
|
+
usageError(
|
|
69882
|
+
writer,
|
|
69883
|
+
`expected AGENTS.md, CLAUDE.md, or README.md, got ${JSON.stringify(path2)}`,
|
|
69884
|
+
USAGE2
|
|
69885
|
+
);
|
|
69886
|
+
return;
|
|
69887
|
+
}
|
|
69888
|
+
const out = createOutput({ json: opts.json }, writer);
|
|
69889
|
+
let result2;
|
|
69890
|
+
try {
|
|
69891
|
+
result2 = await apiPostOrThrow(
|
|
69892
|
+
"context/prs/restore-block",
|
|
69893
|
+
{ proposalId: id, path: file }
|
|
69894
|
+
);
|
|
69895
|
+
} catch (err2) {
|
|
69896
|
+
reportApiFailure(out, writer, err2);
|
|
69897
|
+
return;
|
|
69898
|
+
}
|
|
69899
|
+
if (out.isJson) {
|
|
69900
|
+
out.data(result2);
|
|
69901
|
+
return;
|
|
69902
|
+
}
|
|
69903
|
+
writer.write(
|
|
69904
|
+
`Restored the managed block in ${file} on the steering PR for ${id}.`
|
|
69905
|
+
);
|
|
69906
|
+
writer.write(`Commit: ${result2.commit_sha}`);
|
|
69907
|
+
writer.write(`Status: ${PROPOSAL_STATUS_WORDS[result2.status]}`);
|
|
69908
|
+
}
|
|
69909
|
+
var STEERING_RESTORE_BLOCK_CAPABILITIES, MANAGED_BLOCK_FILES, PROPOSAL_ID2, USAGE2;
|
|
69910
|
+
var init_steering_restore_block = __esm({
|
|
69911
|
+
"src/commands/steering-restore-block.ts"() {
|
|
69912
|
+
init_api();
|
|
69913
|
+
init_capture_writer();
|
|
69914
|
+
init_output();
|
|
69915
|
+
init_steering_findings();
|
|
69916
|
+
STEERING_RESTORE_BLOCK_CAPABILITIES = [
|
|
69917
|
+
"restore_managed_block"
|
|
69918
|
+
];
|
|
69919
|
+
MANAGED_BLOCK_FILES = {
|
|
69920
|
+
"AGENTS.md": true,
|
|
69921
|
+
"CLAUDE.md": true,
|
|
69922
|
+
"README.md": true
|
|
69923
|
+
};
|
|
69924
|
+
PROPOSAL_ID2 = /^prp_[0-9A-Za-z]+$/;
|
|
69925
|
+
USAGE2 = "oxagen steering restore-block <proposal-id> <AGENTS.md|CLAUDE.md|README.md> [--json]";
|
|
69926
|
+
}
|
|
69927
|
+
});
|
|
69928
|
+
|
|
69074
69929
|
// src/commands/tools.ts
|
|
69075
69930
|
var tools_exports = {};
|
|
69076
69931
|
__export(tools_exports, {
|
|
@@ -69149,7 +70004,7 @@ function resolveDownloadUrl(url, apiUrl) {
|
|
|
69149
70004
|
const base2 = apiUrl.replace(/\/+$/, "");
|
|
69150
70005
|
return `${base2}${url.startsWith("/") ? "" : "/"}${url}`;
|
|
69151
70006
|
}
|
|
69152
|
-
function
|
|
70007
|
+
function formatBytes2(bytes) {
|
|
69153
70008
|
return bytes === null ? "not recorded" : `${bytes.toLocaleString("en-US")} bytes`;
|
|
69154
70009
|
}
|
|
69155
70010
|
async function runExportStatus(exportId, opts = {}, writer = stdoutWriter) {
|
|
@@ -69183,7 +70038,7 @@ async function runExportStatus(exportId, opts = {}, writer = stdoutWriter) {
|
|
|
69183
70038
|
);
|
|
69184
70039
|
return;
|
|
69185
70040
|
}
|
|
69186
|
-
writer.write(`Size: ${
|
|
70041
|
+
writer.write(`Size: ${formatBytes2(result2.bundleBytes)}`);
|
|
69187
70042
|
writer.write(`Digest: ${result2.bundleDigest ?? "not recorded"}`);
|
|
69188
70043
|
writer.write(`Frames: ${result2.frameCount ?? "not recorded"}`);
|
|
69189
70044
|
writer.write(`Merkle root: ${result2.merkleRoot ?? "not recorded"}`);
|
|
@@ -69275,7 +70130,7 @@ async function runDownload(exportId, opts = {}, writer = stdoutWriter) {
|
|
|
69275
70130
|
out.data(result2);
|
|
69276
70131
|
return;
|
|
69277
70132
|
}
|
|
69278
|
-
writer.write(`Wrote ${path2} (${
|
|
70133
|
+
writer.write(`Wrote ${path2} (${formatBytes2(bytes.byteLength)}).`);
|
|
69279
70134
|
writer.write(`Digest ${actual} matches the recorded bundle digest.`);
|
|
69280
70135
|
writer.write(`Check every frame offline with \`oxagen verify ${path2}\`.`);
|
|
69281
70136
|
}
|
|
@@ -70446,10 +71301,10 @@ __export(verify_exports, {
|
|
|
70446
71301
|
verifyBundle: () => verifyBundle3
|
|
70447
71302
|
});
|
|
70448
71303
|
import { existsSync as existsSync25, readFileSync as readFileSync22, statSync as statSync10 } from "node:fs";
|
|
70449
|
-
import { join as
|
|
71304
|
+
import { join as join45 } from "node:path";
|
|
70450
71305
|
function readDirectory(dir) {
|
|
70451
71306
|
const read2 = (name) => {
|
|
70452
|
-
const path2 =
|
|
71307
|
+
const path2 = join45(dir, name);
|
|
70453
71308
|
return existsSync25(path2) ? readFileSync22(path2, "utf8") : void 0;
|
|
70454
71309
|
};
|
|
70455
71310
|
return assemble(read2, dir);
|
|
@@ -70509,7 +71364,7 @@ function formatFrame(frame) {
|
|
|
70509
71364
|
return parts.join(" ");
|
|
70510
71365
|
}
|
|
70511
71366
|
function formatCounts(counts) {
|
|
70512
|
-
return counts.map((c) => `${c.kind} ${c.count} (in ${
|
|
71367
|
+
return counts.map((c) => `${c.kind} ${c.count} (in ${plural2(c.frames, "frame")})`).join(", ");
|
|
70513
71368
|
}
|
|
70514
71369
|
function formatVerification(result2) {
|
|
70515
71370
|
const lines = [];
|
|
@@ -70522,7 +71377,7 @@ function formatVerification(result2) {
|
|
|
70522
71377
|
).length;
|
|
70523
71378
|
if (notCarried > 0) {
|
|
70524
71379
|
lines.push(
|
|
70525
|
-
` Digest not carried on ${
|
|
71380
|
+
` Digest not carried on ${plural2(notCarried, "wrapped (tse_) frame")}. A wrapped frame is hashed over its full event, and the bundle does not hold that event for these frames: an export before format 3 never did, and a format-3 export leaves it out when the stored row cannot be proven to rebuild it. For these frames, only the links and the Merkle root can be checked.`
|
|
70526
71381
|
);
|
|
70527
71382
|
}
|
|
70528
71383
|
lines.push("");
|
|
@@ -70551,7 +71406,7 @@ function formatVerification(result2) {
|
|
|
70551
71406
|
(c) => c.status === "broken"
|
|
70552
71407
|
).length;
|
|
70553
71408
|
lines.push(
|
|
70554
|
-
result2.ok ? `HELD ${runId}: ${
|
|
71409
|
+
result2.ok ? `HELD ${runId}: ${plural2(result2.frames.length, "frame")}` : `BROKEN ${runId}: ${brokenFrames} of ${plural2(result2.frames.length, "frame")} broken, ${plural2(brokenChecks, "check")} broken`
|
|
70555
71410
|
);
|
|
70556
71411
|
return lines;
|
|
70557
71412
|
}
|
|
@@ -70569,7 +71424,7 @@ async function verifyBundle3(bundle2, opts = {}, writer = stdoutWriter) {
|
|
|
70569
71424
|
if (!result2.ok && (process.exitCode === void 0 || process.exitCode === 0))
|
|
70570
71425
|
process.exitCode = 1;
|
|
70571
71426
|
}
|
|
70572
|
-
var REQUIRED, OPTIONAL, BundleReadError,
|
|
71427
|
+
var REQUIRED, OPTIONAL, BundleReadError, plural2;
|
|
70573
71428
|
var init_verify2 = __esm({
|
|
70574
71429
|
"src/commands/verify.ts"() {
|
|
70575
71430
|
init_esm2();
|
|
@@ -70584,7 +71439,7 @@ var init_verify2 = __esm({
|
|
|
70584
71439
|
OPTIONAL = "redactions.json";
|
|
70585
71440
|
BundleReadError = class extends Error {
|
|
70586
71441
|
};
|
|
70587
|
-
|
|
71442
|
+
plural2 = (n4, word) => `${n4} ${word}${n4 === 1 ? "" : "s"}`;
|
|
70588
71443
|
}
|
|
70589
71444
|
});
|
|
70590
71445
|
|
|
@@ -70796,7 +71651,7 @@ function ago(iso, now = /* @__PURE__ */ new Date()) {
|
|
|
70796
71651
|
if (hours < 48) return `${hours}h ago`;
|
|
70797
71652
|
return `${Math.round(hours / 24)}d ago`;
|
|
70798
71653
|
}
|
|
70799
|
-
function
|
|
71654
|
+
function plural3(count7, one, many) {
|
|
70800
71655
|
return `${count7} ${count7 === 1 ? one : many}`;
|
|
70801
71656
|
}
|
|
70802
71657
|
function table(headers, rows) {
|
|
@@ -70808,7 +71663,7 @@ function table(headers, rows) {
|
|
|
70808
71663
|
}
|
|
70809
71664
|
function formatWorkspaceMemories(result2, now = /* @__PURE__ */ new Date()) {
|
|
70810
71665
|
if (result2.groups.length === 0) {
|
|
70811
|
-
return result2.total_groups === 0 ? "No memories yet. Oxagen collects them from enrolled hosts every five minutes." : `No memories on this page. The list holds ${
|
|
71666
|
+
return result2.total_groups === 0 ? "No memories yet. Oxagen collects them from enrolled hosts every five minutes." : `No memories on this page. The list holds ${plural3(result2.total_groups, "group", "groups")}.`;
|
|
70812
71667
|
}
|
|
70813
71668
|
const rows = result2.groups.map((group) => {
|
|
70814
71669
|
const { memory } = group;
|
|
@@ -70827,13 +71682,13 @@ function formatWorkspaceMemories(result2, now = /* @__PURE__ */ new Date()) {
|
|
|
70827
71682
|
const shown2 = result2.groups.length;
|
|
70828
71683
|
lines.push(
|
|
70829
71684
|
"",
|
|
70830
|
-
shown2 < result2.total_groups ? `Showing ${shown2} of ${
|
|
71685
|
+
shown2 < result2.total_groups ? `Showing ${shown2} of ${plural3(result2.total_groups, "group", "groups")}. Use --limit and --offset to page.` : `${plural3(result2.total_groups, "group", "groups")}.`
|
|
70831
71686
|
);
|
|
70832
71687
|
if (result2.truncated)
|
|
70833
71688
|
lines.push(
|
|
70834
71689
|
`More than ${result2.total_memories} memories matched, and the list groups the top ${result2.total_memories}. Narrow the filters to see the rest.`
|
|
70835
71690
|
);
|
|
70836
|
-
lines.push(`${
|
|
71691
|
+
lines.push(`${plural3(result2.waiting, "memory waits", "memories wait")} in this workspace.`);
|
|
70837
71692
|
return lines.join("\n");
|
|
70838
71693
|
}
|
|
70839
71694
|
function formatWorkspaceMemory(result2, now = /* @__PURE__ */ new Date()) {
|
|
@@ -70891,7 +71746,7 @@ function formatDismissResult(result2, restore) {
|
|
|
70891
71746
|
const lines = [];
|
|
70892
71747
|
if (result2.changed.length > 0)
|
|
70893
71748
|
lines.push(
|
|
70894
|
-
`${restore ? "Restored" : "Dismissed"} ${
|
|
71749
|
+
`${restore ? "Restored" : "Dismissed"} ${plural3(result2.changed.length, "memory", "memories")}: ${result2.changed.join(", ")}.`
|
|
70895
71750
|
);
|
|
70896
71751
|
else lines.push(`No memory was ${restore ? "restored" : "dismissed"}.`);
|
|
70897
71752
|
if (!restore && result2.rejections > 0)
|
|
@@ -71360,7 +72215,7 @@ import {
|
|
|
71360
72215
|
writeFileSync as writeFileSync10
|
|
71361
72216
|
} from "node:fs";
|
|
71362
72217
|
import { homedir as homedir12, hostname as osHostname3 } from "node:os";
|
|
71363
|
-
import { join as
|
|
72218
|
+
import { join as join46, relative as relative7, resolve as resolve17, sep as sep5 } from "node:path";
|
|
71364
72219
|
function git4(cwd, args) {
|
|
71365
72220
|
return new Promise((done) => {
|
|
71366
72221
|
try {
|
|
@@ -71407,7 +72262,7 @@ function parseRemoteRepository(url) {
|
|
|
71407
72262
|
}
|
|
71408
72263
|
function oxagenPresent(root) {
|
|
71409
72264
|
try {
|
|
71410
|
-
return readdirSync12(
|
|
72265
|
+
return readdirSync12(join46(root, ".oxagen")).some(
|
|
71411
72266
|
(name) => name !== "workspace.json"
|
|
71412
72267
|
);
|
|
71413
72268
|
} catch {
|
|
@@ -71416,18 +72271,18 @@ function oxagenPresent(root) {
|
|
|
71416
72271
|
}
|
|
71417
72272
|
function symlinkState(root) {
|
|
71418
72273
|
try {
|
|
71419
|
-
if (!lstatSync8(
|
|
72274
|
+
if (!lstatSync8(join46(root, ".stella")).isDirectory()) return "none";
|
|
71420
72275
|
} catch {
|
|
71421
72276
|
return "none";
|
|
71422
72277
|
}
|
|
71423
72278
|
let oxagenReal;
|
|
71424
72279
|
try {
|
|
71425
|
-
oxagenReal = realpathSync7(
|
|
72280
|
+
oxagenReal = realpathSync7(join46(root, ".oxagen"));
|
|
71426
72281
|
} catch {
|
|
71427
72282
|
return "missing";
|
|
71428
72283
|
}
|
|
71429
72284
|
for (const link of STELLA_LINKS) {
|
|
71430
|
-
const at =
|
|
72285
|
+
const at = join46(root, link);
|
|
71431
72286
|
try {
|
|
71432
72287
|
if (!lstatSync8(at).isSymbolicLink()) return "missing";
|
|
71433
72288
|
const target2 = realpathSync7(at);
|
|
@@ -71441,7 +72296,7 @@ function symlinkState(root) {
|
|
|
71441
72296
|
return "linked";
|
|
71442
72297
|
}
|
|
71443
72298
|
function machineId(configDir = getConfigDir()) {
|
|
71444
|
-
const file =
|
|
72299
|
+
const file = join46(configDir, MACHINE_ID_FILE);
|
|
71445
72300
|
let secret = null;
|
|
71446
72301
|
try {
|
|
71447
72302
|
if (existsSync26(file)) {
|
|
@@ -71521,14 +72376,14 @@ async function ensureWorkspaceLinkIgnored(root) {
|
|
|
71521
72376
|
const top = await git4(root, ["rev-parse", "--show-toplevel"]);
|
|
71522
72377
|
if (!top) return null;
|
|
71523
72378
|
const topDir = resolve17(top);
|
|
71524
|
-
const entry2 =
|
|
72379
|
+
const entry2 = relative7(
|
|
71525
72380
|
topDir,
|
|
71526
|
-
|
|
72381
|
+
join46(realpathOr2(root), ".oxagen", "workspace.json")
|
|
71527
72382
|
).split(sep5).join("/");
|
|
71528
72383
|
if (entry2.startsWith("../")) return null;
|
|
71529
72384
|
const rule = await git4(topDir, ["check-ignore", "--no-index", "-v", entry2]);
|
|
71530
72385
|
if (rule !== null) return null;
|
|
71531
|
-
const gitignore =
|
|
72386
|
+
const gitignore = join46(resolve17(top), ".gitignore");
|
|
71532
72387
|
let existing = "";
|
|
71533
72388
|
try {
|
|
71534
72389
|
existing = readFileSync23(gitignore, "utf8");
|
|
@@ -72011,8 +72866,8 @@ import {
|
|
|
72011
72866
|
} from "node:fs";
|
|
72012
72867
|
import {
|
|
72013
72868
|
dirname as dirname26,
|
|
72014
|
-
isAbsolute as
|
|
72015
|
-
join as
|
|
72869
|
+
isAbsolute as isAbsolute12,
|
|
72870
|
+
join as join47,
|
|
72016
72871
|
parse as parsePath2,
|
|
72017
72872
|
posix as posix5,
|
|
72018
72873
|
sep as sep6
|
|
@@ -72025,7 +72880,7 @@ function checkSteeringPath(path2) {
|
|
|
72025
72880
|
if (path2.includes("\\")) {
|
|
72026
72881
|
return { ok: false, reason: "contains a backslash" };
|
|
72027
72882
|
}
|
|
72028
|
-
if (posix5.isAbsolute(path2) ||
|
|
72883
|
+
if (posix5.isAbsolute(path2) || isAbsolute12(path2) || /^[A-Za-z]:/.test(path2)) {
|
|
72029
72884
|
return { ok: false, reason: "absolute path" };
|
|
72030
72885
|
}
|
|
72031
72886
|
const normalized = posix5.normalize(path2);
|
|
@@ -72125,7 +72980,7 @@ function findLinkedRoot(start) {
|
|
|
72125
72980
|
}
|
|
72126
72981
|
function fsReader(root) {
|
|
72127
72982
|
return (path2) => {
|
|
72128
|
-
const abs =
|
|
72983
|
+
const abs = join47(root, ...path2.split("/"));
|
|
72129
72984
|
try {
|
|
72130
72985
|
const st = lstatSync9(abs);
|
|
72131
72986
|
if (!st.isFile()) return Buffer.from(`\0not-a-file:${abs}`);
|
|
@@ -72136,14 +72991,14 @@ function fsReader(root) {
|
|
|
72136
72991
|
};
|
|
72137
72992
|
}
|
|
72138
72993
|
function assertInsideOxagen(root, path2) {
|
|
72139
|
-
const oxagenAbs =
|
|
72994
|
+
const oxagenAbs = join47(root, OXAGEN_DIR);
|
|
72140
72995
|
let oxagenReal;
|
|
72141
72996
|
try {
|
|
72142
72997
|
oxagenReal = realpathSync8(oxagenAbs);
|
|
72143
72998
|
} catch {
|
|
72144
72999
|
return;
|
|
72145
73000
|
}
|
|
72146
|
-
const abs =
|
|
73001
|
+
const abs = join47(root, ...path2.split("/"));
|
|
72147
73002
|
try {
|
|
72148
73003
|
if (lstatSync9(abs).isSymbolicLink()) {
|
|
72149
73004
|
throw new Error(
|
|
@@ -72173,8 +73028,8 @@ function assertInsideOxagen(root, path2) {
|
|
|
72173
73028
|
}
|
|
72174
73029
|
}
|
|
72175
73030
|
function pruneEmptyDirs(root, path2) {
|
|
72176
|
-
const stop =
|
|
72177
|
-
let dir = dirname26(
|
|
73031
|
+
const stop = join47(root, OXAGEN_DIR);
|
|
73032
|
+
let dir = dirname26(join47(root, ...path2.split("/")));
|
|
72178
73033
|
while (dir.startsWith(stop + sep6)) {
|
|
72179
73034
|
try {
|
|
72180
73035
|
if (readdirSync13(dir).length > 0) return;
|
|
@@ -72189,12 +73044,12 @@ function applyPlan(root, plan) {
|
|
|
72189
73044
|
for (const w of plan.writes) assertInsideOxagen(root, w.path);
|
|
72190
73045
|
for (const d of plan.deletes) assertInsideOxagen(root, d);
|
|
72191
73046
|
for (const w of plan.writes) {
|
|
72192
|
-
const abs =
|
|
73047
|
+
const abs = join47(root, ...w.path.split("/"));
|
|
72193
73048
|
mkdirSync12(dirname26(abs), { recursive: true });
|
|
72194
73049
|
atomicWriteFileSync(abs, w.content);
|
|
72195
73050
|
}
|
|
72196
73051
|
for (const d of plan.deletes) {
|
|
72197
|
-
rmSync9(
|
|
73052
|
+
rmSync9(join47(root, ...d.split("/")), { force: true });
|
|
72198
73053
|
pruneEmptyDirs(root, d);
|
|
72199
73054
|
}
|
|
72200
73055
|
}
|
|
@@ -74292,7 +75147,7 @@ var init_registry_launch = __esm({
|
|
|
74292
75147
|
function messageOf2(error) {
|
|
74293
75148
|
return error instanceof Error ? error.message : String(error);
|
|
74294
75149
|
}
|
|
74295
|
-
function
|
|
75150
|
+
function isRecord10(value) {
|
|
74296
75151
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
74297
75152
|
}
|
|
74298
75153
|
function isList(value) {
|
|
@@ -74303,7 +75158,7 @@ function jsonEqual(a, b5) {
|
|
|
74303
75158
|
if (Array.isArray(a)) {
|
|
74304
75159
|
return Array.isArray(b5) && a.length === b5.length && a.every((item, index) => jsonEqual(item, b5[index]));
|
|
74305
75160
|
}
|
|
74306
|
-
if (
|
|
75161
|
+
if (isRecord10(a) && isRecord10(b5)) {
|
|
74307
75162
|
const keys = Object.keys(a);
|
|
74308
75163
|
return keys.length === Object.keys(b5).length && keys.every((key) => Object.hasOwn(b5, key) && jsonEqual(a[key], b5[key]));
|
|
74309
75164
|
}
|
|
@@ -74312,16 +75167,16 @@ function jsonEqual(a, b5) {
|
|
|
74312
75167
|
function valueAt2(value, path2) {
|
|
74313
75168
|
let current = value;
|
|
74314
75169
|
for (const step of path2.split(".")) {
|
|
74315
|
-
if (step.endsWith("[]") || !
|
|
75170
|
+
if (step.endsWith("[]") || !isRecord10(current) || !Object.hasOwn(current, step)) return void 0;
|
|
74316
75171
|
current = current[step];
|
|
74317
75172
|
}
|
|
74318
75173
|
return current;
|
|
74319
75174
|
}
|
|
74320
75175
|
function withValueAt(value, path2, replacement) {
|
|
74321
75176
|
const [step, ...rest] = path2.split(".");
|
|
74322
|
-
if (step === void 0 || !
|
|
75177
|
+
if (step === void 0 || !isRecord10(value)) return value;
|
|
74323
75178
|
const inner = Object.hasOwn(value, step) ? value[step] : void 0;
|
|
74324
|
-
if (rest.length > 0 && !
|
|
75179
|
+
if (rest.length > 0 && !isRecord10(inner)) return value;
|
|
74325
75180
|
const next = rest.length === 0 ? replacement : withValueAt(inner, rest.join("."), replacement);
|
|
74326
75181
|
return { ...value, [step]: next };
|
|
74327
75182
|
}
|
|
@@ -74996,11 +75851,11 @@ var init_openapi = __esm({
|
|
|
74996
75851
|
});
|
|
74997
75852
|
|
|
74998
75853
|
// ../../packages/mcp-studio/src/compile/json-schema.ts
|
|
74999
|
-
function
|
|
75854
|
+
function isRecord12(value) {
|
|
75000
75855
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
75001
75856
|
}
|
|
75002
75857
|
function propertiesOf(schema) {
|
|
75003
|
-
return
|
|
75858
|
+
return isRecord12(schema.properties) ? schema.properties : {};
|
|
75004
75859
|
}
|
|
75005
75860
|
function requiredOf(schema) {
|
|
75006
75861
|
if (!Array.isArray(schema.required)) return [];
|
|
@@ -82612,13 +83467,13 @@ var require_path = __commonJS({
|
|
|
82612
83467
|
"../../node_modules/.pnpm/@protobufjs+path@1.1.2/node_modules/@protobufjs/path/index.js"(exports) {
|
|
82613
83468
|
"use strict";
|
|
82614
83469
|
var path2 = exports;
|
|
82615
|
-
var
|
|
83470
|
+
var isAbsolute14 = (
|
|
82616
83471
|
/**
|
|
82617
83472
|
* Tests if the specified path is absolute.
|
|
82618
83473
|
* @param {string} path Path to test
|
|
82619
83474
|
* @returns {boolean} `true` if path is absolute
|
|
82620
83475
|
*/
|
|
82621
|
-
path2.isAbsolute = function
|
|
83476
|
+
path2.isAbsolute = function isAbsolute15(path3) {
|
|
82622
83477
|
return /^(?:\/|\w+:)/.test(path3);
|
|
82623
83478
|
}
|
|
82624
83479
|
);
|
|
@@ -82630,7 +83485,7 @@ var require_path = __commonJS({
|
|
|
82630
83485
|
*/
|
|
82631
83486
|
path2.normalize = function normalize3(path3) {
|
|
82632
83487
|
path3 = path3.replace(/\\/g, "/").replace(/\/{2,}/g, "/");
|
|
82633
|
-
var parts = path3.split("/"), absolute =
|
|
83488
|
+
var parts = path3.split("/"), absolute = isAbsolute14(path3), prefix = "";
|
|
82634
83489
|
if (absolute)
|
|
82635
83490
|
prefix = parts.shift() + "/";
|
|
82636
83491
|
for (var i2 = 0; i2 < parts.length; ) {
|
|
@@ -82652,7 +83507,7 @@ var require_path = __commonJS({
|
|
|
82652
83507
|
path2.resolve = function resolve19(originPath, includePath, alreadyNormalized) {
|
|
82653
83508
|
if (!alreadyNormalized)
|
|
82654
83509
|
includePath = normalize2(includePath);
|
|
82655
|
-
if (
|
|
83510
|
+
if (isAbsolute14(includePath))
|
|
82656
83511
|
return includePath;
|
|
82657
83512
|
if (!alreadyNormalized)
|
|
82658
83513
|
originPath = normalize2(originPath);
|
|
@@ -86926,7 +87781,7 @@ function shapeInput(key, entry2, upstream, supplied, issues) {
|
|
|
86926
87781
|
for (const [name, value] of defaults) {
|
|
86927
87782
|
if (!usable("defaults", name)) continue;
|
|
86928
87783
|
const property = shaped[name];
|
|
86929
|
-
shaped[name] = { ...
|
|
87784
|
+
shaped[name] = { ...isRecord12(property) ? property : {}, default: value };
|
|
86930
87785
|
required = required.filter((other) => other !== name);
|
|
86931
87786
|
}
|
|
86932
87787
|
const renamed = /* @__PURE__ */ new Map();
|
|
@@ -86972,7 +87827,7 @@ function selectTree(paths) {
|
|
|
86972
87827
|
return root;
|
|
86973
87828
|
}
|
|
86974
87829
|
function trimObject(schema, children) {
|
|
86975
|
-
if (!
|
|
87830
|
+
if (!isRecord12(schema.properties)) return schema;
|
|
86976
87831
|
const properties = schema.properties;
|
|
86977
87832
|
const kept = {};
|
|
86978
87833
|
for (const [name, node2] of children) {
|
|
@@ -86986,9 +87841,9 @@ function trimObject(schema, children) {
|
|
|
86986
87841
|
return out;
|
|
86987
87842
|
}
|
|
86988
87843
|
function trimNode(schema, node2) {
|
|
86989
|
-
if (node2.whole || !
|
|
87844
|
+
if (node2.whole || !isRecord12(schema)) return schema;
|
|
86990
87845
|
if (!node2.array) return trimObject(schema, node2.children);
|
|
86991
|
-
return
|
|
87846
|
+
return isRecord12(schema.items) ? { ...schema, items: trimObject(schema.items, node2.children) } : schema;
|
|
86992
87847
|
}
|
|
86993
87848
|
function selectOutput(outputSchema, select) {
|
|
86994
87849
|
if (select.length === 0) return outputSchema;
|
|
@@ -87660,12 +88515,12 @@ function walkSchemas(root, at, visit2) {
|
|
|
87660
88515
|
node2.forEach((item, index) => walk(item, `${path2}[${index}]`, depth + 1));
|
|
87661
88516
|
return;
|
|
87662
88517
|
}
|
|
87663
|
-
if (!
|
|
88518
|
+
if (!isRecord12(node2) || above.has(node2)) return;
|
|
87664
88519
|
visit2(node2, path2);
|
|
87665
88520
|
above.add(node2);
|
|
87666
88521
|
for (const [key, value] of Object.entries(node2)) {
|
|
87667
88522
|
if (DATA.has(key)) continue;
|
|
87668
|
-
if (SCHEMA_MAPS.has(key) &&
|
|
88523
|
+
if (SCHEMA_MAPS.has(key) && isRecord12(value)) {
|
|
87669
88524
|
for (const [name, child] of Object.entries(value)) walk(child, `${path2}.${key}.${name}`, depth + 1);
|
|
87670
88525
|
} else {
|
|
87671
88526
|
walk(value, `${path2}.${key}`, depth + 1);
|
|
@@ -87676,14 +88531,14 @@ function walkSchemas(root, at, visit2) {
|
|
|
87676
88531
|
walk(root, at, 0);
|
|
87677
88532
|
}
|
|
87678
88533
|
function tagOf(schema) {
|
|
87679
|
-
if (!
|
|
88534
|
+
if (!isRecord12(schema)) return void 0;
|
|
87680
88535
|
if (Object.hasOwn(schema, "const")) return JSON.stringify(schema.const);
|
|
87681
88536
|
if (Array.isArray(schema.enum) && schema.enum.length === 1) return JSON.stringify(schema.enum[0]);
|
|
87682
88537
|
return void 0;
|
|
87683
88538
|
}
|
|
87684
88539
|
function distinguishable(branches) {
|
|
87685
88540
|
if (branches.length < 2) return true;
|
|
87686
|
-
const records = branches.filter(
|
|
88541
|
+
const records = branches.filter(isRecord12);
|
|
87687
88542
|
const [first] = records;
|
|
87688
88543
|
if (first === void 0 || records.length < branches.length) return false;
|
|
87689
88544
|
const types = records.map((branch) => branch.type);
|
|
@@ -87774,7 +88629,7 @@ function shapedInput(entry2, upstream) {
|
|
|
87774
88629
|
for (const [name, value] of defaults) {
|
|
87775
88630
|
if (!Object.hasOwn(shaped, name)) continue;
|
|
87776
88631
|
const property = shaped[name];
|
|
87777
|
-
shaped[name] = { ...
|
|
88632
|
+
shaped[name] = { ...isRecord12(property) ? property : {}, default: value };
|
|
87778
88633
|
required = required.filter((other) => other !== name);
|
|
87779
88634
|
}
|
|
87780
88635
|
const renamed = new Map(rename3.filter(([from]) => Object.hasOwn(shaped, from)));
|
|
@@ -87804,7 +88659,7 @@ function selectTree2(paths) {
|
|
|
87804
88659
|
return root;
|
|
87805
88660
|
}
|
|
87806
88661
|
function trimObject2(schema, children) {
|
|
87807
|
-
if (!
|
|
88662
|
+
if (!isRecord12(schema.properties)) return schema;
|
|
87808
88663
|
const properties = schema.properties;
|
|
87809
88664
|
const kept = {};
|
|
87810
88665
|
for (const [name, node2] of children) {
|
|
@@ -87818,9 +88673,9 @@ function trimObject2(schema, children) {
|
|
|
87818
88673
|
return out;
|
|
87819
88674
|
}
|
|
87820
88675
|
function trimNode2(schema, node2) {
|
|
87821
|
-
if (node2.whole || !
|
|
88676
|
+
if (node2.whole || !isRecord12(schema)) return schema;
|
|
87822
88677
|
if (!node2.array) return trimObject2(schema, node2.children);
|
|
87823
|
-
return
|
|
88678
|
+
return isRecord12(schema.items) ? { ...schema, items: trimObject2(schema.items, node2.children) } : schema;
|
|
87824
88679
|
}
|
|
87825
88680
|
function servedOutput(outputSchema, select) {
|
|
87826
88681
|
if (select.length === 0) return outputSchema;
|
|
@@ -87870,7 +88725,7 @@ function quoted(values) {
|
|
|
87870
88725
|
return orList2(values.map((value) => JSON.stringify(value)));
|
|
87871
88726
|
}
|
|
87872
88727
|
function isArraySchema(schema) {
|
|
87873
|
-
if (!
|
|
88728
|
+
if (!isRecord12(schema)) return false;
|
|
87874
88729
|
return schema.type === "array" || Array.isArray(schema.type) && schema.type.includes("array");
|
|
87875
88730
|
}
|
|
87876
88731
|
function lintTools(folder, context, report) {
|
|
@@ -88047,7 +88902,7 @@ function lintUpstream(folder, context, key, entry2, upstream, report) {
|
|
|
88047
88902
|
});
|
|
88048
88903
|
}
|
|
88049
88904
|
const oneOf2 = (node2, at) => {
|
|
88050
|
-
if (!Array.isArray(node2.oneOf) ||
|
|
88905
|
+
if (!Array.isArray(node2.oneOf) || isRecord12(node2.discriminator) || distinguishable(node2.oneOf)) return;
|
|
88051
88906
|
report("undiscriminated_one_of", {
|
|
88052
88907
|
tool: key,
|
|
88053
88908
|
field: `${at}.oneOf`,
|
|
@@ -88657,7 +89512,7 @@ function upstreamError(response, bytes) {
|
|
|
88657
89512
|
let problem;
|
|
88658
89513
|
if (text4 !== "" && isJsonMediaType(headerValue(response.headers, "content-type"))) {
|
|
88659
89514
|
const parsed = parseJson3(text4);
|
|
88660
|
-
if (parsed.ok &&
|
|
89515
|
+
if (parsed.ok && isRecord10(parsed.value)) problem = parsed.value;
|
|
88661
89516
|
}
|
|
88662
89517
|
const title = problem === void 0 ? void 0 : firstText(problem, ["title"]);
|
|
88663
89518
|
const detail = problem === void 0 ? text4.trim() === "" ? void 0 : text4 : firstText(problem, ["detail", "message", "error_description", "error"]);
|
|
@@ -88841,11 +89696,11 @@ var init_apply_credential = __esm({
|
|
|
88841
89696
|
|
|
88842
89697
|
// ../../packages/mcp-studio/src/execute/mcp.ts
|
|
88843
89698
|
function toolResult(value) {
|
|
88844
|
-
if (!
|
|
89699
|
+
if (!isRecord10(value)) return { ok: false, detail: "The tools/call result is not an object." };
|
|
88845
89700
|
if (!isList(value.content)) return { ok: false, detail: "The tools/call result has no content list." };
|
|
88846
89701
|
const content = [];
|
|
88847
89702
|
for (const [index, item] of value.content.entries()) {
|
|
88848
|
-
if (!
|
|
89703
|
+
if (!isRecord10(item) || typeof item.type !== "string") {
|
|
88849
89704
|
return { ok: false, detail: `Content item ${index} is not an object with a string type.` };
|
|
88850
89705
|
}
|
|
88851
89706
|
content.push({ ...item, type: item.type });
|
|
@@ -88853,7 +89708,7 @@ function toolResult(value) {
|
|
|
88853
89708
|
const result2 = { content };
|
|
88854
89709
|
const structured = value.structuredContent;
|
|
88855
89710
|
if (structured !== void 0 && structured !== null) {
|
|
88856
|
-
if (!
|
|
89711
|
+
if (!isRecord10(structured)) return { ok: false, detail: "The tools/call result's structuredContent is not an object." };
|
|
88857
89712
|
result2.structuredContent = structured;
|
|
88858
89713
|
}
|
|
88859
89714
|
const isError = value.isError;
|
|
@@ -88972,7 +89827,7 @@ function rejectedAttempt(response, failure2) {
|
|
|
88972
89827
|
function findResponse(value, id) {
|
|
88973
89828
|
const messages = isList(value) ? value : [value];
|
|
88974
89829
|
for (const message of messages) {
|
|
88975
|
-
if (
|
|
89830
|
+
if (isRecord10(message) && message.id === id && !Object.hasOwn(message, "method")) return message;
|
|
88976
89831
|
}
|
|
88977
89832
|
return void 0;
|
|
88978
89833
|
}
|
|
@@ -89022,8 +89877,8 @@ async function readReply(session, response, id, what) {
|
|
|
89022
89877
|
return { ok: true, value: message };
|
|
89023
89878
|
}
|
|
89024
89879
|
function rpcError2(error) {
|
|
89025
|
-
const message =
|
|
89026
|
-
const code =
|
|
89880
|
+
const message = isRecord10(error) && typeof error.message === "string" ? error.message : JSON.stringify(error);
|
|
89881
|
+
const code = isRecord10(error) && typeof error.code === "number" ? ` (code ${error.code})` : "";
|
|
89027
89882
|
return { title: "MCP error", detail: cutDetail(`${message}${code}`), status: void 0 };
|
|
89028
89883
|
}
|
|
89029
89884
|
async function initialize(session) {
|
|
@@ -89050,7 +89905,7 @@ async function initialize(session) {
|
|
|
89050
89905
|
if (!reply2.ok) return reply2;
|
|
89051
89906
|
if (Object.hasOwn(reply2.value, "error")) return { ok: false, error: rpcError2(reply2.value.error) };
|
|
89052
89907
|
const result2 = reply2.value.result;
|
|
89053
|
-
if (!
|
|
89908
|
+
if (!isRecord10(result2)) return invalidResponse("The MCP server's initialize result is not an object.", response.status);
|
|
89054
89909
|
const version2 = result2.protocolVersion;
|
|
89055
89910
|
session.protocol = typeof version2 === "string" && PROTOCOL_VERSION2.test(version2) ? version2 : MCP_PROTOCOL_VERSION2;
|
|
89056
89911
|
return { ok: true, value: void 0 };
|
|
@@ -89252,8 +90107,8 @@ function firstPosition(paging, args, options) {
|
|
|
89252
90107
|
if (paging.style === "offset") return 0;
|
|
89253
90108
|
const properties = options.inputSchema.properties;
|
|
89254
90109
|
const name = options.agentName(paging.input);
|
|
89255
|
-
const property =
|
|
89256
|
-
if (
|
|
90110
|
+
const property = isRecord10(properties) && Object.hasOwn(properties, name) ? properties[name] : void 0;
|
|
90111
|
+
if (isRecord10(property)) {
|
|
89257
90112
|
const fallback = wholeNumber(property.default) ?? wholeNumber(property.minimum);
|
|
89258
90113
|
if (fallback !== void 0) return fallback;
|
|
89259
90114
|
}
|
|
@@ -89351,11 +90206,11 @@ function errorText4(error) {
|
|
|
89351
90206
|
function asSentence(text4) {
|
|
89352
90207
|
return /[.!?…]$/.test(text4) ? text4 : `${text4}.`;
|
|
89353
90208
|
}
|
|
89354
|
-
function
|
|
90209
|
+
function plural4(count7, one, many) {
|
|
89355
90210
|
return `${count7} ${count7 === 1 ? one : many}`;
|
|
89356
90211
|
}
|
|
89357
90212
|
function pagingNote(paged, options) {
|
|
89358
|
-
const read2 = `${
|
|
90213
|
+
const read2 = `${plural4(paged.items, "item", "items")} from ${plural4(paged.pages, "page", "pages")}`;
|
|
89359
90214
|
switch (paged.stop) {
|
|
89360
90215
|
case "last_page":
|
|
89361
90216
|
return void 0;
|
|
@@ -89403,7 +90258,7 @@ function graphqlDocument(template, args) {
|
|
|
89403
90258
|
return { query, variables: Object.fromEntries(present.map((a) => [a.name, args[a.property]])) };
|
|
89404
90259
|
}
|
|
89405
90260
|
function errorMessages(errors) {
|
|
89406
|
-
return errors.map((entry2) =>
|
|
90261
|
+
return errors.map((entry2) => isRecord10(entry2) && typeof entry2.message === "string" ? entry2.message : JSON.stringify(entry2)).join("; ");
|
|
89407
90262
|
}
|
|
89408
90263
|
function invalidResponse2(detail, status2) {
|
|
89409
90264
|
return { ok: false, error: { title: "Invalid response", detail, status: status2 } };
|
|
@@ -89414,14 +90269,14 @@ function interpret(template) {
|
|
|
89414
90269
|
const status2 = response.status;
|
|
89415
90270
|
const parsed = bytes.byteLength === 0 ? void 0 : parseJson3(decodeText2(bytes));
|
|
89416
90271
|
const body2 = parsed?.ok === true ? parsed.value : void 0;
|
|
89417
|
-
if (
|
|
90272
|
+
if (isRecord10(body2) && isList(body2.errors) && body2.errors.length > 0) {
|
|
89418
90273
|
return { ok: false, error: { title: "GraphQL error", detail: cutDetail(errorMessages(body2.errors)), status: status2 } };
|
|
89419
90274
|
}
|
|
89420
90275
|
if (status2 < 200 || status2 >= 300) return { ok: false, error: upstreamError(response, bytes) };
|
|
89421
90276
|
if (parsed === void 0) return invalidResponse2(`The upstream answered ${status2} with no body.`, status2);
|
|
89422
90277
|
if (!parsed.ok) return invalidResponse2(`The upstream answered ${status2} with JSON that does not parse: ${parsed.message}`, status2);
|
|
89423
|
-
const data =
|
|
89424
|
-
if (!
|
|
90278
|
+
const data = isRecord10(body2) ? body2.data : void 0;
|
|
90279
|
+
if (!isRecord10(data)) return invalidResponse2(`The upstream answered ${status2} with no data object.`, status2);
|
|
89425
90280
|
if (!Object.hasOwn(data, field)) return invalidResponse2(`The response's data has no ${field} field.`, status2);
|
|
89426
90281
|
const value = data[field];
|
|
89427
90282
|
return { ok: true, value: isList(value) ? { items: value } : value };
|
|
@@ -107716,7 +108571,7 @@ function scalarText(value, name) {
|
|
|
107716
108571
|
}
|
|
107717
108572
|
function shapeOf(value, name) {
|
|
107718
108573
|
if (isList(value)) return { kind: "list", items: value.map((item) => scalarText(item, name)) };
|
|
107719
|
-
if (
|
|
108574
|
+
if (isRecord10(value)) {
|
|
107720
108575
|
return {
|
|
107721
108576
|
kind: "object",
|
|
107722
108577
|
entries: Object.entries(value).filter(([, item]) => item !== void 0).map(([key, item]) => [key, scalarText(item, name)])
|
|
@@ -107837,7 +108692,7 @@ function formText(value) {
|
|
|
107837
108692
|
throw invalidArguments(`A form body cannot carry a ${typeof value} value.`);
|
|
107838
108693
|
}
|
|
107839
108694
|
function formBody(value) {
|
|
107840
|
-
if (!
|
|
108695
|
+
if (!isRecord10(value)) throw invalidArguments("A form body takes an object.");
|
|
107841
108696
|
const form = new URLSearchParams();
|
|
107842
108697
|
for (const [key, item] of Object.entries(value)) {
|
|
107843
108698
|
const items = (isList(item) ? item : [item]).filter((one) => one !== void 0);
|
|
@@ -108065,7 +108920,7 @@ function project(value, at) {
|
|
|
108065
108920
|
const each = at.each;
|
|
108066
108921
|
return value.map((item) => project(item, each)).filter((item) => item !== ABSENT);
|
|
108067
108922
|
}
|
|
108068
|
-
if (
|
|
108923
|
+
if (isRecord10(value) && at.fields.size > 0) {
|
|
108069
108924
|
const kept = [];
|
|
108070
108925
|
for (const [name, child] of at.fields) {
|
|
108071
108926
|
if (!Object.hasOwn(value, name)) continue;
|
|
@@ -108082,7 +108937,7 @@ function remove(value, at) {
|
|
|
108082
108937
|
const each = at.each;
|
|
108083
108938
|
return value.map((item) => remove(item, each)).filter((item) => item !== ABSENT);
|
|
108084
108939
|
}
|
|
108085
|
-
if (
|
|
108940
|
+
if (isRecord10(value) && at.fields.size > 0) {
|
|
108086
108941
|
const kept = [];
|
|
108087
108942
|
for (const [name, item] of Object.entries(value)) {
|
|
108088
108943
|
const child = at.fields.get(name);
|
|
@@ -108118,10 +108973,10 @@ function shapeRecord(value, rules, isError) {
|
|
|
108118
108973
|
let out = value;
|
|
108119
108974
|
if (rules.select !== void 0 && !isError) out = project(out, rules.select);
|
|
108120
108975
|
if (rules.redact !== void 0) out = remove(out, rules.redact);
|
|
108121
|
-
return
|
|
108976
|
+
return isRecord10(out) ? out : {};
|
|
108122
108977
|
}
|
|
108123
108978
|
function shapeJson(value, rules) {
|
|
108124
|
-
return
|
|
108979
|
+
return isRecord10(value) ? shapeRecord(value, rules, false) : value;
|
|
108125
108980
|
}
|
|
108126
108981
|
function byteLength(text4) {
|
|
108127
108982
|
return encodeText(text4).byteLength;
|
|
@@ -108148,7 +109003,7 @@ function resultBytes(content, structured) {
|
|
|
108148
109003
|
}
|
|
108149
109004
|
function jsonResult(value, text4) {
|
|
108150
109005
|
const result2 = { content: [textItem(text4)] };
|
|
108151
|
-
if (
|
|
109006
|
+
if (isRecord10(value)) result2.structuredContent = value;
|
|
108152
109007
|
return result2;
|
|
108153
109008
|
}
|
|
108154
109009
|
function fitsCap(result2, rules) {
|
|
@@ -108203,7 +109058,7 @@ function shapeTextItem(item, rules, isError) {
|
|
|
108203
109058
|
const text4 = item.text;
|
|
108204
109059
|
if (typeof text4 !== "string") return item;
|
|
108205
109060
|
const parsed = parseJson3(text4);
|
|
108206
|
-
if (!parsed.ok || !
|
|
109061
|
+
if (!parsed.ok || !isRecord10(parsed.value)) return item;
|
|
108207
109062
|
return { ...item, text: JSON.stringify(shapeRecord(parsed.value, rules, isError)) };
|
|
108208
109063
|
}
|
|
108209
109064
|
function shapeToolResult(result2, rules, notes) {
|
|
@@ -108268,7 +109123,7 @@ function hasType(type, value) {
|
|
|
108268
109123
|
case "boolean":
|
|
108269
109124
|
return typeof value === "boolean";
|
|
108270
109125
|
case "object":
|
|
108271
|
-
return
|
|
109126
|
+
return isRecord10(value);
|
|
108272
109127
|
case "array":
|
|
108273
109128
|
return isList(value);
|
|
108274
109129
|
default:
|
|
@@ -108279,10 +109134,10 @@ function checkString(schema, value, path2) {
|
|
|
108279
109134
|
const issues = [];
|
|
108280
109135
|
const length = [...value].length;
|
|
108281
109136
|
if (typeof schema.minLength === "number" && length < schema.minLength) {
|
|
108282
|
-
issues.push(`${path2} must be at least ${schema.minLength} ${
|
|
109137
|
+
issues.push(`${path2} must be at least ${schema.minLength} ${plural5(schema.minLength, "character")} long.`);
|
|
108283
109138
|
}
|
|
108284
109139
|
if (typeof schema.maxLength === "number" && length > schema.maxLength) {
|
|
108285
|
-
issues.push(`${path2} must be at most ${schema.maxLength} ${
|
|
109140
|
+
issues.push(`${path2} must be at most ${schema.maxLength} ${plural5(schema.maxLength, "character")} long.`);
|
|
108286
109141
|
}
|
|
108287
109142
|
if (typeof schema.pattern === "string" && testPattern(schema.pattern, value) === false) {
|
|
108288
109143
|
issues.push(`${path2} must match the pattern ${schema.pattern}.`);
|
|
@@ -108340,7 +109195,7 @@ function resolveRef(root, ref2) {
|
|
|
108340
109195
|
const index = Number(token);
|
|
108341
109196
|
if (!Number.isInteger(index) || index < 0 || index >= current.length) return void 0;
|
|
108342
109197
|
current = current[index];
|
|
108343
|
-
} else if (
|
|
109198
|
+
} else if (isRecord10(current) && Object.hasOwn(current, token)) {
|
|
108344
109199
|
current = current[token];
|
|
108345
109200
|
} else {
|
|
108346
109201
|
return void 0;
|
|
@@ -108350,7 +109205,7 @@ function resolveRef(root, ref2) {
|
|
|
108350
109205
|
}
|
|
108351
109206
|
function canonical2(value) {
|
|
108352
109207
|
if (isList(value)) return `[${value.map(canonical2).join(",")}]`;
|
|
108353
|
-
if (
|
|
109208
|
+
if (isRecord10(value)) {
|
|
108354
109209
|
const keys = Object.keys(value).sort();
|
|
108355
109210
|
return `{${keys.map((key) => `${JSON.stringify(key)}:${canonical2(value[key])}`).join(",")}}`;
|
|
108356
109211
|
}
|
|
@@ -108364,7 +109219,7 @@ function listOf(values) {
|
|
|
108364
109219
|
const more = values.length - shown2.length;
|
|
108365
109220
|
return more > 0 ? `${shown2.join(", ")}, and ${more} more` : shown2.join(", ");
|
|
108366
109221
|
}
|
|
108367
|
-
function
|
|
109222
|
+
function plural5(count7, one, many = `${one}s`) {
|
|
108368
109223
|
return count7 === 1 ? one : many;
|
|
108369
109224
|
}
|
|
108370
109225
|
var MAX_DEPTH2, MAX_STEPS, MAX_ISSUES, TYPE_NAMES, Checker;
|
|
@@ -108394,7 +109249,7 @@ var init_validate = __esm({
|
|
|
108394
109249
|
this.steps += 1;
|
|
108395
109250
|
if (depth > MAX_DEPTH2 || this.steps > MAX_STEPS) return [];
|
|
108396
109251
|
if (schema === false) return [`${path2} is not allowed.`];
|
|
108397
|
-
if (!
|
|
109252
|
+
if (!isRecord10(schema)) return [];
|
|
108398
109253
|
if (value === null && schema.nullable === true) return [];
|
|
108399
109254
|
const issues = [];
|
|
108400
109255
|
if (typeof schema.$ref === "string") {
|
|
@@ -108412,7 +109267,7 @@ var init_validate = __esm({
|
|
|
108412
109267
|
if (typeof value === "string") issues.push(...checkString(schema, value, path2));
|
|
108413
109268
|
else if (typeof value === "number") issues.push(...checkNumber(schema, value, path2));
|
|
108414
109269
|
else if (isList(value)) issues.push(...this.checkArray(schema, value, path2, depth));
|
|
108415
|
-
else if (
|
|
109270
|
+
else if (isRecord10(value)) issues.push(...this.checkObject(schema, value, path2, depth));
|
|
108416
109271
|
issues.push(...this.checkCombinators(schema, value, path2, depth));
|
|
108417
109272
|
return issues;
|
|
108418
109273
|
}
|
|
@@ -108422,10 +109277,10 @@ var init_validate = __esm({
|
|
|
108422
109277
|
checkArray(schema, value, path2, depth) {
|
|
108423
109278
|
const issues = [];
|
|
108424
109279
|
if (typeof schema.minItems === "number" && value.length < schema.minItems) {
|
|
108425
|
-
issues.push(`${path2} must have at least ${schema.minItems} ${
|
|
109280
|
+
issues.push(`${path2} must have at least ${schema.minItems} ${plural5(schema.minItems, "item")}.`);
|
|
108426
109281
|
}
|
|
108427
109282
|
if (typeof schema.maxItems === "number" && value.length > schema.maxItems) {
|
|
108428
|
-
issues.push(`${path2} must have at most ${schema.maxItems} ${
|
|
109283
|
+
issues.push(`${path2} must have at most ${schema.maxItems} ${plural5(schema.maxItems, "item")}.`);
|
|
108429
109284
|
}
|
|
108430
109285
|
if (schema.uniqueItems === true) {
|
|
108431
109286
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -108457,13 +109312,13 @@ var init_validate = __esm({
|
|
|
108457
109312
|
}
|
|
108458
109313
|
}
|
|
108459
109314
|
if (typeof schema.minProperties === "number" && present.length < schema.minProperties) {
|
|
108460
|
-
issues.push(`${path2} must have at least ${schema.minProperties} ${
|
|
109315
|
+
issues.push(`${path2} must have at least ${schema.minProperties} ${plural5(schema.minProperties, "property", "properties")}.`);
|
|
108461
109316
|
}
|
|
108462
109317
|
if (typeof schema.maxProperties === "number" && present.length > schema.maxProperties) {
|
|
108463
|
-
issues.push(`${path2} must have at most ${schema.maxProperties} ${
|
|
109318
|
+
issues.push(`${path2} must have at most ${schema.maxProperties} ${plural5(schema.maxProperties, "property", "properties")}.`);
|
|
108464
109319
|
}
|
|
108465
|
-
const properties =
|
|
108466
|
-
const patterns =
|
|
109320
|
+
const properties = isRecord10(schema.properties) ? schema.properties : {};
|
|
109321
|
+
const patterns = isRecord10(schema.patternProperties) ? Object.entries(schema.patternProperties) : [];
|
|
108467
109322
|
for (const key of present) {
|
|
108468
109323
|
const at = propertyPath(path2, key);
|
|
108469
109324
|
let known = false;
|
|
@@ -108743,7 +109598,7 @@ function differenceAt(path2, expected, actual) {
|
|
|
108743
109598
|
if (expected.length === actual.length) return void 0;
|
|
108744
109599
|
return { path: `${path2}[${shared}]`, expected: expected[shared], actual: actual[shared] };
|
|
108745
109600
|
}
|
|
108746
|
-
if (
|
|
109601
|
+
if (isRecord10(expected) && isRecord10(actual)) {
|
|
108747
109602
|
for (const key of Object.keys(expected)) {
|
|
108748
109603
|
const found = differenceAt(keyPath(path2, key), expected[key], Object.hasOwn(actual, key) ? actual[key] : void 0);
|
|
108749
109604
|
if (found !== void 0) return found;
|
|
@@ -108821,7 +109676,7 @@ function rpcMessage(request3) {
|
|
|
108821
109676
|
const parsed = parseJson3(decodeText2(request3.body));
|
|
108822
109677
|
if (!parsed.ok) return void 0;
|
|
108823
109678
|
const value = isList(parsed.value) ? parsed.value[0] : parsed.value;
|
|
108824
|
-
return
|
|
109679
|
+
return isRecord10(value) ? value : void 0;
|
|
108825
109680
|
}
|
|
108826
109681
|
function replayTransport(exchanges, route) {
|
|
108827
109682
|
let next = 0;
|
|
@@ -109530,7 +110385,7 @@ import {
|
|
|
109530
110385
|
readlinkSync as readlinkSync3,
|
|
109531
110386
|
statSync as statSync11
|
|
109532
110387
|
} from "node:fs";
|
|
109533
|
-
import { dirname as dirname27, isAbsolute as
|
|
110388
|
+
import { dirname as dirname27, isAbsolute as isAbsolute13, join as join48, relative as relative8, resolve as resolve18, sep as sep7 } from "node:path";
|
|
109534
110389
|
function git5(cwd, args, input) {
|
|
109535
110390
|
try {
|
|
109536
110391
|
return execFileSync2("git", args, {
|
|
@@ -109557,7 +110412,7 @@ function commitOf(root, ref2) {
|
|
|
109557
110412
|
return sha.length > 0 ? sha : null;
|
|
109558
110413
|
}
|
|
109559
110414
|
function readWorkingFile(root, path2) {
|
|
109560
|
-
const abs =
|
|
110415
|
+
const abs = join48(root, ...path2.split("/"));
|
|
109561
110416
|
try {
|
|
109562
110417
|
const stat5 = lstatSync10(abs);
|
|
109563
110418
|
if (stat5.isSymbolicLink()) return readlinkSync3(abs, "utf8");
|
|
@@ -109651,7 +110506,7 @@ function isDir(path2) {
|
|
|
109651
110506
|
function findSteeringRoot(start) {
|
|
109652
110507
|
let dir = resolve18(start);
|
|
109653
110508
|
for (; ; ) {
|
|
109654
|
-
if (isFile(
|
|
110509
|
+
if (isFile(join48(dir, WORKSPACE_TOML_PATH)) || isFile(join48(dir, AGENTS_MD_PATH)) && isDir(join48(dir, STEERING_DIR))) {
|
|
109655
110510
|
return dir;
|
|
109656
110511
|
}
|
|
109657
110512
|
const parent = dirname27(dir);
|
|
@@ -109665,8 +110520,8 @@ function within3(path2, scope) {
|
|
|
109665
110520
|
function scopesFor(root, cwd, paths, trees) {
|
|
109666
110521
|
const scopes = [];
|
|
109667
110522
|
for (const path2 of paths) {
|
|
109668
|
-
const rel =
|
|
109669
|
-
if (rel === ".." || rel.startsWith(`..${sep7}`) ||
|
|
110523
|
+
const rel = relative8(root, resolve18(cwd, path2));
|
|
110524
|
+
if (rel === ".." || rel.startsWith(`..${sep7}`) || isAbsolute13(rel)) {
|
|
109670
110525
|
return { error: `${path2} is outside the steering repo at ${root}.` };
|
|
109671
110526
|
}
|
|
109672
110527
|
const scope = rel.split(sep7).join("/");
|
|
@@ -109731,7 +110586,7 @@ function cacheFile(cacheDir, root) {
|
|
|
109731
110586
|
key: token === void 0 ? null : createHash20("sha256").update(token).digest("hex").slice(0, 16)
|
|
109732
110587
|
};
|
|
109733
110588
|
const key = createHash20("sha256").update(JSON.stringify([root, identity])).digest("hex").slice(0, 32);
|
|
109734
|
-
return
|
|
110589
|
+
return join48(cacheDir, `${key}.json`);
|
|
109735
110590
|
}
|
|
109736
110591
|
function readCache(file, now) {
|
|
109737
110592
|
let entry2;
|
|
@@ -109830,7 +110685,7 @@ async function fetchSteeringIndex(root) {
|
|
|
109830
110685
|
function defaultDeps2() {
|
|
109831
110686
|
return {
|
|
109832
110687
|
fetchPublished: fetchSteeringIndex,
|
|
109833
|
-
cacheDir:
|
|
110688
|
+
cacheDir: join48(getConfigDir(), "cache", "steering-check"),
|
|
109834
110689
|
now: () => Date.now()
|
|
109835
110690
|
};
|
|
109836
110691
|
}
|
|
@@ -112086,7 +112941,7 @@ function buildProgram() {
|
|
|
112086
112941
|
}
|
|
112087
112942
|
);
|
|
112088
112943
|
const steeringCmd = program2.command("steering").description(
|
|
112089
|
-
"Steering records: whether .oxagen/ carries the ones merged on the production branch, and
|
|
112944
|
+
"Steering records: whether .oxagen/ carries the ones merged on the production branch, Markdown import, and instruction file findings"
|
|
112090
112945
|
);
|
|
112091
112946
|
steeringCmd.command("status").description(
|
|
112092
112947
|
"Compare .oxagen/ against the remote production branch and show the two gates"
|
|
@@ -112142,6 +112997,26 @@ function buildProgram() {
|
|
|
112142
112997
|
await handleSteeringImport2(paths, opts);
|
|
112143
112998
|
}
|
|
112144
112999
|
);
|
|
113000
|
+
steeringCmd.command("findings").description(
|
|
113001
|
+
"List the statements in linked repositories' instruction files that repeat or contradict a steering record"
|
|
113002
|
+
).option("--json", "Output JSON").action(async (opts) => {
|
|
113003
|
+
const { steeringFindings: steeringFindings2 } = await Promise.resolve().then(() => (init_steering_findings(), steering_findings_exports));
|
|
113004
|
+
await steeringFindings2(opts);
|
|
113005
|
+
});
|
|
113006
|
+
steeringCmd.command("promote").argument("<finding-id>", "The crf_\u2026 id `oxagen steering findings` shows").description(
|
|
113007
|
+
"Propose a new version of the record a statement contradicts, with the statement as its text, and open its steering PR"
|
|
113008
|
+
).option("--json", "Output JSON").action(async (findingId, opts) => {
|
|
113009
|
+
const { steeringPromote: steeringPromote2 } = await Promise.resolve().then(() => (init_steering_promote(), steering_promote_exports));
|
|
113010
|
+
await steeringPromote2(findingId, opts);
|
|
113011
|
+
});
|
|
113012
|
+
steeringCmd.command("restore-block").argument("<proposal-id>", "The prp_\u2026 proposal whose steering PR holds the file").argument("<path>", "AGENTS.md, CLAUDE.md, or README.md").description(
|
|
113013
|
+
"Restore Oxagen's managed block in one file of an open steering PR, as one commit from the production branch"
|
|
113014
|
+
).option("--json", "Output JSON").action(
|
|
113015
|
+
async (proposalId, path2, opts) => {
|
|
113016
|
+
const { steeringRestoreBlock: steeringRestoreBlock2 } = await Promise.resolve().then(() => (init_steering_restore_block(), steering_restore_block_exports));
|
|
113017
|
+
await steeringRestoreBlock2(proposalId, path2, opts);
|
|
113018
|
+
}
|
|
113019
|
+
);
|
|
112145
113020
|
const toolsCmd = program2.command("tools").description("The workspace's connected MCP servers and their tools");
|
|
112146
113021
|
toolsCmd.command("migrate").description(
|
|
112147
113022
|
"Open the pull request that moves the workspace's MCP servers into its steering repo, or print the one already open"
|
|
@@ -112156,7 +113031,7 @@ function buildProgram() {
|
|
|
112156
113031
|
"The repository root to mount at /workspace (default: the current directory)"
|
|
112157
113032
|
).option(
|
|
112158
113033
|
"--github-repository <owner/name>",
|
|
112159
|
-
"The one repository the run may
|
|
113034
|
+
"The one repository the run may fetch and push, through Oxagen's Git custody. The workspace must have it bound."
|
|
112160
113035
|
).argument("[command...]", "After --: claude or codex, then its arguments").action(
|
|
112161
113036
|
async (command2, opts) => {
|
|
112162
113037
|
if (command2.length === 0) {
|
|
@@ -112724,7 +113599,7 @@ function buildProgram() {
|
|
|
112724
113599
|
"With --contained: the repository root to mount at /workspace (default: the current directory)"
|
|
112725
113600
|
).option(
|
|
112726
113601
|
"--github-repository <owner/name>",
|
|
112727
|
-
"With --contained: the one repository the run may
|
|
113602
|
+
"With --contained: the one repository the run may fetch and push, through Oxagen's Git custody. The workspace must have it bound."
|
|
112728
113603
|
).argument("[command...]", "After --: the agent's command and its arguments").action(
|
|
112729
113604
|
async (command2, opts) => {
|
|
112730
113605
|
const { handleAgentRun: handleAgentRun2 } = await Promise.resolve().then(() => (init_tacho(), tacho_exports));
|