@posthog/agent 2.3.259 → 2.3.263
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 +9 -2
- package/dist/agent.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -1
- package/dist/index.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 +23 -0
- package/dist/server/agent-server.js +223 -20
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +232 -21
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +1 -1
- package/src/acp-extensions.ts +3 -0
- package/src/adapters/claude/permissions/permission-handlers.ts +11 -5
- package/src/server/agent-server.test.ts +140 -7
- package/src/server/agent-server.ts +317 -29
- package/src/server/bin.ts +13 -0
- package/src/server/question-relay.test.ts +34 -5
- package/src/server/schemas.test.ts +52 -0
- package/src/server/schemas.ts +16 -0
- package/src/server/types.ts +1 -0
package/dist/server/bin.cjs
CHANGED
|
@@ -5683,7 +5683,7 @@ var import_hono = require("hono");
|
|
|
5683
5683
|
// package.json
|
|
5684
5684
|
var package_default = {
|
|
5685
5685
|
name: "@posthog/agent",
|
|
5686
|
-
version: "2.3.
|
|
5686
|
+
version: "2.3.263",
|
|
5687
5687
|
repository: "https://github.com/PostHog/code",
|
|
5688
5688
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
5689
5689
|
exports: {
|
|
@@ -5844,7 +5844,9 @@ var POSTHOG_NOTIFICATIONS = {
|
|
|
5844
5844
|
/** Marks a boundary for log compaction */
|
|
5845
5845
|
COMPACT_BOUNDARY: "_posthog/compact_boundary",
|
|
5846
5846
|
/** Token usage update for a session turn */
|
|
5847
|
-
USAGE_UPDATE: "_posthog/usage_update"
|
|
5847
|
+
USAGE_UPDATE: "_posthog/usage_update",
|
|
5848
|
+
/** Response to a relayed permission request (plan approval, question) */
|
|
5849
|
+
PERMISSION_RESPONSE: "_posthog/permission_response"
|
|
5848
5850
|
};
|
|
5849
5851
|
function isNotification(method, notification) {
|
|
5850
5852
|
if (!method) return false;
|
|
@@ -8281,6 +8283,11 @@ async function canUseTool(context) {
|
|
|
8281
8283
|
if (planFileResult) {
|
|
8282
8284
|
return planFileResult;
|
|
8283
8285
|
}
|
|
8286
|
+
if (session.permissionMode === "plan") {
|
|
8287
|
+
const message = `This tool is not available in plan mode. Write your plan to a file in ${getClaudePlansDir()} and call ExitPlanMode when ready.`;
|
|
8288
|
+
await emitToolDenial(context, message);
|
|
8289
|
+
return { behavior: "deny", message, interrupt: false };
|
|
8290
|
+
}
|
|
8284
8291
|
return handleDefaultPermissionFlow(context);
|
|
8285
8292
|
}
|
|
8286
8293
|
|
|
@@ -12219,13 +12226,27 @@ var userMessageParamsSchema = import_v4.z.object({
|
|
|
12219
12226
|
import_v4.z.array(import_v4.z.record(import_v4.z.string(), import_v4.z.unknown())).min(1, "Content is required")
|
|
12220
12227
|
])
|
|
12221
12228
|
});
|
|
12229
|
+
var permissionResponseParamsSchema = import_v4.z.object({
|
|
12230
|
+
requestId: import_v4.z.string().min(1, "requestId is required"),
|
|
12231
|
+
optionId: import_v4.z.string().min(1, "optionId is required"),
|
|
12232
|
+
customInput: import_v4.z.string().optional(),
|
|
12233
|
+
answers: import_v4.z.record(import_v4.z.string(), import_v4.z.string()).optional()
|
|
12234
|
+
});
|
|
12235
|
+
var setConfigOptionParamsSchema = import_v4.z.object({
|
|
12236
|
+
configId: import_v4.z.string().min(1, "configId is required"),
|
|
12237
|
+
value: import_v4.z.string().min(1, "value is required")
|
|
12238
|
+
});
|
|
12222
12239
|
var commandParamsSchemas = {
|
|
12223
12240
|
user_message: userMessageParamsSchema,
|
|
12224
12241
|
"posthog/user_message": userMessageParamsSchema,
|
|
12225
12242
|
cancel: import_v4.z.object({}).optional(),
|
|
12226
12243
|
"posthog/cancel": import_v4.z.object({}).optional(),
|
|
12227
12244
|
close: import_v4.z.object({}).optional(),
|
|
12228
|
-
"posthog/close": import_v4.z.object({}).optional()
|
|
12245
|
+
"posthog/close": import_v4.z.object({}).optional(),
|
|
12246
|
+
permission_response: permissionResponseParamsSchema,
|
|
12247
|
+
"posthog/permission_response": permissionResponseParamsSchema,
|
|
12248
|
+
set_config_option: setConfigOptionParamsSchema,
|
|
12249
|
+
"posthog/set_config_option": setConfigOptionParamsSchema
|
|
12229
12250
|
};
|
|
12230
12251
|
function validateCommandParams(method, params) {
|
|
12231
12252
|
const schema = commandParamsSchemas[method] ?? commandParamsSchemas[method.replace("posthog/", "")];
|
|
@@ -12342,6 +12363,7 @@ var AgentServer = class _AgentServer {
|
|
|
12342
12363
|
// causing a second session to be created and duplicate Slack messages to be sent.
|
|
12343
12364
|
initializationPromise = null;
|
|
12344
12365
|
pendingEvents = [];
|
|
12366
|
+
pendingPermissions = /* @__PURE__ */ new Map();
|
|
12345
12367
|
detachSseController(controller) {
|
|
12346
12368
|
if (this.session?.sseController === controller) {
|
|
12347
12369
|
this.session.sseController = null;
|
|
@@ -12379,6 +12401,9 @@ var AgentServer = class _AgentServer {
|
|
|
12379
12401
|
getEffectiveMode(payload) {
|
|
12380
12402
|
return payload.mode ?? this.config.mode;
|
|
12381
12403
|
}
|
|
12404
|
+
getSessionPermissionMode() {
|
|
12405
|
+
return this.session?.permissionMode ?? "default";
|
|
12406
|
+
}
|
|
12382
12407
|
createApp() {
|
|
12383
12408
|
const app = new import_hono.Hono();
|
|
12384
12409
|
app.get("/health", (c) => {
|
|
@@ -12423,6 +12448,7 @@ var AgentServer = class _AgentServer {
|
|
|
12423
12448
|
await this.initializeSession(payload, sseController);
|
|
12424
12449
|
} else {
|
|
12425
12450
|
this.session.sseController = sseController;
|
|
12451
|
+
this.session.hasDesktopConnected = true;
|
|
12426
12452
|
this.replayPendingEvents();
|
|
12427
12453
|
}
|
|
12428
12454
|
this.sendSseEvent(sseController, {
|
|
@@ -12612,12 +12638,9 @@ var AgentServer = class _AgentServer {
|
|
|
12612
12638
|
prompt,
|
|
12613
12639
|
...this.detectedPrUrl && {
|
|
12614
12640
|
_meta: {
|
|
12615
|
-
|
|
12616
|
-
|
|
12617
|
-
|
|
12618
|
-
1. Check out the existing PR branch with \`gh pr checkout ${this.detectedPrUrl}\`
|
|
12619
|
-
2. Make changes, commit, and push to that branch
|
|
12620
|
-
You MUST NOT create a new branch, close the existing PR, or create a new PR.`
|
|
12641
|
+
// Keep the live-session PR override aligned with the startup
|
|
12642
|
+
// prompt policy so non-Slack runs remain review-first.
|
|
12643
|
+
prContext: this.buildDetectedPrContext(this.detectedPrUrl)
|
|
12621
12644
|
}
|
|
12622
12645
|
}
|
|
12623
12646
|
});
|
|
@@ -12665,6 +12688,43 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
|
|
|
12665
12688
|
await this.cleanupSession();
|
|
12666
12689
|
return { closed: true };
|
|
12667
12690
|
}
|
|
12691
|
+
case "posthog/set_config_option":
|
|
12692
|
+
case "set_config_option": {
|
|
12693
|
+
const configId = params.configId;
|
|
12694
|
+
const value = params.value;
|
|
12695
|
+
this.logger.info("Set config option requested", { configId, value });
|
|
12696
|
+
const result = await this.session.clientConnection.setSessionConfigOption({
|
|
12697
|
+
sessionId: this.session.acpSessionId,
|
|
12698
|
+
configId,
|
|
12699
|
+
value
|
|
12700
|
+
});
|
|
12701
|
+
return {
|
|
12702
|
+
configOptions: result.configOptions
|
|
12703
|
+
};
|
|
12704
|
+
}
|
|
12705
|
+
case POSTHOG_NOTIFICATIONS.PERMISSION_RESPONSE:
|
|
12706
|
+
case "permission_response": {
|
|
12707
|
+
const requestId = params.requestId;
|
|
12708
|
+
const optionId = params.optionId;
|
|
12709
|
+
const customInput = params.customInput;
|
|
12710
|
+
const answers = params.answers;
|
|
12711
|
+
this.logger.info("Permission response received", {
|
|
12712
|
+
requestId,
|
|
12713
|
+
optionId
|
|
12714
|
+
});
|
|
12715
|
+
const resolved = this.resolvePermission(
|
|
12716
|
+
requestId,
|
|
12717
|
+
optionId,
|
|
12718
|
+
customInput,
|
|
12719
|
+
answers
|
|
12720
|
+
);
|
|
12721
|
+
if (!resolved) {
|
|
12722
|
+
throw new Error(
|
|
12723
|
+
`No pending permission request found for id: ${requestId}`
|
|
12724
|
+
);
|
|
12725
|
+
}
|
|
12726
|
+
return { resolved: true };
|
|
12727
|
+
}
|
|
12668
12728
|
default:
|
|
12669
12729
|
throw new Error(`Unknown method: ${method}`);
|
|
12670
12730
|
}
|
|
@@ -12783,6 +12843,8 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
|
|
|
12783
12843
|
if (prUrl) {
|
|
12784
12844
|
this.detectedPrUrl = prUrl;
|
|
12785
12845
|
}
|
|
12846
|
+
const runState = preTaskRun?.state;
|
|
12847
|
+
const initialPermissionMode = typeof runState?.initial_permission_mode === "string" ? runState.initial_permission_mode : "bypassPermissions";
|
|
12786
12848
|
const sessionResponse = await clientConnection.newSession({
|
|
12787
12849
|
cwd: this.config.repositoryPath ?? "/tmp/workspace",
|
|
12788
12850
|
mcpServers: this.config.mcpServers ?? [],
|
|
@@ -12792,6 +12854,7 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
|
|
|
12792
12854
|
systemPrompt: this.buildSessionSystemPrompt(prUrl),
|
|
12793
12855
|
allowedDomains: this.config.allowedDomains,
|
|
12794
12856
|
jsonSchema: preTask?.json_schema ?? null,
|
|
12857
|
+
permissionMode: initialPermissionMode,
|
|
12795
12858
|
...this.config.claudeCode?.plugins?.length && {
|
|
12796
12859
|
claudeCode: {
|
|
12797
12860
|
options: {
|
|
@@ -12814,7 +12877,9 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
|
|
|
12814
12877
|
treeTracker,
|
|
12815
12878
|
sseController,
|
|
12816
12879
|
deviceInfo,
|
|
12817
|
-
logWriter
|
|
12880
|
+
logWriter,
|
|
12881
|
+
permissionMode: initialPermissionMode,
|
|
12882
|
+
hasDesktopConnected: sseController !== null
|
|
12818
12883
|
};
|
|
12819
12884
|
this.logger = new Logger({
|
|
12820
12885
|
debug: true,
|
|
@@ -12828,6 +12893,7 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
|
|
|
12828
12893
|
this.logger.info(
|
|
12829
12894
|
`Agent version: ${this.config.version ?? package_default.version}`
|
|
12830
12895
|
);
|
|
12896
|
+
this.logger.info(`Initial permission mode: ${initialPermissionMode}`);
|
|
12831
12897
|
this.posthogAPI.updateTaskRun(payload.task_id, payload.run_id, {
|
|
12832
12898
|
status: "in_progress"
|
|
12833
12899
|
}).catch(
|
|
@@ -13077,13 +13143,38 @@ ${toolSummary}`);
|
|
|
13077
13143
|
}
|
|
13078
13144
|
return { append: cloudAppend };
|
|
13079
13145
|
}
|
|
13146
|
+
getCloudInteractionOrigin() {
|
|
13147
|
+
return process.env.POSTHOG_CODE_INTERACTION_ORIGIN ?? process.env.CODE_INTERACTION_ORIGIN ?? process.env.TWIG_INTERACTION_ORIGIN;
|
|
13148
|
+
}
|
|
13149
|
+
/**
|
|
13150
|
+
* Slack-origin cloud runs auto-publish by default. Every other origin is
|
|
13151
|
+
* review-first unless the user explicitly asks, and createPr=false always
|
|
13152
|
+
* disables publishing.
|
|
13153
|
+
*/
|
|
13154
|
+
shouldAutoPublishCloudChanges() {
|
|
13155
|
+
return this.getCloudInteractionOrigin() === "slack" && this.config.createPr !== false;
|
|
13156
|
+
}
|
|
13157
|
+
buildDetectedPrContext(prUrl) {
|
|
13158
|
+
if (!this.shouldAutoPublishCloudChanges()) {
|
|
13159
|
+
return `An open pull request already exists: ${prUrl}
|
|
13160
|
+
Use that PR as context if it is helpful, but stop with local changes ready for review.
|
|
13161
|
+
Do NOT create commits, push to the PR branch, update the pull request, create a new branch, or create a new pull request unless the user explicitly asks.`;
|
|
13162
|
+
}
|
|
13163
|
+
return `IMPORTANT \u2014 OVERRIDE PREVIOUS INSTRUCTIONS ABOUT CREATING BRANCHES/PRs.
|
|
13164
|
+
You already have an open pull request: ${prUrl}
|
|
13165
|
+
You MUST:
|
|
13166
|
+
1. Check out the existing PR branch with \`gh pr checkout ${prUrl}\`
|
|
13167
|
+
2. Make changes, commit, and push to that branch
|
|
13168
|
+
You MUST NOT create a new branch, close the existing PR, or create a new PR.`;
|
|
13169
|
+
}
|
|
13080
13170
|
buildCloudSystemPrompt(prUrl) {
|
|
13081
13171
|
const taskId = this.config.taskId;
|
|
13172
|
+
const shouldAutoCreatePr = this.shouldAutoPublishCloudChanges();
|
|
13082
13173
|
const attributionInstructions = `
|
|
13083
13174
|
## Attribution
|
|
13084
13175
|
Do NOT use Claude Code's default attribution (no "Co-Authored-By" trailers, no "Generated with [Claude Code]" lines).
|
|
13085
13176
|
|
|
13086
|
-
|
|
13177
|
+
If you create a commit, add the following trailers to the commit message (after a blank line at the end):
|
|
13087
13178
|
Generated-By: PostHog Code
|
|
13088
13179
|
Task-Id: ${taskId}
|
|
13089
13180
|
|
|
@@ -13098,6 +13189,20 @@ EOF
|
|
|
13098
13189
|
)"
|
|
13099
13190
|
\`\`\``;
|
|
13100
13191
|
if (prUrl) {
|
|
13192
|
+
if (!shouldAutoCreatePr) {
|
|
13193
|
+
return `
|
|
13194
|
+
# Cloud Task Execution
|
|
13195
|
+
|
|
13196
|
+
This task already has an open pull request: ${prUrl}
|
|
13197
|
+
|
|
13198
|
+
Do the requested work, but stop with local changes ready for review.
|
|
13199
|
+
|
|
13200
|
+
Important:
|
|
13201
|
+
- Do NOT create new commits, push to the branch, or update the pull request unless the user explicitly asks.
|
|
13202
|
+
- Do NOT create a new branch or a new pull request.
|
|
13203
|
+
${attributionInstructions}
|
|
13204
|
+
`;
|
|
13205
|
+
}
|
|
13101
13206
|
return `
|
|
13102
13207
|
# Cloud Task Execution
|
|
13103
13208
|
|
|
@@ -13131,6 +13236,17 @@ When the user asks for code changes or software engineering tasks:
|
|
|
13131
13236
|
Important:
|
|
13132
13237
|
- Do NOT create branches, commits, or pull requests in this mode.
|
|
13133
13238
|
- Prefer using MCP tools to answer questions with real data over giving generic advice.
|
|
13239
|
+
`;
|
|
13240
|
+
}
|
|
13241
|
+
if (!shouldAutoCreatePr) {
|
|
13242
|
+
return `
|
|
13243
|
+
# Cloud Task Execution
|
|
13244
|
+
|
|
13245
|
+
Do the requested work, but stop with local changes ready for review.
|
|
13246
|
+
|
|
13247
|
+
Important:
|
|
13248
|
+
- Do NOT create a branch, commit, push, or open a pull request unless the user explicitly asks.
|
|
13249
|
+
${attributionInstructions}
|
|
13134
13250
|
`;
|
|
13135
13251
|
}
|
|
13136
13252
|
return `
|
|
@@ -13239,32 +13355,73 @@ ${attributionInstructions}
|
|
|
13239
13355
|
LLM_GATEWAY_URL: gatewayUrl
|
|
13240
13356
|
});
|
|
13241
13357
|
}
|
|
13358
|
+
buildSlackQuestionRelayResponse(payload, toolMeta2) {
|
|
13359
|
+
this.relaySlackQuestion(payload, toolMeta2);
|
|
13360
|
+
return {
|
|
13361
|
+
outcome: { outcome: "cancelled" },
|
|
13362
|
+
_meta: {
|
|
13363
|
+
message: "This question has been relayed to the Slack thread where this task originated. The user will reply there. Do NOT re-ask the question or pick an answer yourself. Simply let the user know you are waiting for their reply."
|
|
13364
|
+
}
|
|
13365
|
+
};
|
|
13366
|
+
}
|
|
13367
|
+
shouldBlockPublishPermission(params) {
|
|
13368
|
+
if (this.config.createPr !== false) {
|
|
13369
|
+
return false;
|
|
13370
|
+
}
|
|
13371
|
+
const meta = params.toolCall?._meta && typeof params.toolCall._meta === "object" && !Array.isArray(params.toolCall._meta) ? params.toolCall._meta : null;
|
|
13372
|
+
const rawInput = params.toolCall?.rawInput && typeof params.toolCall.rawInput === "object" && !Array.isArray(params.toolCall.rawInput) ? params.toolCall.rawInput : null;
|
|
13373
|
+
const toolName = typeof meta?.toolName === "string" ? meta.toolName : null;
|
|
13374
|
+
const command = typeof rawInput?.command === "string" ? rawInput.command : null;
|
|
13375
|
+
return Boolean(
|
|
13376
|
+
toolName && (toolName === "Bash" || toolName.includes("bash")) && command && /\bgit\s+push\b|\bgh\s+pr\s+(create|edit|ready|merge)\b/.test(command)
|
|
13377
|
+
);
|
|
13378
|
+
}
|
|
13242
13379
|
createCloudClient(payload) {
|
|
13243
13380
|
const mode = this.getEffectiveMode(payload);
|
|
13244
|
-
const interactionOrigin = process.env.CODE_INTERACTION_ORIGIN ?? process.env.TWIG_INTERACTION_ORIGIN;
|
|
13381
|
+
const interactionOrigin = process.env.POSTHOG_CODE_INTERACTION_ORIGIN ?? process.env.CODE_INTERACTION_ORIGIN ?? process.env.TWIG_INTERACTION_ORIGIN;
|
|
13245
13382
|
return {
|
|
13246
13383
|
requestPermission: async (params) => {
|
|
13247
13384
|
this.logger.debug("Permission request", {
|
|
13248
13385
|
mode,
|
|
13249
13386
|
interactionOrigin,
|
|
13387
|
+
kind: params.toolCall?.kind,
|
|
13250
13388
|
options: params.options
|
|
13251
13389
|
});
|
|
13252
13390
|
const allowOption = params.options.find(
|
|
13253
13391
|
(o) => o.kind === "allow_once" || o.kind === "allow_always"
|
|
13254
13392
|
);
|
|
13255
13393
|
const selectedOptionId = allowOption?.optionId ?? params.options[0].optionId;
|
|
13394
|
+
const codeToolKind = params.toolCall?._meta?.codeToolKind;
|
|
13395
|
+
const isPlanApproval = params.toolCall?.kind === "switch_mode";
|
|
13256
13396
|
if (interactionOrigin === "slack") {
|
|
13257
|
-
const codeToolKind = params.toolCall?._meta?.codeToolKind;
|
|
13258
13397
|
if (codeToolKind === "question") {
|
|
13259
|
-
this.
|
|
13260
|
-
|
|
13261
|
-
|
|
13262
|
-
|
|
13263
|
-
|
|
13264
|
-
|
|
13265
|
-
|
|
13398
|
+
return this.buildSlackQuestionRelayResponse(
|
|
13399
|
+
payload,
|
|
13400
|
+
params.toolCall?._meta
|
|
13401
|
+
);
|
|
13402
|
+
}
|
|
13403
|
+
}
|
|
13404
|
+
{
|
|
13405
|
+
const isQuestion = codeToolKind === "question";
|
|
13406
|
+
const sessionPermissionMode = this.getSessionPermissionMode();
|
|
13407
|
+
const needsRelay = isQuestion || isPlanApproval || sessionPermissionMode === "default";
|
|
13408
|
+
if (needsRelay && this.session?.hasDesktopConnected) {
|
|
13409
|
+
this.logger.info("Relaying permission to connected client", {
|
|
13410
|
+
kind: params.toolCall?.kind,
|
|
13411
|
+
isQuestion,
|
|
13412
|
+
sessionPermissionMode
|
|
13413
|
+
});
|
|
13414
|
+
return this.relayPermissionToClient(params);
|
|
13266
13415
|
}
|
|
13267
13416
|
}
|
|
13417
|
+
if (this.shouldBlockPublishPermission(params)) {
|
|
13418
|
+
return {
|
|
13419
|
+
outcome: { outcome: "cancelled" },
|
|
13420
|
+
_meta: {
|
|
13421
|
+
message: "This run is configured to stop before publishing. Do not push commits or create/update pull requests unless the user explicitly asks."
|
|
13422
|
+
}
|
|
13423
|
+
};
|
|
13424
|
+
}
|
|
13268
13425
|
return {
|
|
13269
13426
|
outcome: {
|
|
13270
13427
|
outcome: "selected",
|
|
@@ -13276,6 +13433,12 @@ ${attributionInstructions}
|
|
|
13276
13433
|
this.logger.debug("Extension notification", { method, params });
|
|
13277
13434
|
},
|
|
13278
13435
|
sessionUpdate: async (params) => {
|
|
13436
|
+
if (params.update?.sessionUpdate === "current_mode_update" && typeof params.update?.currentModeId === "string" && this.session) {
|
|
13437
|
+
this.session.permissionMode = params.update.currentModeId;
|
|
13438
|
+
this.logger.info("Permission mode updated", {
|
|
13439
|
+
mode: params.update.currentModeId
|
|
13440
|
+
});
|
|
13441
|
+
}
|
|
13279
13442
|
if (params.update?.sessionUpdate === "tool_call_update") {
|
|
13280
13443
|
const meta = params.update?._meta?.claudeCode;
|
|
13281
13444
|
const toolName = meta?.toolName;
|
|
@@ -13454,6 +13617,13 @@ ${attributionInstructions}
|
|
|
13454
13617
|
} catch (error) {
|
|
13455
13618
|
this.logger.error("Failed to flush session logs", error);
|
|
13456
13619
|
}
|
|
13620
|
+
for (const [, pending] of this.pendingPermissions) {
|
|
13621
|
+
pending.resolve({
|
|
13622
|
+
outcome: { outcome: "selected", optionId: "reject" },
|
|
13623
|
+
_meta: { customInput: "Session is shutting down." }
|
|
13624
|
+
});
|
|
13625
|
+
}
|
|
13626
|
+
this.pendingPermissions.clear();
|
|
13457
13627
|
try {
|
|
13458
13628
|
await this.session.acpConnection.cleanup();
|
|
13459
13629
|
} catch (error) {
|
|
@@ -13531,6 +13701,39 @@ ${attributionInstructions}
|
|
|
13531
13701
|
this.detachSseController(controller);
|
|
13532
13702
|
}
|
|
13533
13703
|
}
|
|
13704
|
+
/**
|
|
13705
|
+
* Relay a permission request (e.g., plan approval) to the connected desktop
|
|
13706
|
+
* app via SSE and wait for a response via the `/command` endpoint.
|
|
13707
|
+
*
|
|
13708
|
+
* The promise waits indefinitely — if SSE is disconnected, the event is
|
|
13709
|
+
* buffered by broadcastEvent and replayed when the client reconnects. Session
|
|
13710
|
+
* cleanup force-resolves all pending permissions, so there is no leak.
|
|
13711
|
+
*/
|
|
13712
|
+
relayPermissionToClient(params) {
|
|
13713
|
+
const requestId = crypto.randomUUID();
|
|
13714
|
+
this.broadcastEvent({
|
|
13715
|
+
type: "permission_request",
|
|
13716
|
+
requestId,
|
|
13717
|
+
options: params.options,
|
|
13718
|
+
toolCall: params.toolCall
|
|
13719
|
+
});
|
|
13720
|
+
return new Promise((resolve4) => {
|
|
13721
|
+
this.pendingPermissions.set(requestId, { resolve: resolve4 });
|
|
13722
|
+
});
|
|
13723
|
+
}
|
|
13724
|
+
resolvePermission(requestId, optionId, customInput, answers) {
|
|
13725
|
+
const pending = this.pendingPermissions.get(requestId);
|
|
13726
|
+
if (!pending) return false;
|
|
13727
|
+
this.pendingPermissions.delete(requestId);
|
|
13728
|
+
const meta = {};
|
|
13729
|
+
if (customInput) meta.customInput = customInput;
|
|
13730
|
+
if (answers) meta.answers = answers;
|
|
13731
|
+
pending.resolve({
|
|
13732
|
+
outcome: { outcome: "selected", optionId },
|
|
13733
|
+
...Object.keys(meta).length > 0 ? { _meta: meta } : {}
|
|
13734
|
+
});
|
|
13735
|
+
return true;
|
|
13736
|
+
}
|
|
13534
13737
|
};
|
|
13535
13738
|
|
|
13536
13739
|
// src/server/bin.ts
|
|
@@ -13549,6 +13752,12 @@ var envSchema = import_v42.z.object({
|
|
|
13549
13752
|
}).regex(/^\d+$/, "POSTHOG_PROJECT_ID must be a numeric string").transform((val) => parseInt(val, 10))
|
|
13550
13753
|
});
|
|
13551
13754
|
var program = new import_commander.Command();
|
|
13755
|
+
function parseBooleanOption(raw, flag) {
|
|
13756
|
+
if (raw === void 0) return void 0;
|
|
13757
|
+
if (raw === "true") return true;
|
|
13758
|
+
if (raw === "false") return false;
|
|
13759
|
+
program.error(`${flag} must be either "true" or "false"`);
|
|
13760
|
+
}
|
|
13552
13761
|
function parseJsonOption(raw, schema, flag) {
|
|
13553
13762
|
if (!raw) return void 0;
|
|
13554
13763
|
let parsed;
|
|
@@ -13572,7 +13781,7 @@ program.name("agent-server").description("PostHog cloud agent server - runs in s
|
|
|
13572
13781
|
).option("--repositoryPath <path>", "Path to the repository").requiredOption("--taskId <id>", "Task ID").requiredOption("--runId <id>", "Task run ID").option(
|
|
13573
13782
|
"--mcpServers <json>",
|
|
13574
13783
|
"MCP servers config as JSON array (ACP McpServer[] format)"
|
|
13575
|
-
).option("--baseBranch <branch>", "Base branch for PR creation").option(
|
|
13784
|
+
).option("--createPr <boolean>", "Whether this run may publish changes").option("--baseBranch <branch>", "Base branch for PR creation").option(
|
|
13576
13785
|
"--claudeCodeConfig <json>",
|
|
13577
13786
|
"Claude Code config as JSON (systemPrompt, systemPromptAppend, plugins)"
|
|
13578
13787
|
).option(
|
|
@@ -13588,6 +13797,7 @@ ${errors}`);
|
|
|
13588
13797
|
}
|
|
13589
13798
|
const env = envResult.data;
|
|
13590
13799
|
const mode = options.mode === "background" ? "background" : "interactive";
|
|
13800
|
+
const createPr = parseBooleanOption(options.createPr, "--createPr");
|
|
13591
13801
|
const mcpServers = parseJsonOption(
|
|
13592
13802
|
options.mcpServers,
|
|
13593
13803
|
mcpServersSchema,
|
|
@@ -13609,6 +13819,7 @@ ${errors}`);
|
|
|
13609
13819
|
mode,
|
|
13610
13820
|
taskId: options.taskId,
|
|
13611
13821
|
runId: options.runId,
|
|
13822
|
+
createPr,
|
|
13612
13823
|
mcpServers,
|
|
13613
13824
|
baseBranch: options.baseBranch,
|
|
13614
13825
|
claudeCode,
|