@posthog/agent 2.3.657 → 2.3.663
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.js +7 -2
- package/dist/agent.js.map +1 -1
- package/dist/posthog-api.js +1 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.d.ts +4 -0
- package/dist/server/agent-server.js +712 -4
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +720 -7
- package/dist/server/bin.cjs.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/codex/spawn.ts +9 -0
- package/src/agent.ts +1 -0
- package/src/server/agent-server.test.ts +241 -0
- package/src/server/agent-server.ts +55 -3
- package/src/server/bin.ts +12 -0
- package/src/server/event-stream-sender.test.ts +74 -0
- package/src/server/event-stream-sender.ts +101 -52
- package/src/server/streaming-upload.ts +160 -0
- package/src/server/types.ts +2 -0
- package/src/types.ts +2 -0
package/dist/server/bin.cjs
CHANGED
|
@@ -4590,7 +4590,7 @@ function isSupportedReasoningEffort(adapter, modelId, value) {
|
|
|
4590
4590
|
// src/server/agent-server.ts
|
|
4591
4591
|
var import_promises6 = require("fs/promises");
|
|
4592
4592
|
var import_node_path9 = require("path");
|
|
4593
|
-
var
|
|
4593
|
+
var import_node_url3 = require("url");
|
|
4594
4594
|
var import_sdk5 = require("@agentclientprotocol/sdk");
|
|
4595
4595
|
var import_node_server = require("@hono/node-server");
|
|
4596
4596
|
|
|
@@ -9471,7 +9471,7 @@ var import_zod4 = require("zod");
|
|
|
9471
9471
|
// package.json
|
|
9472
9472
|
var package_default = {
|
|
9473
9473
|
name: "@posthog/agent",
|
|
9474
|
-
version: "2.3.
|
|
9474
|
+
version: "2.3.663",
|
|
9475
9475
|
repository: "https://github.com/PostHog/code",
|
|
9476
9476
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
9477
9477
|
exports: {
|
|
@@ -19503,6 +19503,10 @@ function buildConfigArgs(options) {
|
|
|
19503
19503
|
if (options.reasoningEffort) {
|
|
19504
19504
|
args2.push("-c", `model_reasoning_effort="${options.reasoningEffort}"`);
|
|
19505
19505
|
}
|
|
19506
|
+
if (options.additionalDirectories?.length) {
|
|
19507
|
+
const escaped = options.additionalDirectories.map((p) => `"${p.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`).join(",");
|
|
19508
|
+
args2.push("-c", `sandbox_workspace_write.writable_roots=[${escaped}]`);
|
|
19509
|
+
}
|
|
19506
19510
|
if (options.instructions) {
|
|
19507
19511
|
const escaped = options.instructions.replace(/\\/g, "\\\\").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/"/g, '\\"');
|
|
19508
19512
|
args2.push("-c", `instructions="${escaped}"`);
|
|
@@ -22454,6 +22458,669 @@ function normalizeCloudPromptContent(content) {
|
|
|
22454
22458
|
return content;
|
|
22455
22459
|
}
|
|
22456
22460
|
|
|
22461
|
+
// src/server/event-stream-sender.ts
|
|
22462
|
+
var import_node_buffer3 = require("buffer");
|
|
22463
|
+
|
|
22464
|
+
// src/server/streaming-upload.ts
|
|
22465
|
+
var import_node_buffer2 = require("buffer");
|
|
22466
|
+
var import_node_http = require("http");
|
|
22467
|
+
var import_node_https = require("https");
|
|
22468
|
+
var import_node_url2 = require("url");
|
|
22469
|
+
function headersFromIncoming(headers) {
|
|
22470
|
+
const result = new Headers();
|
|
22471
|
+
for (const [name2, value] of Object.entries(headers)) {
|
|
22472
|
+
if (value === void 0) {
|
|
22473
|
+
continue;
|
|
22474
|
+
}
|
|
22475
|
+
if (Array.isArray(value)) {
|
|
22476
|
+
for (const item of value) {
|
|
22477
|
+
result.append(name2, item);
|
|
22478
|
+
}
|
|
22479
|
+
} else {
|
|
22480
|
+
result.set(name2, String(value));
|
|
22481
|
+
}
|
|
22482
|
+
}
|
|
22483
|
+
return result;
|
|
22484
|
+
}
|
|
22485
|
+
function abortError() {
|
|
22486
|
+
const error = new Error("aborted");
|
|
22487
|
+
error.name = "AbortError";
|
|
22488
|
+
return error;
|
|
22489
|
+
}
|
|
22490
|
+
function writeRequestChunk(request, chunk) {
|
|
22491
|
+
return new Promise((resolve8, reject) => {
|
|
22492
|
+
const onError2 = (error) => {
|
|
22493
|
+
request.off("error", onError2);
|
|
22494
|
+
reject(error);
|
|
22495
|
+
};
|
|
22496
|
+
request.once("error", onError2);
|
|
22497
|
+
request.write(import_node_buffer2.Buffer.from(chunk), (error) => {
|
|
22498
|
+
request.off("error", onError2);
|
|
22499
|
+
if (error) {
|
|
22500
|
+
reject(error);
|
|
22501
|
+
return;
|
|
22502
|
+
}
|
|
22503
|
+
resolve8();
|
|
22504
|
+
});
|
|
22505
|
+
});
|
|
22506
|
+
}
|
|
22507
|
+
function closeRequest(request) {
|
|
22508
|
+
return new Promise((resolve8, reject) => {
|
|
22509
|
+
const onError2 = (error) => {
|
|
22510
|
+
request.off("error", onError2);
|
|
22511
|
+
reject(error);
|
|
22512
|
+
};
|
|
22513
|
+
request.once("error", onError2);
|
|
22514
|
+
request.end(() => {
|
|
22515
|
+
request.off("error", onError2);
|
|
22516
|
+
resolve8();
|
|
22517
|
+
});
|
|
22518
|
+
});
|
|
22519
|
+
}
|
|
22520
|
+
function createNodeStreamingUpload({
|
|
22521
|
+
url,
|
|
22522
|
+
headers,
|
|
22523
|
+
abortController
|
|
22524
|
+
}) {
|
|
22525
|
+
const parsedUrl = new import_node_url2.URL(url);
|
|
22526
|
+
const requestFactory = parsedUrl.protocol === "https:" ? import_node_https.request : parsedUrl.protocol === "http:" ? import_node_http.request : void 0;
|
|
22527
|
+
if (!requestFactory) {
|
|
22528
|
+
throw new Error(`Unsupported event ingest protocol: ${parsedUrl.protocol}`);
|
|
22529
|
+
}
|
|
22530
|
+
const request = requestFactory(parsedUrl, {
|
|
22531
|
+
method: "POST",
|
|
22532
|
+
headers
|
|
22533
|
+
});
|
|
22534
|
+
let closed = false;
|
|
22535
|
+
const responsePromise = new Promise((resolve8, reject) => {
|
|
22536
|
+
request.on("response", (response) => {
|
|
22537
|
+
const chunks = [];
|
|
22538
|
+
response.on("data", (chunk) => {
|
|
22539
|
+
chunks.push(import_node_buffer2.Buffer.isBuffer(chunk) ? chunk : import_node_buffer2.Buffer.from(chunk));
|
|
22540
|
+
});
|
|
22541
|
+
response.on("end", () => {
|
|
22542
|
+
resolve8(
|
|
22543
|
+
new Response(import_node_buffer2.Buffer.concat(chunks), {
|
|
22544
|
+
status: response.statusCode ?? 0,
|
|
22545
|
+
statusText: response.statusMessage,
|
|
22546
|
+
headers: headersFromIncoming(response.headers)
|
|
22547
|
+
})
|
|
22548
|
+
);
|
|
22549
|
+
});
|
|
22550
|
+
response.on("error", reject);
|
|
22551
|
+
});
|
|
22552
|
+
request.on("error", reject);
|
|
22553
|
+
});
|
|
22554
|
+
const abortRequest = () => {
|
|
22555
|
+
closed = true;
|
|
22556
|
+
if (!request.destroyed) {
|
|
22557
|
+
request.destroy(abortError());
|
|
22558
|
+
}
|
|
22559
|
+
};
|
|
22560
|
+
abortController.signal.addEventListener("abort", abortRequest, {
|
|
22561
|
+
once: true
|
|
22562
|
+
});
|
|
22563
|
+
void responsePromise.finally(() => {
|
|
22564
|
+
abortController.signal.removeEventListener("abort", abortRequest);
|
|
22565
|
+
}).catch(() => void 0);
|
|
22566
|
+
return {
|
|
22567
|
+
async write(chunk) {
|
|
22568
|
+
if (closed) {
|
|
22569
|
+
throw new Error("Cannot write to closed event ingest stream");
|
|
22570
|
+
}
|
|
22571
|
+
await writeRequestChunk(request, chunk);
|
|
22572
|
+
},
|
|
22573
|
+
async close() {
|
|
22574
|
+
if (closed) {
|
|
22575
|
+
return;
|
|
22576
|
+
}
|
|
22577
|
+
closed = true;
|
|
22578
|
+
await closeRequest(request);
|
|
22579
|
+
},
|
|
22580
|
+
async abort() {
|
|
22581
|
+
abortRequest();
|
|
22582
|
+
},
|
|
22583
|
+
responsePromise
|
|
22584
|
+
};
|
|
22585
|
+
}
|
|
22586
|
+
|
|
22587
|
+
// src/server/event-stream-sender.ts
|
|
22588
|
+
var DEFAULT_MAX_BUFFERED_EVENTS = 2e4;
|
|
22589
|
+
var DEFAULT_MAX_STREAM_EVENTS = 900;
|
|
22590
|
+
var DEFAULT_MAX_STREAM_BYTES = 4e6;
|
|
22591
|
+
var DEFAULT_MAX_EVENT_BYTES = 9e5;
|
|
22592
|
+
var DEFAULT_FLUSH_DELAY_MS = 0;
|
|
22593
|
+
var DEFAULT_RETRY_DELAY_MS = 1e3;
|
|
22594
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 1e4;
|
|
22595
|
+
var DEFAULT_STOP_TIMEOUT_MS = 3e4;
|
|
22596
|
+
var DEFAULT_STREAM_WINDOW_MS = 5 * 60 * 1e3;
|
|
22597
|
+
var STREAM_COMPLETE_CONTROL_TYPE = "_posthog/stream_complete";
|
|
22598
|
+
var TaskRunEventStreamSender = class {
|
|
22599
|
+
constructor(config) {
|
|
22600
|
+
this.config = config;
|
|
22601
|
+
const apiUrl = config.apiUrl.replace(/\/$/, "");
|
|
22602
|
+
this.ingestUrl = `${apiUrl}/api/projects/${config.projectId}/tasks/${encodeURIComponent(
|
|
22603
|
+
config.taskId
|
|
22604
|
+
)}/runs/${encodeURIComponent(config.runId)}/event_stream/`;
|
|
22605
|
+
this.maxBufferedEvents = config.maxBufferedEvents ?? DEFAULT_MAX_BUFFERED_EVENTS;
|
|
22606
|
+
this.maxStreamEvents = config.maxStreamEvents ?? DEFAULT_MAX_STREAM_EVENTS;
|
|
22607
|
+
this.maxStreamBytes = config.maxStreamBytes ?? DEFAULT_MAX_STREAM_BYTES;
|
|
22608
|
+
this.maxEventBytes = config.maxEventBytes ?? DEFAULT_MAX_EVENT_BYTES;
|
|
22609
|
+
this.flushDelayMs = config.flushDelayMs ?? DEFAULT_FLUSH_DELAY_MS;
|
|
22610
|
+
this.retryDelayMs = config.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
|
|
22611
|
+
this.requestTimeoutMs = config.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
22612
|
+
this.stopTimeoutMs = config.stopTimeoutMs ?? DEFAULT_STOP_TIMEOUT_MS;
|
|
22613
|
+
this.streamWindowMs = config.streamWindowMs ?? DEFAULT_STREAM_WINDOW_MS;
|
|
22614
|
+
this.createStreamingUpload = config.createStreamingUpload ?? createNodeStreamingUpload;
|
|
22615
|
+
}
|
|
22616
|
+
ingestUrl;
|
|
22617
|
+
maxBufferedEvents;
|
|
22618
|
+
maxStreamEvents;
|
|
22619
|
+
maxStreamBytes;
|
|
22620
|
+
maxEventBytes;
|
|
22621
|
+
flushDelayMs;
|
|
22622
|
+
retryDelayMs;
|
|
22623
|
+
requestTimeoutMs;
|
|
22624
|
+
stopTimeoutMs;
|
|
22625
|
+
streamWindowMs;
|
|
22626
|
+
createStreamingUpload;
|
|
22627
|
+
encoder = new TextEncoder();
|
|
22628
|
+
sequence = 0;
|
|
22629
|
+
lastKnownAcceptedSeq = 0;
|
|
22630
|
+
bufferedEvents = [];
|
|
22631
|
+
flushTimer = null;
|
|
22632
|
+
flushPromise = null;
|
|
22633
|
+
streamClosePromise = null;
|
|
22634
|
+
activeStream = null;
|
|
22635
|
+
stopPromise = null;
|
|
22636
|
+
stopped = false;
|
|
22637
|
+
sequenceSynced = false;
|
|
22638
|
+
sequenceInitialized = false;
|
|
22639
|
+
transportCompleted = false;
|
|
22640
|
+
droppedBeforeSequenceCount = 0;
|
|
22641
|
+
bufferRevision = 0;
|
|
22642
|
+
enqueue(event) {
|
|
22643
|
+
if (this.stopped) return;
|
|
22644
|
+
if (!this.canAcceptEvent(event)) {
|
|
22645
|
+
return;
|
|
22646
|
+
}
|
|
22647
|
+
const envelope = {
|
|
22648
|
+
seq: ++this.sequence,
|
|
22649
|
+
event
|
|
22650
|
+
};
|
|
22651
|
+
this.bufferedEvents.push(envelope);
|
|
22652
|
+
this.scheduleFlush();
|
|
22653
|
+
}
|
|
22654
|
+
async stop() {
|
|
22655
|
+
if (this.stopPromise) {
|
|
22656
|
+
await this.stopPromise;
|
|
22657
|
+
return;
|
|
22658
|
+
}
|
|
22659
|
+
this.stopped = true;
|
|
22660
|
+
if (this.flushTimer) {
|
|
22661
|
+
clearTimeout(this.flushTimer);
|
|
22662
|
+
this.flushTimer = null;
|
|
22663
|
+
}
|
|
22664
|
+
this.stopPromise = this.drainForStop();
|
|
22665
|
+
await this.stopPromise;
|
|
22666
|
+
}
|
|
22667
|
+
scheduleFlush(delayMs = this.flushDelayMs) {
|
|
22668
|
+
if (this.flushTimer || this.flushPromise || this.stopped) return;
|
|
22669
|
+
this.flushTimer = setTimeout(() => {
|
|
22670
|
+
this.flushTimer = null;
|
|
22671
|
+
void this.flush();
|
|
22672
|
+
}, delayMs);
|
|
22673
|
+
}
|
|
22674
|
+
async drainForStop() {
|
|
22675
|
+
const startedAtMs = Date.now();
|
|
22676
|
+
const deadlineAtMs = startedAtMs + this.stopTimeoutMs;
|
|
22677
|
+
while (!this.transportCompleted) {
|
|
22678
|
+
const previousLength = this.bufferedEvents.length;
|
|
22679
|
+
const previousRevision = this.bufferRevision;
|
|
22680
|
+
try {
|
|
22681
|
+
await this.flush();
|
|
22682
|
+
await this.writeCompletionLine();
|
|
22683
|
+
await this.closeActiveStream();
|
|
22684
|
+
this.transportCompleted = true;
|
|
22685
|
+
return;
|
|
22686
|
+
} catch (error) {
|
|
22687
|
+
this.config.logger.warn(
|
|
22688
|
+
"Task run event ingest stop request failed",
|
|
22689
|
+
this.describeError(error)
|
|
22690
|
+
);
|
|
22691
|
+
}
|
|
22692
|
+
const madeProgress = this.bufferedEvents.length < previousLength || this.bufferRevision !== previousRevision;
|
|
22693
|
+
if (!madeProgress && !await this.waitBeforeStopRetry(deadlineAtMs)) {
|
|
22694
|
+
this.warnStopDeadlineReached(startedAtMs);
|
|
22695
|
+
return;
|
|
22696
|
+
}
|
|
22697
|
+
if (Date.now() >= deadlineAtMs && !this.transportCompleted) {
|
|
22698
|
+
this.warnStopDeadlineReached(startedAtMs);
|
|
22699
|
+
return;
|
|
22700
|
+
}
|
|
22701
|
+
}
|
|
22702
|
+
}
|
|
22703
|
+
async flush() {
|
|
22704
|
+
if (this.flushPromise) {
|
|
22705
|
+
await this.flushPromise.catch(() => void 0);
|
|
22706
|
+
}
|
|
22707
|
+
if (this.bufferedEvents.length === 0) {
|
|
22708
|
+
return true;
|
|
22709
|
+
}
|
|
22710
|
+
const previousBufferLength = this.bufferedEvents.length;
|
|
22711
|
+
const flushPromise = this.flushBufferedEvents();
|
|
22712
|
+
this.flushPromise = flushPromise;
|
|
22713
|
+
try {
|
|
22714
|
+
await flushPromise;
|
|
22715
|
+
return this.bufferedEvents.length < previousBufferLength;
|
|
22716
|
+
} catch (error) {
|
|
22717
|
+
this.config.logger.warn(
|
|
22718
|
+
"Task run event ingest stream write failed",
|
|
22719
|
+
this.describeError(error)
|
|
22720
|
+
);
|
|
22721
|
+
await this.abortActiveStream();
|
|
22722
|
+
if (!this.stopped) {
|
|
22723
|
+
this.scheduleFlush(this.retryDelayMs);
|
|
22724
|
+
}
|
|
22725
|
+
return false;
|
|
22726
|
+
} finally {
|
|
22727
|
+
if (this.flushPromise === flushPromise) {
|
|
22728
|
+
this.flushPromise = null;
|
|
22729
|
+
}
|
|
22730
|
+
if (!this.stopped && this.hasUnwrittenBufferedEvents()) {
|
|
22731
|
+
this.scheduleFlush(0);
|
|
22732
|
+
}
|
|
22733
|
+
}
|
|
22734
|
+
}
|
|
22735
|
+
async flushBufferedEvents() {
|
|
22736
|
+
while (true) {
|
|
22737
|
+
const stream = await this.ensureActiveStream();
|
|
22738
|
+
const nextEvent = this.bufferedEvents.find(
|
|
22739
|
+
(event) => event.seq > stream.sentThroughSeq
|
|
22740
|
+
);
|
|
22741
|
+
if (!nextEvent) {
|
|
22742
|
+
return;
|
|
22743
|
+
}
|
|
22744
|
+
const line = `${this.serializeEnvelope(nextEvent)}
|
|
22745
|
+
`;
|
|
22746
|
+
const lineBytes = import_node_buffer3.Buffer.byteLength(line, "utf8");
|
|
22747
|
+
if (this.shouldRollStreamBeforeWriting(stream, lineBytes)) {
|
|
22748
|
+
await this.closeActiveStream();
|
|
22749
|
+
continue;
|
|
22750
|
+
}
|
|
22751
|
+
await stream.upload.write(this.encoder.encode(line));
|
|
22752
|
+
stream.sentThroughSeq = nextEvent.seq;
|
|
22753
|
+
stream.sentEvents += 1;
|
|
22754
|
+
stream.sentBytes += lineBytes;
|
|
22755
|
+
}
|
|
22756
|
+
}
|
|
22757
|
+
hasUnwrittenBufferedEvents() {
|
|
22758
|
+
const sentThroughSeq = this.activeStream?.sentThroughSeq ?? this.lastKnownAcceptedSeq;
|
|
22759
|
+
return this.bufferedEvents.some((event) => event.seq > sentThroughSeq);
|
|
22760
|
+
}
|
|
22761
|
+
async writeCompletionLine() {
|
|
22762
|
+
await this.syncSequenceWithServer();
|
|
22763
|
+
while (true) {
|
|
22764
|
+
const stream = await this.ensureActiveStream();
|
|
22765
|
+
const hasUnwrittenEvents = this.bufferedEvents.some(
|
|
22766
|
+
(event) => event.seq > stream.sentThroughSeq
|
|
22767
|
+
);
|
|
22768
|
+
if (hasUnwrittenEvents) {
|
|
22769
|
+
await this.flushBufferedEvents();
|
|
22770
|
+
continue;
|
|
22771
|
+
}
|
|
22772
|
+
const line = `${JSON.stringify({
|
|
22773
|
+
type: STREAM_COMPLETE_CONTROL_TYPE,
|
|
22774
|
+
final_seq: this.sequence
|
|
22775
|
+
})}
|
|
22776
|
+
`;
|
|
22777
|
+
const lineBytes = import_node_buffer3.Buffer.byteLength(line, "utf8");
|
|
22778
|
+
if (this.shouldRollStreamBeforeWriting(stream, lineBytes, {
|
|
22779
|
+
ignoreEventCount: true
|
|
22780
|
+
})) {
|
|
22781
|
+
await this.closeActiveStream();
|
|
22782
|
+
continue;
|
|
22783
|
+
}
|
|
22784
|
+
await stream.upload.write(this.encoder.encode(line));
|
|
22785
|
+
stream.sentBytes += lineBytes;
|
|
22786
|
+
return;
|
|
22787
|
+
}
|
|
22788
|
+
}
|
|
22789
|
+
shouldRollStreamBeforeWriting(stream, lineBytes, options = {}) {
|
|
22790
|
+
if (!options.ignoreEventCount && stream.sentEvents > 0 && stream.sentEvents >= this.maxStreamEvents) {
|
|
22791
|
+
return true;
|
|
22792
|
+
}
|
|
22793
|
+
if (stream.sentBytes > 0 && stream.sentBytes + lineBytes > this.maxStreamBytes) {
|
|
22794
|
+
return true;
|
|
22795
|
+
}
|
|
22796
|
+
return Date.now() - stream.startedAtMs >= this.streamWindowMs;
|
|
22797
|
+
}
|
|
22798
|
+
async ensureActiveStream() {
|
|
22799
|
+
if (this.streamClosePromise) {
|
|
22800
|
+
await this.streamClosePromise.catch(() => void 0);
|
|
22801
|
+
}
|
|
22802
|
+
if (this.activeStream) {
|
|
22803
|
+
return this.activeStream;
|
|
22804
|
+
}
|
|
22805
|
+
await this.syncSequenceWithServer();
|
|
22806
|
+
const abortController = new AbortController();
|
|
22807
|
+
const upload = this.createStreamingUpload({
|
|
22808
|
+
url: this.ingestUrl,
|
|
22809
|
+
headers: this.buildHeaders(),
|
|
22810
|
+
abortController
|
|
22811
|
+
});
|
|
22812
|
+
const activeStream = {
|
|
22813
|
+
abortController,
|
|
22814
|
+
upload,
|
|
22815
|
+
responsePromise: upload.responsePromise,
|
|
22816
|
+
startedAtMs: Date.now(),
|
|
22817
|
+
sentThroughSeq: this.lastKnownAcceptedSeq,
|
|
22818
|
+
sentEvents: 0,
|
|
22819
|
+
sentBytes: 0,
|
|
22820
|
+
windowTimer: null
|
|
22821
|
+
};
|
|
22822
|
+
this.activeStream = activeStream;
|
|
22823
|
+
this.scheduleStreamWindowClose(activeStream);
|
|
22824
|
+
upload.responsePromise.catch((error) => {
|
|
22825
|
+
void this.handleActiveStreamResponseFailure(activeStream, error);
|
|
22826
|
+
});
|
|
22827
|
+
return activeStream;
|
|
22828
|
+
}
|
|
22829
|
+
scheduleStreamWindowClose(stream, delayOverrideMs) {
|
|
22830
|
+
this.clearStreamWindowClose(stream);
|
|
22831
|
+
const delayMs = delayOverrideMs ?? Math.max(0, stream.startedAtMs + this.streamWindowMs - Date.now());
|
|
22832
|
+
stream.windowTimer = setTimeout(() => {
|
|
22833
|
+
stream.windowTimer = null;
|
|
22834
|
+
void this.closeExpiredStream(stream);
|
|
22835
|
+
}, delayMs);
|
|
22836
|
+
}
|
|
22837
|
+
clearStreamWindowClose(stream) {
|
|
22838
|
+
if (!stream.windowTimer) {
|
|
22839
|
+
return;
|
|
22840
|
+
}
|
|
22841
|
+
clearTimeout(stream.windowTimer);
|
|
22842
|
+
stream.windowTimer = null;
|
|
22843
|
+
}
|
|
22844
|
+
async closeExpiredStream(stream) {
|
|
22845
|
+
if (this.activeStream !== stream || this.stopped) {
|
|
22846
|
+
return;
|
|
22847
|
+
}
|
|
22848
|
+
if (this.flushPromise) {
|
|
22849
|
+
this.scheduleStreamWindowClose(stream, 50);
|
|
22850
|
+
return;
|
|
22851
|
+
}
|
|
22852
|
+
try {
|
|
22853
|
+
await this.closeActiveStream();
|
|
22854
|
+
} catch (error) {
|
|
22855
|
+
this.config.logger.warn(
|
|
22856
|
+
"Task run event ingest stream window close failed",
|
|
22857
|
+
this.describeError(error)
|
|
22858
|
+
);
|
|
22859
|
+
if (!this.stopped && this.bufferedEvents.length > 0) {
|
|
22860
|
+
this.scheduleFlush(this.retryDelayMs);
|
|
22861
|
+
}
|
|
22862
|
+
}
|
|
22863
|
+
}
|
|
22864
|
+
async handleActiveStreamResponseFailure(stream, error) {
|
|
22865
|
+
if (this.activeStream !== stream) {
|
|
22866
|
+
return;
|
|
22867
|
+
}
|
|
22868
|
+
this.config.logger.warn(
|
|
22869
|
+
"Task run event ingest stream request failed",
|
|
22870
|
+
this.describeError(error)
|
|
22871
|
+
);
|
|
22872
|
+
try {
|
|
22873
|
+
await this.abortActiveStream();
|
|
22874
|
+
} catch (abortError2) {
|
|
22875
|
+
this.config.logger.warn(
|
|
22876
|
+
"Task run event ingest stream abort failed",
|
|
22877
|
+
this.describeError(abortError2)
|
|
22878
|
+
);
|
|
22879
|
+
}
|
|
22880
|
+
if (!this.stopped && this.bufferedEvents.length > 0) {
|
|
22881
|
+
this.scheduleFlush(this.retryDelayMs);
|
|
22882
|
+
}
|
|
22883
|
+
}
|
|
22884
|
+
async closeActiveStream() {
|
|
22885
|
+
if (this.streamClosePromise) {
|
|
22886
|
+
await this.streamClosePromise;
|
|
22887
|
+
return;
|
|
22888
|
+
}
|
|
22889
|
+
const stream = this.activeStream;
|
|
22890
|
+
if (!stream) {
|
|
22891
|
+
return;
|
|
22892
|
+
}
|
|
22893
|
+
const closePromise = this.closeStream(stream);
|
|
22894
|
+
this.streamClosePromise = closePromise;
|
|
22895
|
+
try {
|
|
22896
|
+
await closePromise;
|
|
22897
|
+
} finally {
|
|
22898
|
+
this.clearStreamWindowClose(stream);
|
|
22899
|
+
if (this.activeStream === stream) {
|
|
22900
|
+
this.activeStream = null;
|
|
22901
|
+
}
|
|
22902
|
+
if (this.streamClosePromise === closePromise) {
|
|
22903
|
+
this.streamClosePromise = null;
|
|
22904
|
+
}
|
|
22905
|
+
}
|
|
22906
|
+
}
|
|
22907
|
+
async closeStream(stream) {
|
|
22908
|
+
try {
|
|
22909
|
+
await stream.upload.close();
|
|
22910
|
+
} catch (error) {
|
|
22911
|
+
stream.abortController.abort();
|
|
22912
|
+
this.sequenceSynced = false;
|
|
22913
|
+
throw error;
|
|
22914
|
+
}
|
|
22915
|
+
let response;
|
|
22916
|
+
try {
|
|
22917
|
+
response = await this.waitForResponseWithTimeout(
|
|
22918
|
+
stream.responsePromise,
|
|
22919
|
+
stream.abortController
|
|
22920
|
+
);
|
|
22921
|
+
} catch (error) {
|
|
22922
|
+
stream.abortController.abort();
|
|
22923
|
+
this.sequenceSynced = false;
|
|
22924
|
+
throw error;
|
|
22925
|
+
}
|
|
22926
|
+
await this.applyIngestResponse(response, "Event ingest stream");
|
|
22927
|
+
this.sequenceSynced = true;
|
|
22928
|
+
}
|
|
22929
|
+
async abortActiveStream() {
|
|
22930
|
+
const stream = this.activeStream;
|
|
22931
|
+
if (!stream) {
|
|
22932
|
+
return;
|
|
22933
|
+
}
|
|
22934
|
+
stream.abortController.abort();
|
|
22935
|
+
this.clearStreamWindowClose(stream);
|
|
22936
|
+
try {
|
|
22937
|
+
await stream.upload.abort();
|
|
22938
|
+
} catch {
|
|
22939
|
+
} finally {
|
|
22940
|
+
if (this.activeStream === stream) {
|
|
22941
|
+
this.activeStream = null;
|
|
22942
|
+
}
|
|
22943
|
+
this.sequenceSynced = false;
|
|
22944
|
+
}
|
|
22945
|
+
}
|
|
22946
|
+
async waitBeforeStopRetry(deadlineAtMs) {
|
|
22947
|
+
const remainingMs = deadlineAtMs - Date.now();
|
|
22948
|
+
if (remainingMs <= 0) {
|
|
22949
|
+
return false;
|
|
22950
|
+
}
|
|
22951
|
+
await new Promise(
|
|
22952
|
+
(resolve8) => setTimeout(resolve8, Math.min(this.retryDelayMs, remainingMs))
|
|
22953
|
+
);
|
|
22954
|
+
return Date.now() < deadlineAtMs;
|
|
22955
|
+
}
|
|
22956
|
+
warnStopDeadlineReached(startedAtMs) {
|
|
22957
|
+
this.config.logger.warn(
|
|
22958
|
+
"Task run event ingest stop deadline reached before fully completing transport",
|
|
22959
|
+
{
|
|
22960
|
+
remaining: this.bufferedEvents.length,
|
|
22961
|
+
stopTimeoutMs: this.stopTimeoutMs,
|
|
22962
|
+
elapsedMs: Date.now() - startedAtMs
|
|
22963
|
+
}
|
|
22964
|
+
);
|
|
22965
|
+
}
|
|
22966
|
+
async syncSequenceWithServer() {
|
|
22967
|
+
if (this.sequenceSynced) return;
|
|
22968
|
+
const response = await this.fetchWithTimeout({
|
|
22969
|
+
method: "POST",
|
|
22970
|
+
headers: this.buildHeaders(),
|
|
22971
|
+
body: ""
|
|
22972
|
+
});
|
|
22973
|
+
const responseBody = await this.parseResponse(response);
|
|
22974
|
+
if (!response.ok) {
|
|
22975
|
+
throw new Error(
|
|
22976
|
+
`Event ingest sequence sync returned HTTP ${response.status}: ${responseBody.text.slice(0, 300)}`
|
|
22977
|
+
);
|
|
22978
|
+
}
|
|
22979
|
+
const lastAcceptedSeq = responseBody.parsed?.last_accepted_seq;
|
|
22980
|
+
if (typeof lastAcceptedSeq === "number" && lastAcceptedSeq > 0) {
|
|
22981
|
+
if (!this.sequenceInitialized) {
|
|
22982
|
+
this.bufferedEvents = this.bufferedEvents.map((event) => ({
|
|
22983
|
+
...event,
|
|
22984
|
+
seq: event.seq + lastAcceptedSeq
|
|
22985
|
+
}));
|
|
22986
|
+
this.sequence += lastAcceptedSeq;
|
|
22987
|
+
this.bufferRevision += 1;
|
|
22988
|
+
} else {
|
|
22989
|
+
this.acceptThrough(lastAcceptedSeq);
|
|
22990
|
+
if (lastAcceptedSeq > this.sequence) {
|
|
22991
|
+
this.sequence = lastAcceptedSeq;
|
|
22992
|
+
}
|
|
22993
|
+
}
|
|
22994
|
+
this.lastKnownAcceptedSeq = lastAcceptedSeq;
|
|
22995
|
+
}
|
|
22996
|
+
this.sequenceSynced = true;
|
|
22997
|
+
this.sequenceInitialized = true;
|
|
22998
|
+
}
|
|
22999
|
+
async fetchWithTimeout(init2) {
|
|
23000
|
+
const abortController = new AbortController();
|
|
23001
|
+
const timeout = setTimeout(() => {
|
|
23002
|
+
abortController.abort();
|
|
23003
|
+
}, this.requestTimeoutMs);
|
|
23004
|
+
try {
|
|
23005
|
+
return await fetch(this.ingestUrl, {
|
|
23006
|
+
...init2,
|
|
23007
|
+
signal: abortController.signal
|
|
23008
|
+
});
|
|
23009
|
+
} finally {
|
|
23010
|
+
clearTimeout(timeout);
|
|
23011
|
+
}
|
|
23012
|
+
}
|
|
23013
|
+
async waitForResponseWithTimeout(responsePromise, abortController) {
|
|
23014
|
+
const timeout = setTimeout(() => {
|
|
23015
|
+
abortController.abort();
|
|
23016
|
+
}, this.requestTimeoutMs);
|
|
23017
|
+
try {
|
|
23018
|
+
return await responsePromise;
|
|
23019
|
+
} finally {
|
|
23020
|
+
clearTimeout(timeout);
|
|
23021
|
+
}
|
|
23022
|
+
}
|
|
23023
|
+
async applyIngestResponse(response, label) {
|
|
23024
|
+
const responseBody = await this.parseResponse(response);
|
|
23025
|
+
const lastAcceptedSeq = responseBody.parsed?.last_accepted_seq;
|
|
23026
|
+
if (typeof lastAcceptedSeq === "number") {
|
|
23027
|
+
this.acceptThrough(lastAcceptedSeq);
|
|
23028
|
+
if (lastAcceptedSeq > this.sequence) {
|
|
23029
|
+
this.sequence = lastAcceptedSeq;
|
|
23030
|
+
}
|
|
23031
|
+
this.lastKnownAcceptedSeq = lastAcceptedSeq;
|
|
23032
|
+
if (response.status === 409) {
|
|
23033
|
+
this.rebaseBufferedEvents(lastAcceptedSeq);
|
|
23034
|
+
}
|
|
23035
|
+
}
|
|
23036
|
+
if (!response.ok) {
|
|
23037
|
+
throw new Error(
|
|
23038
|
+
`${label} returned HTTP ${response.status}: ${responseBody.text.slice(0, 300)}`
|
|
23039
|
+
);
|
|
23040
|
+
}
|
|
23041
|
+
}
|
|
23042
|
+
acceptThrough(lastAcceptedSeq) {
|
|
23043
|
+
const previousLength = this.bufferedEvents.length;
|
|
23044
|
+
this.bufferedEvents = this.bufferedEvents.filter(
|
|
23045
|
+
(event) => event.seq > lastAcceptedSeq
|
|
23046
|
+
);
|
|
23047
|
+
if (this.bufferedEvents.length !== previousLength) {
|
|
23048
|
+
this.bufferRevision += 1;
|
|
23049
|
+
}
|
|
23050
|
+
}
|
|
23051
|
+
buildHeaders() {
|
|
23052
|
+
return {
|
|
23053
|
+
Authorization: `Bearer ${this.config.token}`,
|
|
23054
|
+
"Content-Type": "application/x-ndjson"
|
|
23055
|
+
};
|
|
23056
|
+
}
|
|
23057
|
+
rebaseBufferedEvents(lastAcceptedSeq) {
|
|
23058
|
+
let nextSeq = lastAcceptedSeq + 1;
|
|
23059
|
+
this.bufferedEvents = this.bufferedEvents.map((event) => ({
|
|
23060
|
+
...event,
|
|
23061
|
+
seq: nextSeq++
|
|
23062
|
+
}));
|
|
23063
|
+
this.sequence = nextSeq - 1;
|
|
23064
|
+
this.sequenceSynced = true;
|
|
23065
|
+
this.sequenceInitialized = true;
|
|
23066
|
+
this.lastKnownAcceptedSeq = lastAcceptedSeq;
|
|
23067
|
+
this.bufferRevision += 1;
|
|
23068
|
+
}
|
|
23069
|
+
async parseResponse(response) {
|
|
23070
|
+
const text2 = await response.text();
|
|
23071
|
+
if (!text2) {
|
|
23072
|
+
return { parsed: null, text: text2 };
|
|
23073
|
+
}
|
|
23074
|
+
try {
|
|
23075
|
+
return { parsed: JSON.parse(text2), text: text2 };
|
|
23076
|
+
} catch {
|
|
23077
|
+
return { parsed: null, text: text2 };
|
|
23078
|
+
}
|
|
23079
|
+
}
|
|
23080
|
+
canAcceptEvent(event) {
|
|
23081
|
+
const eventBytes = import_node_buffer3.Buffer.byteLength(
|
|
23082
|
+
this.serializeEnvelope({ seq: this.sequence + 1, event }),
|
|
23083
|
+
"utf8"
|
|
23084
|
+
);
|
|
23085
|
+
if (eventBytes > this.maxEventBytes) {
|
|
23086
|
+
this.config.logger.warn("Dropped oversized task run event", {
|
|
23087
|
+
eventBytes,
|
|
23088
|
+
maxEventBytes: this.maxEventBytes
|
|
23089
|
+
});
|
|
23090
|
+
return false;
|
|
23091
|
+
}
|
|
23092
|
+
if (this.bufferedEvents.length >= this.maxBufferedEvents) {
|
|
23093
|
+
this.droppedBeforeSequenceCount += 1;
|
|
23094
|
+
if (this.droppedBeforeSequenceCount === 1 || this.droppedBeforeSequenceCount % 100 === 0) {
|
|
23095
|
+
this.config.logger.warn(
|
|
23096
|
+
"Dropped task run event before assigning sequence due to backpressure",
|
|
23097
|
+
{
|
|
23098
|
+
dropped: this.droppedBeforeSequenceCount,
|
|
23099
|
+
maxBufferedEvents: this.maxBufferedEvents
|
|
23100
|
+
}
|
|
23101
|
+
);
|
|
23102
|
+
}
|
|
23103
|
+
return false;
|
|
23104
|
+
}
|
|
23105
|
+
if (this.droppedBeforeSequenceCount > 0) {
|
|
23106
|
+
this.config.logger.warn("Task run event ingest recovered after drops", {
|
|
23107
|
+
dropped: this.droppedBeforeSequenceCount
|
|
23108
|
+
});
|
|
23109
|
+
this.droppedBeforeSequenceCount = 0;
|
|
23110
|
+
}
|
|
23111
|
+
return true;
|
|
23112
|
+
}
|
|
23113
|
+
serializeEnvelope(envelope) {
|
|
23114
|
+
return JSON.stringify({ seq: envelope.seq, event: envelope.event });
|
|
23115
|
+
}
|
|
23116
|
+
describeError(error) {
|
|
23117
|
+
if (error instanceof Error) {
|
|
23118
|
+
return { message: error.message, stack: error.stack };
|
|
23119
|
+
}
|
|
23120
|
+
return error;
|
|
23121
|
+
}
|
|
23122
|
+
};
|
|
23123
|
+
|
|
22457
23124
|
// src/server/jwt.ts
|
|
22458
23125
|
var import_jsonwebtoken = __toESM(require("jsonwebtoken"), 1);
|
|
22459
23126
|
var import_zod3 = require("zod");
|
|
@@ -22718,6 +23385,7 @@ var AgentServer = class {
|
|
|
22718
23385
|
session = null;
|
|
22719
23386
|
app;
|
|
22720
23387
|
posthogAPI;
|
|
23388
|
+
eventStreamSender = null;
|
|
22721
23389
|
questionRelayedToSlack = false;
|
|
22722
23390
|
detectedPrUrl = null;
|
|
22723
23391
|
lastReportedBranch = null;
|
|
@@ -22761,6 +23429,17 @@ var AgentServer = class {
|
|
|
22761
23429
|
getApiKey: () => config.apiKey,
|
|
22762
23430
|
userAgent: `posthog/cloud.hog.dev; version: ${config.version ?? package_default.version}`
|
|
22763
23431
|
});
|
|
23432
|
+
if (config.eventIngestToken) {
|
|
23433
|
+
this.eventStreamSender = new TaskRunEventStreamSender({
|
|
23434
|
+
apiUrl: config.apiUrl,
|
|
23435
|
+
projectId: config.projectId,
|
|
23436
|
+
taskId: config.taskId,
|
|
23437
|
+
runId: config.runId,
|
|
23438
|
+
token: config.eventIngestToken,
|
|
23439
|
+
logger: this.logger.child("EventIngest"),
|
|
23440
|
+
streamWindowMs: config.eventIngestStreamWindowMs
|
|
23441
|
+
});
|
|
23442
|
+
}
|
|
22764
23443
|
this.app = this.createApp();
|
|
22765
23444
|
}
|
|
22766
23445
|
getRuntimeAdapter() {
|
|
@@ -22978,7 +23657,9 @@ var AgentServer = class {
|
|
|
22978
23657
|
async stop() {
|
|
22979
23658
|
this.logger.debug("Stopping agent server...");
|
|
22980
23659
|
if (this.session) {
|
|
22981
|
-
await this.cleanupSession();
|
|
23660
|
+
await this.cleanupSession({ completeEventStream: true });
|
|
23661
|
+
} else {
|
|
23662
|
+
await this.eventStreamSender?.stop();
|
|
22982
23663
|
}
|
|
22983
23664
|
if (this.server) {
|
|
22984
23665
|
this.server.close();
|
|
@@ -23682,7 +24363,7 @@ Continue from where you left off. The user is waiting for your response.`
|
|
|
23682
24363
|
await (0, import_promises6.mkdir)(artifactDir, { recursive: true });
|
|
23683
24364
|
const artifactPath = (0, import_node_path9.join)(artifactDir, safeName);
|
|
23684
24365
|
await (0, import_promises6.writeFile)(artifactPath, Buffer.from(data));
|
|
23685
|
-
return resourceLink((0,
|
|
24366
|
+
return resourceLink((0, import_node_url3.pathToFileURL)(artifactPath).toString(), artifact.name, {
|
|
23686
24367
|
...artifact.content_type ? { mimeType: artifact.content_type } : {},
|
|
23687
24368
|
...typeof artifact.size === "number" ? { size: artifact.size } : {}
|
|
23688
24369
|
});
|
|
@@ -23928,6 +24609,11 @@ ${signedCommitInstructions}
|
|
|
23928
24609
|
return;
|
|
23929
24610
|
}
|
|
23930
24611
|
const status = "failed";
|
|
24612
|
+
this.enqueueTaskTerminalEvent(POSTHOG_NOTIFICATIONS.ERROR, {
|
|
24613
|
+
source: "agent_server",
|
|
24614
|
+
stopReason,
|
|
24615
|
+
error: errorMessage2 ?? "Agent error"
|
|
24616
|
+
});
|
|
23931
24617
|
try {
|
|
23932
24618
|
await this.posthogAPI.updateTaskRun(payload.task_id, payload.run_id, {
|
|
23933
24619
|
status,
|
|
@@ -23936,8 +24622,21 @@ ${signedCommitInstructions}
|
|
|
23936
24622
|
this.logger.debug("Task completion signaled", { status, stopReason });
|
|
23937
24623
|
} catch (error) {
|
|
23938
24624
|
this.logger.error("Failed to signal task completion", error);
|
|
24625
|
+
} finally {
|
|
24626
|
+
await this.eventStreamSender?.stop();
|
|
23939
24627
|
}
|
|
23940
24628
|
}
|
|
24629
|
+
enqueueTaskTerminalEvent(method, params) {
|
|
24630
|
+
this.eventStreamSender?.enqueue({
|
|
24631
|
+
type: "notification",
|
|
24632
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
24633
|
+
notification: {
|
|
24634
|
+
jsonrpc: "2.0",
|
|
24635
|
+
method,
|
|
24636
|
+
params
|
|
24637
|
+
}
|
|
24638
|
+
});
|
|
24639
|
+
}
|
|
23941
24640
|
configureEnvironment({
|
|
23942
24641
|
isInternal = false,
|
|
23943
24642
|
originProduct,
|
|
@@ -24204,7 +24903,9 @@ ${signedCommitInstructions}
|
|
|
24204
24903
|
});
|
|
24205
24904
|
}
|
|
24206
24905
|
}
|
|
24207
|
-
async cleanupSession(
|
|
24906
|
+
async cleanupSession({
|
|
24907
|
+
completeEventStream = false
|
|
24908
|
+
} = {}) {
|
|
24208
24909
|
if (!this.session) return;
|
|
24209
24910
|
this.logger.debug("Cleaning up session");
|
|
24210
24911
|
try {
|
|
@@ -24234,6 +24935,9 @@ ${signedCommitInstructions}
|
|
|
24234
24935
|
if (this.session.sseController) {
|
|
24235
24936
|
this.session.sseController.close();
|
|
24236
24937
|
}
|
|
24938
|
+
if (completeEventStream) {
|
|
24939
|
+
await this.eventStreamSender?.stop();
|
|
24940
|
+
}
|
|
24237
24941
|
this.pendingEvents = [];
|
|
24238
24942
|
this.lastReportedBranch = null;
|
|
24239
24943
|
this.session = null;
|
|
@@ -24301,9 +25005,11 @@ ${signedCommitInstructions}
|
|
|
24301
25005
|
);
|
|
24302
25006
|
}
|
|
24303
25007
|
broadcastEvent(event) {
|
|
25008
|
+
if (!this.session) return;
|
|
25009
|
+
this.eventStreamSender?.enqueue(event);
|
|
24304
25010
|
if (this.session?.sseController) {
|
|
24305
25011
|
this.sendSseEvent(this.session.sseController, event);
|
|
24306
|
-
} else
|
|
25012
|
+
} else {
|
|
24307
25013
|
this.pendingEvents.push(event);
|
|
24308
25014
|
}
|
|
24309
25015
|
}
|
|
@@ -24373,7 +25079,12 @@ var envSchema = import_v42.z.object({
|
|
|
24373
25079
|
}).regex(/^\d+$/, "POSTHOG_PROJECT_ID must be a numeric string").transform((val) => parseInt(val, 10)),
|
|
24374
25080
|
POSTHOG_CODE_RUNTIME_ADAPTER: import_v42.z.enum(["claude", "codex"]).optional(),
|
|
24375
25081
|
POSTHOG_CODE_MODEL: import_v42.z.string().optional(),
|
|
24376
|
-
POSTHOG_CODE_REASONING_EFFORT: import_v42.z.enum(["low", "medium", "high", "xhigh", "max"]).optional()
|
|
25082
|
+
POSTHOG_CODE_REASONING_EFFORT: import_v42.z.enum(["low", "medium", "high", "xhigh", "max"]).optional(),
|
|
25083
|
+
POSTHOG_TASK_RUN_EVENT_INGEST_TOKEN: import_v42.z.string().min(1).optional(),
|
|
25084
|
+
POSTHOG_TASK_RUN_EVENT_INGEST_STREAM_WINDOW_MS: import_v42.z.string().regex(
|
|
25085
|
+
/^[1-9]\d*$/,
|
|
25086
|
+
"POSTHOG_TASK_RUN_EVENT_INGEST_STREAM_WINDOW_MS must be a positive integer"
|
|
25087
|
+
).transform((value) => parseInt(value, 10)).optional()
|
|
24377
25088
|
});
|
|
24378
25089
|
var program = new import_commander.Command();
|
|
24379
25090
|
function parseBooleanOption(raw, flag) {
|
|
@@ -24445,6 +25156,8 @@ ${errors}`);
|
|
|
24445
25156
|
const server = new AgentServer({
|
|
24446
25157
|
port: parseInt(options.port, 10),
|
|
24447
25158
|
jwtPublicKey: env.JWT_PUBLIC_KEY,
|
|
25159
|
+
eventIngestToken: env.POSTHOG_TASK_RUN_EVENT_INGEST_TOKEN,
|
|
25160
|
+
eventIngestStreamWindowMs: env.POSTHOG_TASK_RUN_EVENT_INGEST_STREAM_WINDOW_MS,
|
|
24448
25161
|
repositoryPath: options.repositoryPath,
|
|
24449
25162
|
apiUrl: env.POSTHOG_API_URL,
|
|
24450
25163
|
apiKey: env.POSTHOG_PERSONAL_API_KEY,
|