@posthog/wizard 2.66.0 → 2.68.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{add-mcp-server-to-clients-DWDEuDUR.js → add-mcp-server-to-clients-y0swAr9I.js} +25 -25
- package/dist/{add-mcp-server-to-clients-DWDEuDUR.js.map → add-mcp-server-to-clients-y0swAr9I.js.map} +1 -1
- package/dist/{agent-interface-D3MNaDp3.js → agent-interface-CaEptZuu.js} +404 -73
- package/dist/agent-interface-CaEptZuu.js.map +1 -0
- package/dist/{agent-prompt-loader-D8Bajo-L.js → agent-prompt-loader-DZHc9tIG.js} +5 -5
- package/dist/{agent-prompt-loader-D8Bajo-L.js.map → agent-prompt-loader-DZHc9tIG.js.map} +1 -1
- package/dist/{agent-runner-DEeMqJxy.js → agent-runner-Do5kyhPo.js} +85 -39
- package/dist/agent-runner-Do5kyhPo.js.map +1 -0
- package/dist/analytics-BNCWoTKa.js +2 -0
- package/dist/{analytics-D8JNuPAT.js → analytics-tF06lcmE.js} +2 -2
- package/dist/{analytics-D8JNuPAT.js.map → analytics-tF06lcmE.js.map} +1 -1
- package/dist/{api-CemGgyBv.js → api-D7-8R4xx.js} +3 -3
- package/dist/{api-CemGgyBv.js.map → api-D7-8R4xx.js.map} +1 -1
- package/dist/bin.js +200 -85
- package/dist/bin.js.map +1 -1
- package/dist/{bounded-fs-C6OjqZst.js → bounded-fs-BwuqKpBH.js} +3 -3
- package/dist/{bounded-fs-C6OjqZst.js.map → bounded-fs-BwuqKpBH.js.map} +1 -1
- package/dist/{ci-install-DIB2n4Ju.js → ci-install-CrqqhXAw.js} +18 -9
- package/dist/ci-install-CrqqhXAw.js.map +1 -0
- package/dist/{debug-H-GTKvvU.js → debug-CWn7PsPd.js} +1 -1
- package/dist/{debug-BKqv-yfT.js → debug-aA5dm2MR.js} +4 -4
- package/dist/debug-aA5dm2MR.js.map +1 -0
- package/dist/{defaults-BHhXrX9F.js → defaults-DI642M3n.js} +1 -1
- package/dist/{defaults-BHhXrX9F.js.map → defaults-DI642M3n.js.map} +1 -1
- package/dist/{env-api-key-CzHDwfV2.js → env-api-key-CwkRyrgi.js} +2 -2
- package/dist/{env-api-key-CzHDwfV2.js.map → env-api-key-CwkRyrgi.js.map} +1 -1
- package/dist/environment-BGUJxuvj.js +44 -0
- package/dist/environment-BGUJxuvj.js.map +1 -0
- package/dist/errors-BHervYGs.js +156 -0
- package/dist/errors-BHervYGs.js.map +1 -0
- package/dist/{file-watcher-Cr-4tA-e.js → file-watcher-Cn7tD95m.js} +2 -2
- package/dist/{file-watcher-Cr-4tA-e.js.map → file-watcher-Cn7tD95m.js.map} +1 -1
- package/dist/{headless-ui-DT3Db1bk.js → headless-ui-DtIYZNVv.js} +2 -2
- package/dist/{headless-ui-DT3Db1bk.js.map → headless-ui-DtIYZNVv.js.map} +1 -1
- package/dist/{interactive-D3LdFxZG.js → interactive-BRB6w6KG.js} +2 -2
- package/dist/{interactive-D3LdFxZG.js.map → interactive-BRB6w6KG.js.map} +1 -1
- package/dist/{local-dev-BN6NKQ0B.js → local-dev-DPZiIPCK.js} +1 -1
- package/dist/{local-dev-BN6NKQ0B.js.map → local-dev-DPZiIPCK.js.map} +1 -1
- package/dist/{mcp-BjckYQmP.js → mcp-BXdSTZe6.js} +2 -2
- package/dist/{mcp-BjckYQmP.js.map → mcp-BXdSTZe6.js.map} +1 -1
- package/dist/{mcp-prompt-streaming--sRErHKv.js → mcp-prompt-streaming-DhOT15Jj.js} +13 -12
- package/dist/mcp-prompt-streaming-DhOT15Jj.js.map +1 -0
- package/dist/{non-interactive-CNoYoEZp.js → non-interactive-ezilF3PY.js} +7 -2
- package/dist/non-interactive-ezilF3PY.js.map +1 -0
- package/dist/{orchestrator-tools-8bGyDDhn.js → orchestrator-tools-D82843t_.js} +3 -3
- package/dist/{orchestrator-tools-8bGyDDhn.js.map → orchestrator-tools-D82843t_.js.map} +1 -1
- package/dist/{package-json-D0DCWpe5.js → package-json-GEU2VZlS.js} +1 -1
- package/dist/{package-json-D0DCWpe5.js.map → package-json-GEU2VZlS.js.map} +1 -1
- package/dist/{package-manager-BQDHm7ER.js → package-manager-BPoVLj7W.js} +4 -4
- package/dist/package-manager-BPoVLj7W.js.map +1 -0
- package/dist/{pi-W-4RUPFY.js → pi-CKyt4bcu.js} +17 -13
- package/dist/pi-CKyt4bcu.js.map +1 -0
- package/dist/{playground-uHHgZChe.js → playground-Dnyb4jLu.js} +7 -7
- package/dist/{playground-uHHgZChe.js.map → playground-Dnyb4jLu.js.map} +1 -1
- package/dist/{posthog-ChzdlmCs.js → posthog-BHyJiU05.js} +2 -2
- package/dist/{posthog-ChzdlmCs.js.map → posthog-BHyJiU05.js.map} +1 -1
- package/dist/{posthog-integration-LxEBGkoe.js → posthog-integration-DJX4qTDQ.js} +22 -17
- package/dist/posthog-integration-DJX4qTDQ.js.map +1 -0
- package/dist/{provisioning-BHTl91OZ.js → provisioning-DEEt9xl4.js} +3 -3
- package/dist/{provisioning-BHTl91OZ.js.map → provisioning-DEEt9xl4.js.map} +1 -1
- package/dist/{queue-tools-DABh1Ssc.js → queue-tools-i_TmeI02.js} +3 -3
- package/dist/{queue-tools-DABh1Ssc.js.map → queue-tools-i_TmeI02.js.map} +1 -1
- package/dist/{registry-CxNpCNAj.js → registry-CbXqxcX0.js} +81 -81
- package/dist/{registry-CxNpCNAj.js.map → registry-CbXqxcX0.js.map} +1 -1
- package/dist/{security-B4jU_-7q.js → security-DZ1rkONB.js} +21 -9
- package/dist/security-DZ1rkONB.js.map +1 -0
- package/dist/{setup-utils-aWZEdfwh.js → setup-utils-BLKhAx6g.js} +13 -13
- package/dist/{setup-utils-aWZEdfwh.js.map → setup-utils-BLKhAx6g.js.map} +1 -1
- package/dist/{start-tui-BQH4mQIZ.js → start-tui-D1MqJVT1.js} +33 -23
- package/dist/start-tui-D1MqJVT1.js.map +1 -0
- package/dist/{steps-5HAqjUvn.js → steps-Dsw-zBET.js} +7 -7
- package/dist/{steps-5HAqjUvn.js.map → steps-Dsw-zBET.js.map} +1 -1
- package/dist/{store-P_7zUfbj.js → store-OGBMWp3H.js} +5 -5
- package/dist/{store-P_7zUfbj.js.map → store-OGBMWp3H.js.map} +1 -1
- package/dist/{subagent-uGPDXPfS.js → subagent-DrnKYgvu.js} +2 -2
- package/dist/{subagent-uGPDXPfS.js.map → subagent-DrnKYgvu.js.map} +1 -1
- package/dist/{task-oh8OAnvR.js → task-DyvLyDsO.js} +18 -14
- package/dist/task-DyvLyDsO.js.map +1 -0
- package/dist/{task-stream-jUARpyB5.js → task-stream-CLXzeuPO.js} +16 -9
- package/dist/task-stream-CLXzeuPO.js.map +1 -0
- package/dist/{tasks-2mu3lAvm.js → tasks-D77GNdOU.js} +2 -2
- package/dist/{tasks-2mu3lAvm.js.map → tasks-D77GNdOU.js.map} +1 -1
- package/dist/{telemetry-BllPiBKw.js → telemetry-wp-z9LXH.js} +3 -3
- package/dist/{telemetry-BllPiBKw.js.map → telemetry-wp-z9LXH.js.map} +1 -1
- package/dist/{terminal-aWQrDy8s.js → terminal-D9j4wbpD.js} +13 -13
- package/dist/{terminal-aWQrDy8s.js.map → terminal-D9j4wbpD.js.map} +1 -1
- package/dist/{tools-u8TaJFqa.js → tools-D0r4e-Vu.js} +10 -7
- package/dist/tools-D0r4e-Vu.js.map +1 -0
- package/dist/wizard-abort-Bv87YVSp.js +71 -0
- package/dist/wizard-abort-Bv87YVSp.js.map +1 -0
- package/dist/{wizard-abort-pFFH7dcx.js → wizard-abort-oazJA1Jb.js} +1 -1
- package/dist/{wizard-session-DTyLMPsX.js → wizard-session-C_7r3-rO.js} +3 -2
- package/dist/wizard-session-C_7r3-rO.js.map +1 -0
- package/dist/{wizard-session-Cw7-_OcZ.js → wizard-session-D1KQqUml.js} +1 -1
- package/dist/yara-hooks-Bl-FeANN.js +2 -0
- package/dist/{yara-hooks-BXDBIOBq.js → yara-hooks-DeonKbE_.js} +57 -8
- package/dist/yara-hooks-DeonKbE_.js.map +1 -0
- package/package.json +1 -1
- package/dist/agent-interface-D3MNaDp3.js.map +0 -1
- package/dist/agent-runner-DEeMqJxy.js.map +0 -1
- package/dist/analytics-DN3Kzf7H.js +0 -2
- package/dist/ci-install-DIB2n4Ju.js.map +0 -1
- package/dist/debug-BKqv-yfT.js.map +0 -1
- package/dist/environment-Cl-fIQku.js +0 -22
- package/dist/environment-Cl-fIQku.js.map +0 -1
- package/dist/mcp-prompt-streaming--sRErHKv.js.map +0 -1
- package/dist/non-interactive-CNoYoEZp.js.map +0 -1
- package/dist/package-manager-BQDHm7ER.js.map +0 -1
- package/dist/pi-W-4RUPFY.js.map +0 -1
- package/dist/posthog-integration-LxEBGkoe.js.map +0 -1
- package/dist/security-B4jU_-7q.js.map +0 -1
- package/dist/start-tui-BQH4mQIZ.js.map +0 -1
- package/dist/task-oh8OAnvR.js.map +0 -1
- package/dist/task-stream-jUARpyB5.js.map +0 -1
- package/dist/tools-u8TaJFqa.js.map +0 -1
- package/dist/wizard-abort-D9jiMkZA.js +0 -49
- package/dist/wizard-abort-D9jiMkZA.js.map +0 -1
- package/dist/wizard-session-DTyLMPsX.js.map +0 -1
- package/dist/yara-hooks-BXDBIOBq.js.map +0 -1
- package/dist/yara-hooks-i2jOabhI.js +0 -2
|
@@ -1,20 +1,243 @@
|
|
|
1
1
|
import { n as __require } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
2
|
+
import { a as AgentSignals, o as REMARK_INSTRUCTION, s as classifyAuthFailure } from "./errors-BHervYGs.js";
|
|
3
|
+
import { G as POSTHOG_FLAG_HEADER_PREFIX, J as POSTHOG_PROPERTY_HEADER_PREFIX, a as getLogFilePath, dt as WIZARD_REMARK_EVENT_NAME, f as getUI, ht as wizardUserAgentForProgram, o as initLogFile, r as debug, s as logToFile, xt as runtimeEnv } from "./debug-aA5dm2MR.js";
|
|
4
|
+
import { n as analytics } from "./analytics-tF06lcmE.js";
|
|
5
|
+
import { a as safeReadFile, i as readProjectFile, o as walkProjectFiles } from "./bounded-fs-BwuqKpBH.js";
|
|
6
|
+
import { n as ADDITIONAL_FEATURE_PROMPTS } from "./wizard-session-C_7r3-rO.js";
|
|
7
|
+
import { i as wizardAbort, n as registerCleanup, t as WizardError } from "./wizard-abort-Bv87YVSp.js";
|
|
8
|
+
import { _ as modelCapabilities, m as writeJsonAtomic, o as buildOrchestratorTools, p as makeMutex, y as triageModelFor } from "./queue-tools-i_TmeI02.js";
|
|
9
|
+
import { b as coerceAuditChecks, g as AUDIT_CHECKS_FILE, l as prewarmYaraScanner, n as createPostToolUseYaraHooks, p as scanInstalledSkill, r as createPreToolUseYaraHooks } from "./yara-hooks-DeonKbE_.js";
|
|
9
10
|
import { createRequire } from "node:module";
|
|
10
11
|
import * as fs$1 from "fs";
|
|
11
12
|
import fs from "fs";
|
|
12
13
|
import path from "path";
|
|
14
|
+
import path$1 from "node:path";
|
|
13
15
|
import { spawnSync } from "node:child_process";
|
|
16
|
+
import { closeSync, constants, fchmodSync, lstatSync, openSync, renameSync, unlinkSync, writeSync } from "node:fs";
|
|
17
|
+
import { randomBytes } from "node:crypto";
|
|
14
18
|
import { z } from "zod";
|
|
15
19
|
import * as os from "os";
|
|
16
20
|
import { unzipSync } from "fflate";
|
|
17
21
|
import { randomUUID } from "crypto";
|
|
22
|
+
//#region src/lib/gateway-session.ts
|
|
23
|
+
/**
|
|
24
|
+
* Gateway auth for a wizard run: a `phe_` scoped token the backend mints, with
|
|
25
|
+
* pinned attribution, a spend cap and an expiry.
|
|
26
|
+
*
|
|
27
|
+
* A 404 resolves to the legacy posture (OAuth token, Python gateway); every
|
|
28
|
+
* other failure throws, because the legacy path enforces none of those, so a
|
|
29
|
+
* silent downgrade spends unattributed money to hide an outage.
|
|
30
|
+
*/
|
|
31
|
+
let cached = null;
|
|
32
|
+
/**
|
|
33
|
+
* Shared so concurrent callers mint once. The orchestrator starts every runnable
|
|
34
|
+
* task at once, and each would otherwise take its own token and its own cap.
|
|
35
|
+
*/
|
|
36
|
+
let inFlight = null;
|
|
37
|
+
/**
|
|
38
|
+
* Adoption floor. The anthropic subprocess holds its credential for the whole
|
|
39
|
+
* session, so a token below this 401s mid-run.
|
|
40
|
+
*/
|
|
41
|
+
const MIN_USABLE_TTL_MS = 120 * 1e3;
|
|
42
|
+
/** Re-resolve at this fraction of the token's life, leaving a usable remainder. */
|
|
43
|
+
const REFRESH_AT_FRACTION = .8;
|
|
44
|
+
/** How long a legacy fallback sticks before the mint endpoint is retried. */
|
|
45
|
+
const LEGACY_RETRY_MS = 600 * 1e3;
|
|
46
|
+
const MINT_TIMEOUT_MS = 2e4;
|
|
47
|
+
/** Resolve this run's gateway auth, minting and re-minting near expiry. */
|
|
48
|
+
async function gatewayAuth(host, accessToken, program) {
|
|
49
|
+
const key = `${host.apiHost}\n${accessToken}\n${program ?? ""}`;
|
|
50
|
+
if (cached && cached.key === key && Date.now() < cached.staleAtMs) return cached.auth;
|
|
51
|
+
if (inFlight && inFlight.key === key) return inFlight.promise;
|
|
52
|
+
const promise = resolveGatewayAuth(host, accessToken, key, program);
|
|
53
|
+
inFlight = {
|
|
54
|
+
key,
|
|
55
|
+
promise
|
|
56
|
+
};
|
|
57
|
+
try {
|
|
58
|
+
return await promise;
|
|
59
|
+
} finally {
|
|
60
|
+
if (inFlight?.promise === promise) inFlight = null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function resolveGatewayAuth(host, accessToken, key, program) {
|
|
64
|
+
if (!program) {
|
|
65
|
+
logToFile("[gateway] run has no program id; failing the run");
|
|
66
|
+
throw new GatewayMintFailed("this run has no program to attribute its spend to");
|
|
67
|
+
}
|
|
68
|
+
const minted = await mintGatewayToken(host, accessToken, program);
|
|
69
|
+
if (!minted) {
|
|
70
|
+
const auth = legacyAuth(host, accessToken);
|
|
71
|
+
cached = {
|
|
72
|
+
key,
|
|
73
|
+
auth,
|
|
74
|
+
staleAtMs: Date.now() + LEGACY_RETRY_MS
|
|
75
|
+
};
|
|
76
|
+
return auth;
|
|
77
|
+
}
|
|
78
|
+
const expiresAtMs = Date.parse(minted.expiresAt);
|
|
79
|
+
const ttlMs = expiresAtMs - Date.now();
|
|
80
|
+
if (!Number.isFinite(expiresAtMs) || ttlMs < MIN_USABLE_TTL_MS) {
|
|
81
|
+
logToFile(`[gateway] mint returned a token with ${ttlMs}ms of life; failing the run`);
|
|
82
|
+
throw new GatewayMintFailed(`the PostHog gateway issued a token with ${ttlMs}ms of life`);
|
|
83
|
+
}
|
|
84
|
+
const staleAtMs = Date.now() + ttlMs * REFRESH_AT_FRACTION;
|
|
85
|
+
const auth = {
|
|
86
|
+
gatewayUrl: minted.gatewayUrl,
|
|
87
|
+
token: minted.token,
|
|
88
|
+
edition: "v2",
|
|
89
|
+
teamId: minted.teamId
|
|
90
|
+
};
|
|
91
|
+
cached = {
|
|
92
|
+
key,
|
|
93
|
+
auth,
|
|
94
|
+
staleAtMs
|
|
95
|
+
};
|
|
96
|
+
return auth;
|
|
97
|
+
}
|
|
98
|
+
/** The legacy posture: the user's OAuth token against the Python gateway. */
|
|
99
|
+
function legacyAuth(host, accessToken) {
|
|
100
|
+
return {
|
|
101
|
+
gatewayUrl: host.gatewayUrl,
|
|
102
|
+
token: accessToken,
|
|
103
|
+
edition: "legacy"
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Whether a server-supplied origin may receive a bearer and prompt content:
|
|
108
|
+
* https (loopback excepted), and either a posthog.com host or the one the run
|
|
109
|
+
* authenticated against.
|
|
110
|
+
*/
|
|
111
|
+
function isTrustedGatewayUrl(value, apiHost) {
|
|
112
|
+
let url;
|
|
113
|
+
try {
|
|
114
|
+
url = new URL(value);
|
|
115
|
+
} catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
if (url.pathname !== "/" || url.search || url.hash || url.username || url.password) return false;
|
|
119
|
+
if (url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "host.docker.internal") return true;
|
|
120
|
+
if (url.protocol !== "https:") return false;
|
|
121
|
+
if (url.hostname.endsWith(".posthog.com")) return true;
|
|
122
|
+
try {
|
|
123
|
+
return url.hostname === new URL(apiHost).hostname;
|
|
124
|
+
} catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* A deliberate refusal from the mint endpoint, as opposed to the mint being
|
|
130
|
+
* unavailable. Thrown rather than folded into the legacy fallback, so the run
|
|
131
|
+
* stops instead of proceeding without the controls the refusal was enforcing.
|
|
132
|
+
*/
|
|
133
|
+
var GatewayMintRefused = class extends Error {
|
|
134
|
+
status;
|
|
135
|
+
constructor(status, message) {
|
|
136
|
+
super(message);
|
|
137
|
+
this.name = "GatewayMintRefused";
|
|
138
|
+
this.status = status;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* The mint could not produce a usable credential: unreachable, a 5xx, or a
|
|
143
|
+
* response the client cannot use.
|
|
144
|
+
*/
|
|
145
|
+
var GatewayMintFailed = class extends Error {
|
|
146
|
+
constructor(message) {
|
|
147
|
+
super(message);
|
|
148
|
+
this.name = "GatewayMintFailed";
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Whether a mint status means "refused this run" rather than "not available".
|
|
153
|
+
* 429 is the daily run limit, 403 revoked project access, 401 a credential that
|
|
154
|
+
* may not mint. Only 404 falls back; it is the rollout switch.
|
|
155
|
+
*/
|
|
156
|
+
function isMintRefusal(status) {
|
|
157
|
+
return status === 400 || status === 401 || status === 403 || status === 429;
|
|
158
|
+
}
|
|
159
|
+
function mintRefusalMessage(status) {
|
|
160
|
+
switch (status) {
|
|
161
|
+
case 429: return "This wizard program has used its daily run limit. Try again tomorrow.";
|
|
162
|
+
case 403: return "Your access to this project has changed. Re-authenticate and try again.";
|
|
163
|
+
case 400: return "Your PostHog login must cover exactly one project. Re-authenticate and try again.";
|
|
164
|
+
default: return "The wizard could not authenticate to the PostHog gateway.";
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async function mintGatewayToken(host, accessToken, program) {
|
|
168
|
+
try {
|
|
169
|
+
const resp = await fetch(`${host.apiHost}/api/wizard/gateway_token/`, {
|
|
170
|
+
method: "POST",
|
|
171
|
+
headers: {
|
|
172
|
+
Authorization: `Bearer ${accessToken}`,
|
|
173
|
+
"Content-Type": "application/json"
|
|
174
|
+
},
|
|
175
|
+
body: JSON.stringify({ program }),
|
|
176
|
+
signal: AbortSignal.timeout(MINT_TIMEOUT_MS)
|
|
177
|
+
});
|
|
178
|
+
if (!resp.ok) {
|
|
179
|
+
if (isMintRefusal(resp.status)) {
|
|
180
|
+
logToFile(`[gateway] mint refused with HTTP ${resp.status}; failing the run`);
|
|
181
|
+
throw new GatewayMintRefused(resp.status, mintRefusalMessage(resp.status));
|
|
182
|
+
}
|
|
183
|
+
if (resp.status === 404) {
|
|
184
|
+
logToFile("[gateway] mint not enabled for this org; staying on the existing gateway");
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
logToFile(`[gateway] mint failed with HTTP ${resp.status}; failing the run`);
|
|
188
|
+
throw new GatewayMintFailed(`the PostHog gateway could not issue a token (HTTP ${resp.status})`);
|
|
189
|
+
}
|
|
190
|
+
const body = await resp.json();
|
|
191
|
+
if (!body.token) {
|
|
192
|
+
logToFile("[gateway] mint response omitted token; failing the run");
|
|
193
|
+
throw new GatewayMintFailed("mint response omitted token");
|
|
194
|
+
}
|
|
195
|
+
if (!body.expires_at) {
|
|
196
|
+
logToFile("[gateway] mint response omitted expires_at; failing the run");
|
|
197
|
+
throw new GatewayMintFailed("mint response omitted expires_at");
|
|
198
|
+
}
|
|
199
|
+
if (!body.gateway_url) {
|
|
200
|
+
logToFile("[gateway] mint response omitted gateway_url; failing the run");
|
|
201
|
+
throw new GatewayMintFailed("mint response omitted gateway_url");
|
|
202
|
+
}
|
|
203
|
+
if (!isTrustedGatewayUrl(body.gateway_url, host.apiHost)) {
|
|
204
|
+
logToFile("[gateway] mint returned an untrusted gateway url; failing the run");
|
|
205
|
+
throw new GatewayMintFailed("mint returned an untrusted gateway url");
|
|
206
|
+
}
|
|
207
|
+
return {
|
|
208
|
+
token: body.token,
|
|
209
|
+
expiresAt: body.expires_at,
|
|
210
|
+
gatewayUrl: body.gateway_url.replace(/\/+$/, ""),
|
|
211
|
+
teamId: body.team_id
|
|
212
|
+
};
|
|
213
|
+
} catch (e) {
|
|
214
|
+
if (e instanceof GatewayMintRefused || e instanceof GatewayMintFailed) throw e;
|
|
215
|
+
logToFile(`[gateway] mint transport failure (${String(e)}); failing the run`);
|
|
216
|
+
throw new GatewayMintFailed(`could not reach the PostHog gateway (${String(e)})`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* The v2 run-metadata carrier: one JSON blob for the `X-PostHog-Properties`
|
|
221
|
+
* header. Plain keys only, since the gateway strips `$`-prefixed keys as reserved,
|
|
222
|
+
* so feature-flag variants land as `wizard_flag_<key>` instead of the legacy
|
|
223
|
+
* `$feature/<key>` (dashboards keying on `$feature/wizard-*` read the new key
|
|
224
|
+
* post-cutover).
|
|
225
|
+
*/
|
|
226
|
+
function buildWizardPropertiesBlob(wizardMetadata, wizardFlags, teamId) {
|
|
227
|
+
const props = {};
|
|
228
|
+
if (teamId !== void 0) props.team_id = teamId;
|
|
229
|
+
for (const [key, value] of Object.entries(wizardMetadata)) props[stripPropertyPrefix(key)] = value;
|
|
230
|
+
for (const [flagKey, variant] of Object.entries(wizardFlags)) {
|
|
231
|
+
if (!flagKey.toLowerCase().startsWith("wizard")) continue;
|
|
232
|
+
props[`wizard_flag_${flagKey.toLowerCase()}`] = variant;
|
|
233
|
+
}
|
|
234
|
+
return JSON.stringify(props);
|
|
235
|
+
}
|
|
236
|
+
const LEGACY_PROPERTY_PREFIX = "X-POSTHOG-PROPERTY-";
|
|
237
|
+
function stripPropertyPrefix(key) {
|
|
238
|
+
return key.toUpperCase().startsWith(LEGACY_PROPERTY_PREFIX) ? key.slice(19).toLowerCase() : key;
|
|
239
|
+
}
|
|
240
|
+
//#endregion
|
|
18
241
|
//#region src/lib/agent/runner/harness/pi/gateway.ts
|
|
19
242
|
/**
|
|
20
243
|
* PostHog LLM gateway provider spec for pi sessions — shared by the linear run
|
|
@@ -36,15 +259,20 @@ function gatewayApiFor(modelId) {
|
|
|
36
259
|
return modelId.startsWith("openai/") ? "openai-completions" : "anthropic-messages";
|
|
37
260
|
}
|
|
38
261
|
/**
|
|
39
|
-
* Gateway HTTP headers, mirroring `buildAgentEnv` on the anthropic path
|
|
40
|
-
* the
|
|
41
|
-
*
|
|
262
|
+
* Gateway HTTP headers, mirroring `buildAgentEnv` on the anthropic path. The
|
|
263
|
+
* shape follows the gateway edition: legacy sends per-key metadata/flag
|
|
264
|
+
* headers plus the explicit Bedrock-fallback opt-in; v2 (the Go ai-gateway)
|
|
265
|
+
* takes one `X-PostHog-Properties` JSON blob and falls back natively. The 1M
|
|
266
|
+
* context beta rides both, since pi otherwise runs at 200k and overflows on larger
|
|
267
|
+
* projects (the post-run compaction failures).
|
|
42
268
|
*/
|
|
43
|
-
function buildGatewayHeaders(wizardMetadata, wizardFlags) {
|
|
44
|
-
const headers = {
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
|
|
269
|
+
function buildGatewayHeaders(wizardMetadata, wizardFlags, edition = "legacy", teamId) {
|
|
270
|
+
const headers = { "anthropic-beta": "context-1m-2025-08-07" };
|
|
271
|
+
if (edition === "v2") {
|
|
272
|
+
headers["X-PostHog-Properties"] = buildWizardPropertiesBlob(wizardMetadata, wizardFlags, teamId);
|
|
273
|
+
return headers;
|
|
274
|
+
}
|
|
275
|
+
headers["x-posthog-use-bedrock-fallback"] = "true";
|
|
48
276
|
for (const [key, value] of Object.entries(wizardMetadata)) {
|
|
49
277
|
const name = key.startsWith("X-POSTHOG-PROPERTY-") ? key : `${POSTHOG_PROPERTY_HEADER_PREFIX}${key}`;
|
|
50
278
|
headers[name] = value;
|
|
@@ -61,7 +289,7 @@ function buildGatewayHeaders(wizardMetadata, wizardFlags) {
|
|
|
61
289
|
* callers (scan triage) hand it straight to `completeSimple`.
|
|
62
290
|
*/
|
|
63
291
|
function buildGatewayModel(inputs) {
|
|
64
|
-
const { gatewayUrl, wizardMetadata, wizardFlags, modelId } = inputs;
|
|
292
|
+
const { gatewayUrl, wizardMetadata, wizardFlags, modelId, edition, teamId } = inputs;
|
|
65
293
|
const api = gatewayApiFor(modelId);
|
|
66
294
|
return {
|
|
67
295
|
id: modelId,
|
|
@@ -79,7 +307,7 @@ function buildGatewayModel(inputs) {
|
|
|
79
307
|
},
|
|
80
308
|
contextWindow: 1e6,
|
|
81
309
|
maxTokens: 64e3,
|
|
82
|
-
headers: buildGatewayHeaders(wizardMetadata, wizardFlags)
|
|
310
|
+
headers: buildGatewayHeaders(wizardMetadata, wizardFlags, edition, teamId)
|
|
83
311
|
};
|
|
84
312
|
}
|
|
85
313
|
/**
|
|
@@ -90,9 +318,9 @@ function buildGatewayProvider(inputs) {
|
|
|
90
318
|
const { gatewayUrl, accessToken, modelId, effort } = inputs;
|
|
91
319
|
const api = gatewayApiFor(modelId);
|
|
92
320
|
const tableCaps = modelCapabilities(modelId);
|
|
93
|
-
const caps = effort && tableCaps.reasoning ? {
|
|
321
|
+
const caps = effort && effort !== "off" && tableCaps.reasoning ? modelCapabilities(modelId, effort) : effort === "off" && tableCaps.reasoning ? {
|
|
94
322
|
...tableCaps,
|
|
95
|
-
thinkingLevel:
|
|
323
|
+
thinkingLevel: "off"
|
|
96
324
|
} : tableCaps;
|
|
97
325
|
const model = buildGatewayModel(inputs);
|
|
98
326
|
return {
|
|
@@ -127,6 +355,8 @@ function createTriageLLMProvider(auth, harness) {
|
|
|
127
355
|
const model = buildGatewayModel({
|
|
128
356
|
gatewayUrl: baseURL,
|
|
129
357
|
accessToken: authToken,
|
|
358
|
+
edition: auth.edition,
|
|
359
|
+
teamId: auth.teamId,
|
|
130
360
|
wizardMetadata: auth?.wizardMetadata ?? {},
|
|
131
361
|
wizardFlags: auth?.wizardFlags ?? {},
|
|
132
362
|
modelId
|
|
@@ -832,7 +1062,7 @@ function isFullyCancelled(answers) {
|
|
|
832
1062
|
}
|
|
833
1063
|
function createWizardAskBridge(opts) {
|
|
834
1064
|
const timeoutMs = opts.timeoutMs ?? 3e5;
|
|
835
|
-
return { async request({ questions }) {
|
|
1065
|
+
return { async request({ questions, subject }) {
|
|
836
1066
|
const pending = {
|
|
837
1067
|
id: randomUUID(),
|
|
838
1068
|
questions,
|
|
@@ -853,12 +1083,14 @@ function createWizardAskBridge(opts) {
|
|
|
853
1083
|
const durationMs = Date.now() - startedAt;
|
|
854
1084
|
if (isFullyCancelled(answers)) analytics.wizardCapture("wizard_ask cancelled", {
|
|
855
1085
|
source: pending.source,
|
|
1086
|
+
subject,
|
|
856
1087
|
question_count: questions.length,
|
|
857
1088
|
duration_ms: durationMs,
|
|
858
1089
|
timed_out: durationMs >= timeoutMs
|
|
859
1090
|
});
|
|
860
1091
|
else analytics.wizardCapture("wizard_ask answered", {
|
|
861
1092
|
source: pending.source,
|
|
1093
|
+
subject,
|
|
862
1094
|
question_count: questions.length,
|
|
863
1095
|
duration_ms: durationMs
|
|
864
1096
|
});
|
|
@@ -1462,8 +1694,68 @@ const WIZARD_TOOL_NAMES = {
|
|
|
1462
1694
|
const MAX_HANDOFF_TEXT_CHARS = 64 * 1024;
|
|
1463
1695
|
const PUBLISH_HANDOFF_TOOL_NAME = "publish_handoff";
|
|
1464
1696
|
/** Shared between the MCP server and the pi facade so the contract can't drift. */
|
|
1465
|
-
const PUBLISH_HANDOFF_DESCRIPTION = "Publish the handoff document — the full markdown report of what this run did — to the wizard session. Call it exactly once, at the end of the run, passing the complete report as `content`. This call is the
|
|
1697
|
+
const PUBLISH_HANDOFF_DESCRIPTION = "Publish the handoff document — the full markdown report of what this run did — to the wizard session. Call it exactly once, at the end of the run, passing the complete report as `content`. This call is the required way to deliver the report to the user; do not write the report to a file yourself.";
|
|
1466
1698
|
const PUBLISH_HANDOFF_CONTENT_DESCRIPTION = "The complete handoff report as markdown, starting with an H1 heading.";
|
|
1699
|
+
/**
|
|
1700
|
+
* Write the handoff report to the host-designated `targetPath`.
|
|
1701
|
+
*
|
|
1702
|
+
* The destination comes from the host (`POSTHOG_HANDOFF_OUTPUT_PATH`,
|
|
1703
|
+
* process-env only — the agent can neither set nor see it) while the bytes come
|
|
1704
|
+
* from the agent, so the write is treated as a trust-boundary crossing:
|
|
1705
|
+
* - relative paths are refused (a relative destination would silently resolve
|
|
1706
|
+
* against whatever CWD the wizard happens to run in);
|
|
1707
|
+
* - a pre-existing non-regular destination (symlink, directory, FIFO, device)
|
|
1708
|
+
* is refused, so a primed symlink can't redirect the write at another file;
|
|
1709
|
+
* - content lands in a unique sibling temp file opened with O_NOFOLLOW |
|
|
1710
|
+
* O_EXCL and is then rename()d over the destination — atomic for a polling
|
|
1711
|
+
* reader, and rename replaces the *link* rather than following it;
|
|
1712
|
+
* - the final file is chmod'd to 0o600 even when the host pre-created it with
|
|
1713
|
+
* looser permissions (the report quotes the user's code).
|
|
1714
|
+
*
|
|
1715
|
+
* `reason` is safe to surface to the agent (it names no path); `detail` carries
|
|
1716
|
+
* the specifics for the local log only.
|
|
1717
|
+
*/
|
|
1718
|
+
function writeHandoffFileAtomically(targetPath, text) {
|
|
1719
|
+
if (!path$1.isAbsolute(targetPath)) return {
|
|
1720
|
+
ok: false,
|
|
1721
|
+
reason: "destination is not an absolute path",
|
|
1722
|
+
detail: `relative destination refused: ${targetPath}`
|
|
1723
|
+
};
|
|
1724
|
+
let stat;
|
|
1725
|
+
try {
|
|
1726
|
+
stat = lstatSync(targetPath);
|
|
1727
|
+
} catch {
|
|
1728
|
+
stat = void 0;
|
|
1729
|
+
}
|
|
1730
|
+
if (stat && !stat.isFile()) return {
|
|
1731
|
+
ok: false,
|
|
1732
|
+
reason: "destination is not a regular file",
|
|
1733
|
+
detail: `non-regular destination refused: ${targetPath}`
|
|
1734
|
+
};
|
|
1735
|
+
const tmpPath = `${targetPath}.tmp-${process.pid}-${randomBytes(6).toString("hex")}`;
|
|
1736
|
+
let fd;
|
|
1737
|
+
try {
|
|
1738
|
+
fd = openSync(tmpPath, constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | constants.O_NOFOLLOW | constants.O_EXCL, 384);
|
|
1739
|
+
writeSync(fd, text, null, "utf8");
|
|
1740
|
+
fchmodSync(fd, 384);
|
|
1741
|
+
closeSync(fd);
|
|
1742
|
+
fd = void 0;
|
|
1743
|
+
renameSync(tmpPath, targetPath);
|
|
1744
|
+
return { ok: true };
|
|
1745
|
+
} catch (err) {
|
|
1746
|
+
if (fd !== void 0) try {
|
|
1747
|
+
closeSync(fd);
|
|
1748
|
+
} catch {}
|
|
1749
|
+
try {
|
|
1750
|
+
unlinkSync(tmpPath);
|
|
1751
|
+
} catch {}
|
|
1752
|
+
return {
|
|
1753
|
+
ok: false,
|
|
1754
|
+
reason: (typeof err === "object" && err !== null && "code" in err ? String(err.code) : void 0) ?? "write error",
|
|
1755
|
+
detail: err instanceof Error ? err.message : String(err)
|
|
1756
|
+
};
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1467
1759
|
function publishHandoff(content) {
|
|
1468
1760
|
if (content.trim() === "") {
|
|
1469
1761
|
analytics.wizardCapture("handoff published", {
|
|
@@ -1478,14 +1770,29 @@ function publishHandoff(content) {
|
|
|
1478
1770
|
const truncated = content.length > MAX_HANDOFF_TEXT_CHARS;
|
|
1479
1771
|
const text = truncated ? content.slice(0, MAX_HANDOFF_TEXT_CHARS) : content;
|
|
1480
1772
|
getUI().setHandoffText(text);
|
|
1773
|
+
const handoffOutputPath = runtimeEnv("POSTHOG_HANDOFF_OUTPUT_PATH");
|
|
1774
|
+
let handoffOutputWritten;
|
|
1775
|
+
let handoffOutputError;
|
|
1776
|
+
if (handoffOutputPath) {
|
|
1777
|
+
const write = writeHandoffFileAtomically(handoffOutputPath, text);
|
|
1778
|
+
handoffOutputWritten = write.ok;
|
|
1779
|
+
if (!write.ok) {
|
|
1780
|
+
handoffOutputError = write.reason;
|
|
1781
|
+
logToFile(`[publish_handoff] host output write failed (${write.reason}): ${write.detail}`);
|
|
1782
|
+
}
|
|
1783
|
+
}
|
|
1481
1784
|
analytics.wizardCapture("handoff published", {
|
|
1482
1785
|
handoff_ok: true,
|
|
1483
1786
|
handoff_chars: text.length,
|
|
1484
|
-
handoff_truncated: truncated
|
|
1787
|
+
handoff_truncated: truncated,
|
|
1788
|
+
handoff_output_written: handoffOutputWritten
|
|
1485
1789
|
});
|
|
1790
|
+
const notes = [];
|
|
1791
|
+
if (truncated) notes.push("truncated to the 64 KB limit");
|
|
1792
|
+
if (handoffOutputError) notes.push(`host output write failed: ${handoffOutputError}`);
|
|
1486
1793
|
return {
|
|
1487
1794
|
ok: true,
|
|
1488
|
-
message: `Handoff published (${text.length} chars${
|
|
1795
|
+
message: `Handoff published (${text.length} chars${notes.length > 0 ? `, ${notes.join("; ")}` : ""}).`
|
|
1489
1796
|
};
|
|
1490
1797
|
}
|
|
1491
1798
|
//#endregion
|
|
@@ -1847,7 +2154,10 @@ async function createWizardToolsServer(options) {
|
|
|
1847
2154
|
}
|
|
1848
2155
|
askAccounting.record(args.subject);
|
|
1849
2156
|
try {
|
|
1850
|
-
const answers = await askBridge.request({
|
|
2157
|
+
const answers = await askBridge.request({
|
|
2158
|
+
questions: args.questions,
|
|
2159
|
+
subject: normaliseAskSubject(args.subject)
|
|
2160
|
+
});
|
|
1851
2161
|
if (isFullyCancelled(answers)) askAccounting.refund(args.subject);
|
|
1852
2162
|
const sanitised = vaultSensitiveAnswers(args.questions, answers, secretVault);
|
|
1853
2163
|
logToFile(`wizard_ask: resolved ${Object.keys(answers).length} answer(s) for ${args.questions.length} question(s)`);
|
|
@@ -2032,31 +2342,6 @@ function classifyToolToStage(toolName) {
|
|
|
2032
2342
|
return null;
|
|
2033
2343
|
}
|
|
2034
2344
|
//#endregion
|
|
2035
|
-
//#region src/lib/agent/signals.ts
|
|
2036
|
-
/**
|
|
2037
|
-
* Agent signal vocabulary — the marker strings the agent emits and the error
|
|
2038
|
-
* taxonomy the runner returns. Kept as a dependency-free leaf module so both
|
|
2039
|
-
* `agent-interface.ts` and `output-signals.ts` can import it without a cycle.
|
|
2040
|
-
*/
|
|
2041
|
-
const AgentSignals = {
|
|
2042
|
-
STATUS: "[STATUS]",
|
|
2043
|
-
ERROR_MCP_MISSING: "[ERROR-MCP-MISSING]",
|
|
2044
|
-
ERROR_RESOURCE_MISSING: "[ERROR-RESOURCE-MISSING]",
|
|
2045
|
-
SKILL_INSTALL_FAILED: "[SKILL-INSTALL-FAILED]",
|
|
2046
|
-
ABORT: "[ABORT]",
|
|
2047
|
-
WIZARD_REMARK: "[WIZARD-REMARK]",
|
|
2048
|
-
BENCHMARK: "[BENCHMARK]",
|
|
2049
|
-
DASHBOARD_URL: "[DASHBOARD_URL]",
|
|
2050
|
-
NOTEBOOK_URL: "[NOTEBOOK_URL]"
|
|
2051
|
-
};
|
|
2052
|
-
/**
|
|
2053
|
-
* End-of-run reflection ask, shared by both harnesses so remarks are
|
|
2054
|
-
* comparable. The format clause comes FIRST and nothing trails the marker —
|
|
2055
|
-
* literal models (gpt-5-mini) echo whatever text follows it. The parser also
|
|
2056
|
-
* drops remarks that quote this instruction (see AgentOutputSignals.remark).
|
|
2057
|
-
*/
|
|
2058
|
-
const REMARK_INSTRUCTION = `Reply with a single line that starts with ${AgentSignals.WIZARD_REMARK} and no other lines. In that line, state briefly what information or guidance would have been useful to have in the integration prompt or documentation for this run — specifically anything that would have prevented tool failures, erroneous edits, or other wasted turns.`;
|
|
2059
|
-
//#endregion
|
|
2060
2345
|
//#region src/lib/agent/output-signals.ts
|
|
2061
2346
|
/**
|
|
2062
2347
|
* Parses the signal-bearing lines out of agent output and discards the rest.
|
|
@@ -2196,6 +2481,32 @@ const PROVIDER_ENV_NAMESPACE = /^(ANTHROPIC_|CLAUDE_CODE_)/;
|
|
|
2196
2481
|
*/
|
|
2197
2482
|
const BLOCKED_OFF_NAMESPACE_KEYS = new Set(["AWS_BEARER_TOKEN_BEDROCK"]);
|
|
2198
2483
|
/**
|
|
2484
|
+
* Host-orchestration values read only by the wizard process itself (via
|
|
2485
|
+
* `runtimeEnv` in src/env.ts). None of them is ever consumed by the spawned
|
|
2486
|
+
* agent subprocess — the `publish_handoff` MCP tool executes in the wizard's
|
|
2487
|
+
* own process — so the subprocess only ever loses attack surface:
|
|
2488
|
+
*
|
|
2489
|
+
* - `POSTHOG_HANDOFF_OUTPUT_PATH` names the host file the wizard writes the
|
|
2490
|
+
* agent's handoff report to. Handing it to the subprocess tells a
|
|
2491
|
+
* (prompt-injected) agent exactly which file its own report content lands
|
|
2492
|
+
* in, turning the write into a pre-plantable symlink/same-UID overwrite
|
|
2493
|
+
* target. The write itself refuses symlinks, but the agent has no business
|
|
2494
|
+
* knowing the destination at all.
|
|
2495
|
+
* - `POSTHOG_TASK_RUN_ID` / `POSTHOG_TASK_ID` identify the sandbox run and are
|
|
2496
|
+
* read by the wizard's analytics only; they let the agent fingerprint the
|
|
2497
|
+
* run directory where the handoff path typically sits.
|
|
2498
|
+
*
|
|
2499
|
+
* Deliberately NOT stripped: `POSTHOG_API_KEY` / `POSTHOG_HOST` — pre-existing
|
|
2500
|
+
* passthrough that the agent may rely on when writing the user's project key
|
|
2501
|
+
* into the project's own .env. Changing that disposition is a separate,
|
|
2502
|
+
* deliberate decision, not part of this hardening.
|
|
2503
|
+
*/
|
|
2504
|
+
const HOST_ONLY_ENV_KEYS = new Set([
|
|
2505
|
+
"POSTHOG_HANDOFF_OUTPUT_PATH",
|
|
2506
|
+
"POSTHOG_TASK_RUN_ID",
|
|
2507
|
+
"POSTHOG_TASK_ID"
|
|
2508
|
+
]);
|
|
2509
|
+
/**
|
|
2199
2510
|
* Credential / routing knobs that, set in an on-disk Claude **settings** `env`
|
|
2200
2511
|
* block, redirect the binary. A settings file is applied by the binary itself,
|
|
2201
2512
|
* so the subprocess-env strip below cannot remove it — `claude-settings.ts`
|
|
@@ -2255,10 +2566,11 @@ const BLOCKED_AGENT_ENV_PATTERNS = [/^CLAUDE_CODE_SKIP_.+_AUTH$/, /^ANTHROPIC_.+
|
|
|
2255
2566
|
/**
|
|
2256
2567
|
* True if `key` must NOT be inherited by the agent subprocess: anything in the
|
|
2257
2568
|
* provider namespace (the wizard re-injects its own values at the spawn site),
|
|
2258
|
-
*
|
|
2569
|
+
* the lone off-namespace credential, and host-only orchestration values the
|
|
2570
|
+
* subprocess never reads.
|
|
2259
2571
|
*/
|
|
2260
2572
|
function isBlockedAgentEnvKey(key) {
|
|
2261
|
-
return PROVIDER_ENV_NAMESPACE.test(key) || BLOCKED_OFF_NAMESPACE_KEYS.has(key);
|
|
2573
|
+
return PROVIDER_ENV_NAMESPACE.test(key) || BLOCKED_OFF_NAMESPACE_KEYS.has(key) || HOST_ONLY_ENV_KEYS.has(key);
|
|
2262
2574
|
}
|
|
2263
2575
|
/**
|
|
2264
2576
|
* Return a copy of `env` with the entire model-provider namespace removed, so
|
|
@@ -2693,17 +3005,23 @@ function isWarlockDisabled() {
|
|
|
2693
3005
|
return runtimeEnv("POSTHOG_WIZARD_WARLOCK_DISABLED") === "true";
|
|
2694
3006
|
}
|
|
2695
3007
|
/**
|
|
2696
|
-
* Build env for the SDK subprocess: process.env plus ANTHROPIC_CUSTOM_HEADERS
|
|
2697
|
-
*
|
|
2698
|
-
*
|
|
3008
|
+
* Build env for the SDK subprocess: process.env plus ANTHROPIC_CUSTOM_HEADERS.
|
|
3009
|
+
* The header shape follows the gateway edition. Legacy (Python gateway):
|
|
3010
|
+
* per-key `X-POSTHOG-PROPERTY-*`/`X-POSTHOG-FLAG-*` plus the explicit
|
|
3011
|
+
* `x-posthog-use-bedrock-fallback` opt-in. v2 (Go ai-gateway): one
|
|
3012
|
+
* `X-PostHog-Properties` JSON blob. Bedrock fallback is native there, and
|
|
3013
|
+
* per-key metadata headers are not read.
|
|
2699
3014
|
*/
|
|
2700
|
-
function buildAgentEnv(wizardMetadata, wizardFlags) {
|
|
3015
|
+
function buildAgentEnv(wizardMetadata, wizardFlags, auth) {
|
|
2701
3016
|
const headers = createCustomHeaders();
|
|
2702
|
-
headers.add("
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
3017
|
+
if (auth?.edition === "v2") headers.add("X-PostHog-Properties", buildWizardPropertiesBlob(wizardMetadata, wizardFlags, auth.teamId));
|
|
3018
|
+
else {
|
|
3019
|
+
headers.add("x-posthog-use-bedrock-fallback", "true");
|
|
3020
|
+
for (const [key, value] of Object.entries(wizardMetadata)) headers.add(key.startsWith("X-POSTHOG-PROPERTY-") ? key : `${POSTHOG_PROPERTY_HEADER_PREFIX}${key}`, value);
|
|
3021
|
+
for (const [flagKey, variant] of Object.entries(wizardFlags)) {
|
|
3022
|
+
if (!flagKey.toLowerCase().startsWith("wizard")) continue;
|
|
3023
|
+
headers.addFlag(flagKey, variant);
|
|
3024
|
+
}
|
|
2707
3025
|
}
|
|
2708
3026
|
const encoded = headers.encode();
|
|
2709
3027
|
logToFile("ANTHROPIC_CUSTOM_HEADERS", encoded);
|
|
@@ -2798,13 +3116,17 @@ async function initializeAgent(config, options) {
|
|
|
2798
3116
|
logToFile("Install directory:", options.installDir);
|
|
2799
3117
|
try {
|
|
2800
3118
|
process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = "true";
|
|
2801
|
-
const
|
|
3119
|
+
const auth = await gatewayAuth(config.host, config.posthogApiKey, config.programId);
|
|
3120
|
+
const gatewayUrl = auth.gatewayUrl;
|
|
2802
3121
|
process.env.ANTHROPIC_BASE_URL = gatewayUrl;
|
|
2803
|
-
process.env.ANTHROPIC_AUTH_TOKEN =
|
|
2804
|
-
process.env.CLAUDE_CODE_OAUTH_TOKEN =
|
|
3122
|
+
process.env.ANTHROPIC_AUTH_TOKEN = auth.token;
|
|
3123
|
+
process.env.CLAUDE_CODE_OAUTH_TOKEN = auth.token;
|
|
3124
|
+
logToFile("Gateway edition:", auth.edition);
|
|
2805
3125
|
const triageProvider = createTriageLLMProvider({
|
|
2806
3126
|
baseURL: gatewayUrl,
|
|
2807
|
-
authToken:
|
|
3127
|
+
authToken: auth.token,
|
|
3128
|
+
edition: auth.edition,
|
|
3129
|
+
teamId: auth.teamId,
|
|
2808
3130
|
wizardMetadata: {
|
|
2809
3131
|
...config.wizardMetadata ?? {},
|
|
2810
3132
|
call_type: "yara-triage"
|
|
@@ -2861,6 +3183,7 @@ async function initializeAgent(config, options) {
|
|
|
2861
3183
|
suppressTaskRender: !!config.orchestrator,
|
|
2862
3184
|
capture: config.capture,
|
|
2863
3185
|
triageProvider,
|
|
3186
|
+
gatewayAuth: auth,
|
|
2864
3187
|
program: config.integrationLabel,
|
|
2865
3188
|
sequence: config.orchestrator ? "orchestrator" : "linear"
|
|
2866
3189
|
};
|
|
@@ -3034,13 +3357,13 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3034
3357
|
},
|
|
3035
3358
|
env: {
|
|
3036
3359
|
...sanitizeAgentSubprocessEnv(process.env),
|
|
3037
|
-
ANTHROPIC_BASE_URL:
|
|
3038
|
-
ANTHROPIC_AUTH_TOKEN:
|
|
3039
|
-
CLAUDE_CODE_OAUTH_TOKEN:
|
|
3360
|
+
ANTHROPIC_BASE_URL: agentConfig.gatewayAuth.gatewayUrl,
|
|
3361
|
+
ANTHROPIC_AUTH_TOKEN: agentConfig.gatewayAuth.token,
|
|
3362
|
+
CLAUDE_CODE_OAUTH_TOKEN: agentConfig.gatewayAuth.token,
|
|
3040
3363
|
CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: "true",
|
|
3041
3364
|
POSTHOG_MCP_TOKEN: agentConfig.posthogApiKey,
|
|
3042
3365
|
MCP_CONNECTION_NONBLOCKING: "0",
|
|
3043
|
-
ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(agentConfig.wizardMetadata ?? {}, agentConfig.wizardFlags ?? {})
|
|
3366
|
+
ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(agentConfig.wizardMetadata ?? {}, agentConfig.wizardFlags ?? {}, agentConfig.gatewayAuth)
|
|
3044
3367
|
},
|
|
3045
3368
|
canUseTool: (toolName, input) => {
|
|
3046
3369
|
logToFile("canUseTool called:", {
|
|
@@ -3072,7 +3395,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3072
3395
|
if (options.debug) debug("CLI stderr:", data);
|
|
3073
3396
|
},
|
|
3074
3397
|
hooks: {
|
|
3075
|
-
PreToolUse: warlockDisabled ? [] : createPreToolUseYaraHooks(triageProvider),
|
|
3398
|
+
PreToolUse: warlockDisabled ? [] : createPreToolUseYaraHooks(triageProvider, onYaraTerminate),
|
|
3076
3399
|
PostToolUse: warlockDisabled ? [] : createPostToolUseYaraHooks(triageProvider, onYaraTerminate),
|
|
3077
3400
|
Stop: [{
|
|
3078
3401
|
hooks: [createStopHook(config?.additionalFeatureQueue ?? [], signals, config?.requestRemark ?? true)],
|
|
@@ -3119,7 +3442,14 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3119
3442
|
if (message.type === "assistant" && signals.hasApiErrorStatus(401)) {
|
|
3120
3443
|
signalDone();
|
|
3121
3444
|
spinner.stop("Authentication failed");
|
|
3122
|
-
const authError = buildAuthErrorContext(options.installDir,
|
|
3445
|
+
const authError = buildAuthErrorContext(options.installDir, agentConfig.gatewayAuth.gatewayUrl, os.homedir(), signals.apiKeySource);
|
|
3446
|
+
const authCode = classifyAuthFailure({
|
|
3447
|
+
hasSettingsConflict: authError.hasSettingsConflict,
|
|
3448
|
+
usingManagedLogin: authError.usingManagedLogin,
|
|
3449
|
+
apiKey: options.apiKey,
|
|
3450
|
+
gatewayRegion: authError.region,
|
|
3451
|
+
sessionRegion: options.cloudRegion
|
|
3452
|
+
});
|
|
3123
3453
|
logToFile("Agent error: 401, showing auth error screen", authError);
|
|
3124
3454
|
getUI().showAuthError({
|
|
3125
3455
|
hasSettingsConflict: authError.hasSettingsConflict,
|
|
@@ -3129,6 +3459,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3129
3459
|
logFilePath: getLogFilePath()
|
|
3130
3460
|
});
|
|
3131
3461
|
await wizardAbort({
|
|
3462
|
+
code: authCode,
|
|
3132
3463
|
message: "Authentication failed (401)",
|
|
3133
3464
|
error: new WizardError("Authentication failed", {
|
|
3134
3465
|
hasSettingsConflict: authError.hasSettingsConflict,
|
|
@@ -3138,7 +3469,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3138
3469
|
region: authError.region,
|
|
3139
3470
|
usingManagedLogin: authError.usingManagedLogin,
|
|
3140
3471
|
apiKeySource: authError.apiKeySource
|
|
3141
|
-
})
|
|
3472
|
+
}, authCode)
|
|
3142
3473
|
});
|
|
3143
3474
|
}
|
|
3144
3475
|
try {
|
|
@@ -3483,6 +3814,6 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
|
|
|
3483
3814
|
}
|
|
3484
3815
|
}
|
|
3485
3816
|
//#endregion
|
|
3486
|
-
export {
|
|
3817
|
+
export { installSkillById as A, MAX_ENV_KEY_SET as B, WIZARD_ASK_SUBJECT_DESCRIPTION as C, createAskAccounting as D, checkEnvKeys as E, templateEnvWriteRefusal as F, GATEWAY_PROVIDER as G, parseEnvKeyNames as H, vaultSensitiveAnswers as I, buildGatewayProvider as K, fetchWithRetry as L, normaliseAskSubject as M, resolveEnvPath as N, downloadSkill as O, resolveEnvSecretRefs as P, createWizardAskBridge as R, WIZARD_ASK_SENSITIVE_DESCRIPTION as S, WIZARD_TOOL_NAMES as T, toPromptSafeRelativePath as U, isEnvFileName as V, createTriageLLMProvider as W, PUBLISH_HANDOFF_TOOL_NAME as _, wizardCanUseTool as a, CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION as b, classifySettingsConflicts as c, sanitizeAgentSubprocessEnv as d, AgentOutputSignals as f, PUBLISH_HANDOFF_DESCRIPTION as g, PUBLISH_HANDOFF_CONTENT_DESCRIPTION as h, runAgent as i, mergeEnvValues as j, fetchSkillMenu as k, recoverOrphanedSettingsBackups as l, createSecretVault as m, buildRunTags as n, backupAndFixClaudeSettings as o, assembleCommandments as p, gatewayAuth as q, initializeAgent as r, checkAllSettingsConflicts as s, buildAgentEnv as t, restoreClaudeSettings as u, publishHandoff as v, WIZARD_ASK_TOOL_DESCRIPTION as w, ENV_FILE_PATH_DESCRIPTION as x, CHECK_ENV_KEYS_DESCRIPTION as y, isFullyCancelled as z };
|
|
3487
3818
|
|
|
3488
|
-
//# sourceMappingURL=agent-interface-
|
|
3819
|
+
//# sourceMappingURL=agent-interface-CaEptZuu.js.map
|