lody 0.103.0 → 0.104.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.
@@ -0,0 +1,1152 @@
1
+ import { createInterface } from "node:readline";
2
+ import { randomUUID } from "node:crypto";
3
+ import "node:fs";
4
+ import { c as isLodySubagentOutput, S as SessionUsageAccumulator, e as supportsLodySubagentEvents, d as LODY_SUBAGENT_EVENT_METHOD, L as LODY_EXTENSION_METHODS } from "./chunks/subagent-events-BJ9JwZva.js";
5
+ import { spawn } from "node:child_process";
6
+ const FIELDS = [
7
+ "sidekickToolCallMeta",
8
+ "sidekickToolCallIdPrefix",
9
+ "subagentContextMeta",
10
+ "subagentStartedMeta",
11
+ "subagentCompletedMeta",
12
+ "subagentSupportClientCapability",
13
+ "rootAgentId",
14
+ "sidekickAgentId",
15
+ "toolNameMeta",
16
+ "inferenceToolNameMeta",
17
+ "compactionNotificationMethod",
18
+ "compactionSessionIdField",
19
+ "compactionStatusField",
20
+ "compactionSummaryField",
21
+ "compactionStartedStatus",
22
+ "compactionCompletedStatus",
23
+ "compactionFailedStatus",
24
+ "compactionManualCommand",
25
+ "elicitationAllowOtherMeta",
26
+ "usageInputTokensMeta",
27
+ "usageOutputTokensMeta",
28
+ "usageCachedReadTokensMeta",
29
+ "usageCachedWriteTokensMeta",
30
+ "usageTotalCreditCostMeta",
31
+ "usageTotalAcuCostMeta",
32
+ "usageResponseDimensionsMeta"
33
+ ];
34
+ function loadPrivateWireContract() {
35
+ const raw = JSON.parse('{\n "officialRuntime": {\n "package": "devin",\n "version": "3000.11.3",\n "minimumSupportedVersion": "3000.11.1"\n },\n "privateWireContract": {\n "sidekickToolCallMeta": "cognition.ai/sidekick",\n "sidekickToolCallIdPrefix": "sk::",\n "subagentContextMeta": "cognition.ai/subagent_context",\n "subagentStartedMeta": "cognition.ai/subagent_started",\n "subagentCompletedMeta": "cognition.ai/subagent_completed",\n "subagentSupportClientCapability": "cognition.ai/subagentSupport",\n "rootAgentId": "root",\n "sidekickAgentId": "sidekick",\n "toolNameMeta": "cognition.ai/toolName",\n "inferenceToolNameMeta": "cognition.ai/inferenceToolName",\n "compactionNotificationMethod": "_cognition.ai/compaction",\n "compactionSessionIdField": "sessionId",\n "compactionStatusField": "status",\n "compactionSummaryField": "summary",\n "compactionStartedStatus": "started",\n "compactionCompletedStatus": "completed",\n "compactionFailedStatus": "failed",\n "compactionManualCommand": "/compact",\n "elicitationAllowOtherMeta": "cognition.ai/allowOther",\n "usageInputTokensMeta": "cognition.ai/inputTokens",\n "usageOutputTokensMeta": "cognition.ai/outputTokens",\n "usageCachedReadTokensMeta": "cognition.ai/cachedReadTokens",\n "usageCachedWriteTokensMeta": "cognition.ai/cachedWriteTokens",\n "usageTotalCreditCostMeta": "cognition.ai/totalCreditCost",\n "usageTotalAcuCostMeta": "cognition.ai/totalAcuCost",\n "usageResponseDimensionsMeta": "cognition.ai/responseDimensions"\n }\n}\n');
36
+ const section = raw["privateWireContract"];
37
+ if (typeof section !== "object" || section === null || Array.isArray(section)) {
38
+ throw new Error("runtime-manifest.json: privateWireContract must be an object");
39
+ }
40
+ const contract = {};
41
+ for (const field of FIELDS) {
42
+ const value = section[field];
43
+ if (typeof value !== "string" || !value) {
44
+ throw new Error(`runtime-manifest.json: privateWireContract.${field} must be a non-empty string`);
45
+ }
46
+ contract[field] = value;
47
+ }
48
+ return contract;
49
+ }
50
+ const privateWireContract = loadPrivateWireContract();
51
+ const ALLOW_OTHER_META = privateWireContract.elicitationAllowOtherMeta;
52
+ function isRecord$3(value) {
53
+ return typeof value === "object" && value !== null && !Array.isArray(value);
54
+ }
55
+ function clientSupportsLodyElicitation(capabilities) {
56
+ if (!isRecord$3(capabilities))
57
+ return false;
58
+ const meta = capabilities["_meta"];
59
+ if (!isRecord$3(meta))
60
+ return false;
61
+ const lody = meta["lody"];
62
+ if (!isRecord$3(lody))
63
+ return false;
64
+ const elicitation = lody["elicitation"];
65
+ return isRecord$3(elicitation) && elicitation["version"] === 1;
66
+ }
67
+ function extractOptions(entries) {
68
+ if (!Array.isArray(entries))
69
+ return [];
70
+ const options = [];
71
+ for (const entry of entries) {
72
+ if (typeof entry === "string") {
73
+ options.push({ label: entry });
74
+ continue;
75
+ }
76
+ if (!isRecord$3(entry))
77
+ continue;
78
+ const value = entry["const"];
79
+ const title = entry["title"];
80
+ const description = entry["description"];
81
+ const label = typeof value === "string" ? value : typeof title === "string" ? title : void 0;
82
+ if (label === void 0)
83
+ continue;
84
+ const option = { label };
85
+ const detail = typeof value === "string" ? typeof title === "string" ? title : typeof description === "string" ? description : void 0 : typeof description === "string" ? description : void 0;
86
+ if (detail !== void 0)
87
+ option.description = detail;
88
+ options.push(option);
89
+ }
90
+ return options;
91
+ }
92
+ function questionShape(property) {
93
+ if (property["type"] === "array") {
94
+ const items = isRecord$3(property["items"]) ? property["items"] : {};
95
+ return {
96
+ multiSelect: true,
97
+ options: extractOptions(items["anyOf"] ?? items["oneOf"] ?? items["enum"])
98
+ };
99
+ }
100
+ return {
101
+ multiSelect: false,
102
+ options: extractOptions(property["oneOf"] ?? property["anyOf"] ?? property["enum"])
103
+ };
104
+ }
105
+ function hasOptions(property) {
106
+ if (property["type"] === "array") {
107
+ const items = isRecord$3(property["items"]) ? property["items"] : {};
108
+ return Array.isArray(items["anyOf"]) || Array.isArray(items["oneOf"]) || Array.isArray(items["enum"]);
109
+ }
110
+ return Array.isArray(property["oneOf"]) || Array.isArray(property["anyOf"]) || Array.isArray(property["enum"]);
111
+ }
112
+ function freeKey(base, properties) {
113
+ let key = `${base}__other`;
114
+ for (let i = 2; key in properties; i += 1)
115
+ key = `${base}__other_${i}`;
116
+ return key;
117
+ }
118
+ function rewriteElicitationParams(params) {
119
+ const meta = isRecord$3(params["_meta"]) ? params["_meta"] : void 0;
120
+ if (meta?.[ALLOW_OTHER_META] !== true)
121
+ return void 0;
122
+ const schema = isRecord$3(params["requestedSchema"]) ? params["requestedSchema"] : void 0;
123
+ const properties = schema && isRecord$3(schema["properties"]) ? schema["properties"] : void 0;
124
+ const questions = [];
125
+ const customFields = /* @__PURE__ */ new Map();
126
+ const rewrittenProperties = {};
127
+ if (properties) {
128
+ for (const [fieldId, raw] of Object.entries(properties)) {
129
+ rewrittenProperties[fieldId] = raw;
130
+ if (!isRecord$3(raw))
131
+ continue;
132
+ const { options, multiSelect } = questionShape(raw);
133
+ questions.push({
134
+ id: fieldId,
135
+ question: typeof raw["description"] === "string" ? raw["description"] : "",
136
+ header: typeof raw["title"] === "string" ? raw["title"] : "",
137
+ options,
138
+ multiSelect,
139
+ allowCustomAnswer: true
140
+ });
141
+ if (!hasOptions(raw))
142
+ continue;
143
+ const customKey = freeKey(fieldId, {
144
+ ...properties,
145
+ ...rewrittenProperties
146
+ });
147
+ rewrittenProperties[customKey] = {
148
+ type: "string",
149
+ title: "Other",
150
+ description: multiSelect ? "Type your own answer instead of choosing options above." : "Type your own answer instead of choosing an option above.",
151
+ _meta: {
152
+ lody: {
153
+ elicitation: {
154
+ version: 1,
155
+ customAnswerFor: fieldId,
156
+ secret: false
157
+ }
158
+ }
159
+ }
160
+ };
161
+ customFields.set(customKey, { target: fieldId, multiSelect });
162
+ }
163
+ }
164
+ const lody = isRecord$3(meta["lody"]) ? meta["lody"] : {};
165
+ const elicitation = {
166
+ ...isRecord$3(lody["elicitation"]) ? lody["elicitation"] : {},
167
+ version: 1,
168
+ questions
169
+ };
170
+ return {
171
+ params: {
172
+ ...params,
173
+ ...schema ? { requestedSchema: { ...schema, properties: rewrittenProperties } } : {},
174
+ _meta: { ...meta, lody: { ...lody, elicitation } }
175
+ },
176
+ customFields
177
+ };
178
+ }
179
+ function foldElicitationResponse(result, customFields) {
180
+ if (customFields.size === 0 || !isRecord$3(result))
181
+ return void 0;
182
+ if (result["action"] !== "accept" || !isRecord$3(result["content"]))
183
+ return void 0;
184
+ const content = result["content"];
185
+ let changed = false;
186
+ const folded = { ...content };
187
+ for (const [key, field] of customFields) {
188
+ if (!(key in folded))
189
+ continue;
190
+ const value = folded[key];
191
+ delete folded[key];
192
+ changed = true;
193
+ if (typeof value === "string" && value.trim()) {
194
+ folded[field.target] = field.multiSelect ? [value] : value;
195
+ } else if (Array.isArray(value) && value.length > 0) {
196
+ folded[field.target] = value;
197
+ }
198
+ }
199
+ if (!changed)
200
+ return void 0;
201
+ return { ...result, content: folded };
202
+ }
203
+ const CONTEXT_META = privateWireContract.subagentContextMeta;
204
+ const SIDEKICK_META = privateWireContract.sidekickToolCallMeta;
205
+ const STARTED_META = privateWireContract.subagentStartedMeta;
206
+ const COMPLETED_META = privateWireContract.subagentCompletedMeta;
207
+ const SIDEKICK_ID_PREFIX = privateWireContract.sidekickToolCallIdPrefix;
208
+ const ROOT_ACTIVITY = /* @__PURE__ */ new Set([
209
+ "agent_message_chunk",
210
+ "agent_thought_chunk",
211
+ "tool_call",
212
+ "tool_call_update",
213
+ "plan"
214
+ ]);
215
+ const TERMINAL_TOOL_STATUS = /* @__PURE__ */ new Set(["completed", "failed"]);
216
+ const TOOL_DISPLAY_FIELDS = ["title", "kind", "rawInput", "locations"];
217
+ const MAX_BUFFERED_CHILD_UPDATES = 64;
218
+ function isRecord$2(v) {
219
+ return typeof v === "object" && v !== null && !Array.isArray(v);
220
+ }
221
+ function agentContext$1(update) {
222
+ const meta = update["_meta"];
223
+ if (!isRecord$2(meta))
224
+ return void 0;
225
+ const ctx = meta[CONTEXT_META];
226
+ if (!isRecord$2(ctx))
227
+ return void 0;
228
+ const id = ctx["parentAgentId"];
229
+ return typeof id === "string" ? id : void 0;
230
+ }
231
+ function rememberToolDisplay(run, toolCallId, update) {
232
+ const entry = run.toolDisplay.get(toolCallId) ?? {};
233
+ for (const field of TOOL_DISPLAY_FIELDS) {
234
+ if (update[field] !== void 0)
235
+ entry[field] = update[field];
236
+ }
237
+ run.toolDisplay.set(toolCallId, entry);
238
+ }
239
+ function usageProgress(update) {
240
+ const progress = {};
241
+ if (typeof update["used"] === "number")
242
+ progress.contextTokens = update["used"];
243
+ if (typeof update["size"] === "number")
244
+ progress.contextWindowTokens = update["size"];
245
+ return progress;
246
+ }
247
+ class DevinSubagentEvents {
248
+ sessionId;
249
+ runs = /* @__PURE__ */ new Map();
250
+ sidekickRun;
251
+ buffered = /* @__PURE__ */ new Map();
252
+ overflowed = /* @__PURE__ */ new Set();
253
+ /** toolCallIds owned by any closed sidekick run; late updates are dropped. */
254
+ closedSkToolIds = /* @__PURE__ */ new Set();
255
+ /** latest sidekick usage seen before a run exists. */
256
+ stashedProgress;
257
+ /** root activity arrived while sidekick tools were still in flight. */
258
+ rootResumed = false;
259
+ newId;
260
+ now;
261
+ constructor(sessionId, { newId, now } = {}) {
262
+ this.sessionId = sessionId;
263
+ this.newId = newId ?? (() => crypto.randomUUID());
264
+ this.now = now ?? (() => Math.floor(Date.now() / 1e3));
265
+ }
266
+ emit(run, payload) {
267
+ return {
268
+ kind: "event",
269
+ event: {
270
+ version: 1,
271
+ sessionId: this.sessionId,
272
+ runId: run.runId,
273
+ ...payload
274
+ }
275
+ };
276
+ }
277
+ createSubagentRun(agentId, started, ctx) {
278
+ let parentRunId = null;
279
+ if (ctx && ctx !== privateWireContract.rootAgentId) {
280
+ if (ctx === privateWireContract.sidekickAgentId) {
281
+ parentRunId = this.sidekickRun?.live ? this.sidekickRun.runId : null;
282
+ } else {
283
+ const parent = this.runs.get(ctx);
284
+ parentRunId = parent?.live ? parent.runId : null;
285
+ }
286
+ }
287
+ const description = typeof started["title"] === "string" ? started["title"] : typeof started["task"] === "string" ? started["task"] : void 0;
288
+ const snapshot = {
289
+ state: "running",
290
+ parentRunId,
291
+ ...typeof started["profile"] === "string" ? { name: started["profile"] } : {},
292
+ ...description !== void 0 ? { description } : {},
293
+ ...typeof started["model"] === "string" ? { modelId: started["model"] } : {},
294
+ startedAtEpochSeconds: this.now(),
295
+ support: {
296
+ stream: ["text", "thought", "tool", "plan"],
297
+ progress: true,
298
+ outputRead: "none",
299
+ cancel: false
300
+ }
301
+ };
302
+ const run = {
303
+ runId: this.newId(),
304
+ agentId,
305
+ live: true,
306
+ snapshot,
307
+ toolIds: /* @__PURE__ */ new Set(),
308
+ inFlight: /* @__PURE__ */ new Set(),
309
+ mirrors: /* @__PURE__ */ new Set(),
310
+ toolDisplay: /* @__PURE__ */ new Map()
311
+ };
312
+ this.runs.set(agentId, run);
313
+ return run;
314
+ }
315
+ /**
316
+ * Open a new sidekick run. Returned outputs go to the client in order:
317
+ * the snapshot first, then any stashed progress observed before the run.
318
+ */
319
+ openSidekickRun() {
320
+ const out = [];
321
+ const run = {
322
+ runId: this.newId(),
323
+ agentId: privateWireContract.sidekickAgentId,
324
+ live: true,
325
+ snapshot: {
326
+ state: "running",
327
+ parentRunId: null,
328
+ name: "Sidekick",
329
+ startedAtEpochSeconds: this.now(),
330
+ support: {
331
+ stream: ["tool"],
332
+ progress: true,
333
+ outputRead: "none",
334
+ cancel: false
335
+ }
336
+ },
337
+ toolIds: /* @__PURE__ */ new Set(),
338
+ inFlight: /* @__PURE__ */ new Set(),
339
+ mirrors: /* @__PURE__ */ new Set(),
340
+ toolDisplay: /* @__PURE__ */ new Map()
341
+ };
342
+ this.sidekickRun = run;
343
+ out.push(this.emit(run, { type: "snapshot", snapshot: run.snapshot }));
344
+ if (this.stashedProgress !== void 0) {
345
+ const progress = this.stashedProgress;
346
+ this.stashedProgress = void 0;
347
+ out.push(this.emit(run, { type: "progress", progress }));
348
+ }
349
+ return { run, out };
350
+ }
351
+ closeSidekickSnapshot(run, patch) {
352
+ run.live = false;
353
+ for (const id of run.toolIds)
354
+ this.closedSkToolIds.add(id);
355
+ this.rootResumed = false;
356
+ run.snapshot = {
357
+ ...run.snapshot,
358
+ endedAtEpochSeconds: this.now(),
359
+ ...patch
360
+ };
361
+ return this.emit(run, { type: "snapshot", snapshot: run.snapshot });
362
+ }
363
+ mirrorRootUpdate(run, update, toolCallId) {
364
+ return {
365
+ ...update,
366
+ toolCallId: mirrorToolCallId(run.runId, toolCallId),
367
+ _meta: {
368
+ ...isRecord$2(update["_meta"]) ? update["_meta"] : {},
369
+ lody: { subagentRunId: run.runId, subagentToolCallId: toolCallId }
370
+ }
371
+ };
372
+ }
373
+ /**
374
+ * Classify one runtime `session/update` for this session.
375
+ * Returns run events and root-bound updates in order; drops consumed rows.
376
+ */
377
+ handleSessionUpdate(update) {
378
+ const out = [];
379
+ const meta = isRecord$2(update["_meta"]) ? update["_meta"] : void 0;
380
+ const ctx = agentContext$1(update);
381
+ const sessionUpdate = update["sessionUpdate"];
382
+ const completedMeta = meta?.[COMPLETED_META];
383
+ const startedMeta = meta?.[STARTED_META];
384
+ if ((sessionUpdate === "tool_call" || sessionUpdate === "tool_call_update") && (completedMeta !== void 0 || startedMeta !== void 0)) {
385
+ if (completedMeta !== void 0) {
386
+ if (!isRecord$2(completedMeta) || typeof completedMeta["agentId"] !== "string") {
387
+ out.push({ kind: "root", update });
388
+ return out;
389
+ }
390
+ const run2 = this.runs.get(completedMeta["agentId"]);
391
+ if (run2?.live) {
392
+ const failed = completedMeta["success"] === false;
393
+ const patch = {
394
+ state: failed ? "failed" : "completed",
395
+ endedAtEpochSeconds: this.now(),
396
+ ...typeof completedMeta["summary"] === "string" ? { summary: completedMeta["summary"] } : {},
397
+ ...failed && typeof completedMeta["summary"] === "string" ? {
398
+ reason: {
399
+ code: "error",
400
+ message: completedMeta["summary"]
401
+ }
402
+ } : {}
403
+ };
404
+ run2.live = false;
405
+ run2.snapshot = { ...run2.snapshot, ...patch };
406
+ out.push(this.emit(run2, { type: "snapshot", snapshot: run2.snapshot }));
407
+ }
408
+ return out;
409
+ }
410
+ if (!isRecord$2(startedMeta) || typeof startedMeta["agentId"] !== "string") {
411
+ out.push({ kind: "root", update });
412
+ return out;
413
+ }
414
+ const agentId = startedMeta["agentId"];
415
+ const existing = this.runs.get(agentId);
416
+ if (existing?.live)
417
+ return out;
418
+ const run = this.createSubagentRun(agentId, startedMeta, ctx);
419
+ out.push(this.emit(run, { type: "snapshot", snapshot: run.snapshot }));
420
+ if (this.overflowed.delete(agentId)) {
421
+ run.snapshot = { ...run.snapshot, outputIncomplete: true };
422
+ out.push(this.emit(run, { type: "snapshot", snapshot: run.snapshot }));
423
+ }
424
+ const buffered = this.buffered.get(agentId);
425
+ if (buffered) {
426
+ this.buffered.delete(agentId);
427
+ for (const u of buffered)
428
+ out.push(...this.childUpdate(run, u));
429
+ }
430
+ return out;
431
+ }
432
+ if (typeof ctx === "string" && ctx !== privateWireContract.rootAgentId && ctx !== privateWireContract.sidekickAgentId) {
433
+ const run = this.runs.get(ctx);
434
+ if (run?.live) {
435
+ out.push(...this.childUpdate(run, update));
436
+ } else if (!run) {
437
+ const buf = this.buffered.get(ctx) ?? [];
438
+ if (buf.length >= MAX_BUFFERED_CHILD_UPDATES) {
439
+ this.overflowed.add(ctx);
440
+ } else {
441
+ buf.push(update);
442
+ this.buffered.set(ctx, buf);
443
+ }
444
+ }
445
+ return out;
446
+ }
447
+ const toolCallId = typeof update["toolCallId"] === "string" ? update["toolCallId"] : void 0;
448
+ const isSidekick = ctx === privateWireContract.sidekickAgentId || (sessionUpdate === "tool_call" || sessionUpdate === "tool_call_update") && (meta?.[SIDEKICK_META] === true || toolCallId !== void 0 && toolCallId.startsWith(SIDEKICK_ID_PREFIX));
449
+ if (isSidekick) {
450
+ if (toolCallId && this.closedSkToolIds.has(toolCallId)) {
451
+ return out;
452
+ }
453
+ if (sessionUpdate === "usage_update" && !this.sidekickRun?.live) {
454
+ this.stashedProgress = usageProgress(update);
455
+ return out;
456
+ }
457
+ let run = this.sidekickRun;
458
+ if (!run?.live) {
459
+ const opened = this.openSidekickRun();
460
+ run = opened.run;
461
+ out.push(...opened.out);
462
+ }
463
+ if (sessionUpdate === "usage_update") {
464
+ out.push(this.emit(run, { type: "progress", progress: usageProgress(update) }));
465
+ return out;
466
+ }
467
+ if (sessionUpdate === "tool_call" && toolCallId) {
468
+ run.toolIds.add(toolCallId);
469
+ run.inFlight.add(toolCallId);
470
+ } else if (sessionUpdate === "tool_call_update" && toolCallId && TERMINAL_TOOL_STATUS.has(String(update["status"]))) {
471
+ run.inFlight.delete(toolCallId);
472
+ if (toolCallId)
473
+ run.toolIds.add(toolCallId);
474
+ }
475
+ if ((sessionUpdate === "tool_call" || sessionUpdate === "tool_call_update") && toolCallId) {
476
+ rememberToolDisplay(run, toolCallId, update);
477
+ }
478
+ if (isLodySubagentOutput(update)) {
479
+ out.push(this.emit(run, { type: "output", update }));
480
+ if (toolCallId && run.mirrors.has(toolCallId)) {
481
+ out.push({
482
+ kind: "root",
483
+ update: this.mirrorRootUpdate(run, update, toolCallId)
484
+ });
485
+ }
486
+ }
487
+ if (this.rootResumed && run.inFlight.size === 0) {
488
+ out.push(this.closeSidekickSnapshot(run, { state: "completed" }));
489
+ }
490
+ return out;
491
+ }
492
+ if (this.sidekickRun?.live && ROOT_ACTIVITY.has(String(sessionUpdate))) {
493
+ if (this.sidekickRun.inFlight.size === 0) {
494
+ out.push(this.closeSidekickSnapshot(this.sidekickRun, { state: "completed" }));
495
+ } else {
496
+ this.rootResumed = true;
497
+ }
498
+ }
499
+ out.push({ kind: "root", update });
500
+ return out;
501
+ }
502
+ childUpdate(run, update) {
503
+ const out = [];
504
+ if (update["sessionUpdate"] === "usage_update") {
505
+ out.push(this.emit(run, { type: "progress", progress: usageProgress(update) }));
506
+ return out;
507
+ }
508
+ if ((update["sessionUpdate"] === "tool_call" || update["sessionUpdate"] === "tool_call_update") && typeof update["toolCallId"] === "string") {
509
+ rememberToolDisplay(run, update["toolCallId"], update);
510
+ }
511
+ if (isLodySubagentOutput(update)) {
512
+ const toolCallId = "toolCallId" in update && typeof update["toolCallId"] === "string" ? update["toolCallId"] : void 0;
513
+ if (toolCallId)
514
+ run.toolIds.add(toolCallId);
515
+ out.push(this.emit(run, { type: "output", update }));
516
+ if (toolCallId && run.mirrors.has(toolCallId)) {
517
+ out.push({
518
+ kind: "root",
519
+ update: this.mirrorRootUpdate(run, update, toolCallId)
520
+ });
521
+ }
522
+ return out;
523
+ }
524
+ if (update["sessionUpdate"] === "agent_message_chunk" || update["sessionUpdate"] === "agent_thought_chunk") {
525
+ if (run.snapshot.outputIncomplete !== true) {
526
+ run.snapshot = { ...run.snapshot, outputIncomplete: true };
527
+ out.push(this.emit(run, { type: "snapshot", snapshot: run.snapshot }));
528
+ }
529
+ return out;
530
+ }
531
+ return out;
532
+ }
533
+ /**
534
+ * Runtime `session/request_permission` for this session. Returns the
535
+ * rewritten params when the toolCallId belongs to a live run, else null.
536
+ */
537
+ rewritePermissionParams(params) {
538
+ if (!isRecord$2(params))
539
+ return null;
540
+ const toolCall = params["toolCall"];
541
+ if (!isRecord$2(toolCall) || typeof toolCall["toolCallId"] !== "string")
542
+ return null;
543
+ const id = toolCall["toolCallId"];
544
+ const events = [];
545
+ let run;
546
+ for (const r of this.runs.values()) {
547
+ if (r.live && r.toolIds.has(id)) {
548
+ run = r;
549
+ break;
550
+ }
551
+ }
552
+ if (!run && this.sidekickRun?.live && this.sidekickRun.toolIds.has(id)) {
553
+ run = this.sidekickRun;
554
+ }
555
+ if (!run && id.startsWith(SIDEKICK_ID_PREFIX)) {
556
+ if (this.sidekickRun?.live) {
557
+ run = this.sidekickRun;
558
+ } else {
559
+ const opened = this.openSidekickRun();
560
+ events.push(...opened.out);
561
+ run = opened.run;
562
+ }
563
+ run.toolIds.add(id);
564
+ }
565
+ if (!run)
566
+ return null;
567
+ run.mirrors.add(id);
568
+ const known = run.toolDisplay.get(id) ?? {};
569
+ return {
570
+ events,
571
+ params: {
572
+ ...params,
573
+ toolCall: {
574
+ ...known,
575
+ ...toolCall,
576
+ toolCallId: mirrorToolCallId(run.runId, id)
577
+ },
578
+ _meta: {
579
+ ...isRecord$2(params["_meta"]) ? params["_meta"] : {},
580
+ lody: { subagentRunId: run.runId, subagentToolCallId: id }
581
+ }
582
+ }
583
+ };
584
+ }
585
+ /**
586
+ * Client `session/prompt` response arrived. Close any live sidekick run
587
+ * before the response; subagent runs are unaffected (may be background).
588
+ */
589
+ handlePromptDone(stopReason, isError) {
590
+ this.stashedProgress = void 0;
591
+ const run = this.sidekickRun;
592
+ if (!run?.live)
593
+ return [];
594
+ let patch;
595
+ if (isError) {
596
+ patch = {
597
+ state: "unknown",
598
+ outputIncomplete: true,
599
+ reason: { code: "error" }
600
+ };
601
+ } else if (stopReason === "cancelled") {
602
+ patch = { state: "cancelled", reason: { code: "cancelled" } };
603
+ } else {
604
+ patch = { state: "completed" };
605
+ }
606
+ return [this.closeSidekickSnapshot(run, patch)];
607
+ }
608
+ }
609
+ function mirrorToolCallId(runId, toolCallId) {
610
+ return `subagent:${encodeURIComponent(runId)}:${encodeURIComponent(toolCallId)}`;
611
+ }
612
+ const MODEL_OPTION_ID = "model";
613
+ const FALLBACK_MODEL_ID = "devin";
614
+ const SIDEKICK_MODEL_ID = "sidekick";
615
+ const MAX_RECENT_SIGNATURES = 8;
616
+ const PASSTHROUGH_META = [
617
+ privateWireContract.usageTotalCreditCostMeta,
618
+ privateWireContract.usageTotalAcuCostMeta,
619
+ privateWireContract.usageResponseDimensionsMeta
620
+ ];
621
+ function isRecord$1(value) {
622
+ return typeof value === "object" && value !== null && !Array.isArray(value);
623
+ }
624
+ function num(value) {
625
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
626
+ }
627
+ function agentContext(meta) {
628
+ const ctx = meta?.[privateWireContract.subagentContextMeta];
629
+ if (!isRecord$1(ctx))
630
+ return void 0;
631
+ const id = ctx["parentAgentId"];
632
+ return typeof id === "string" ? id : void 0;
633
+ }
634
+ class DevinSessionUsage {
635
+ sessionId;
636
+ /** One accumulator per ACP session: each session is its own accounting
637
+ * lifetime, so each keeps a never-reused usageScopeId. Created lazily so
638
+ * sessions without countable usage never consume an injected id. */
639
+ accumulator;
640
+ modelId = FALLBACK_MODEL_ID;
641
+ operation = 0;
642
+ signatures = /* @__PURE__ */ new Set();
643
+ signatureOrder = [];
644
+ newId;
645
+ constructor(sessionId, newId = crypto.randomUUID.bind(crypto)) {
646
+ this.sessionId = sessionId;
647
+ this.newId = newId;
648
+ }
649
+ /** Track the ACP `model` config option from session responses and
650
+ * config_option_update notifications; usage rows accumulate under it. */
651
+ observeConfigOptions(options) {
652
+ if (!Array.isArray(options))
653
+ return;
654
+ for (const option of options) {
655
+ if (!isRecord$1(option) || option["id"] !== MODEL_OPTION_ID)
656
+ continue;
657
+ const value = option["currentValue"];
658
+ if (typeof value === "string" && value.length > 0)
659
+ this.modelId = value;
660
+ }
661
+ }
662
+ /**
663
+ * Translate one runtime `usage_update` into a Core SessionUsageUpdate, or
664
+ * return undefined when the row must not enter this session's accounting:
665
+ * child-run usage, a duplicate report of an already-counted request, or a
666
+ * row without the private token counters needed for disjoint buckets.
667
+ */
668
+ record(update) {
669
+ const meta = isRecord$1(update["_meta"]) ? update["_meta"] : void 0;
670
+ const ctx = agentContext(meta);
671
+ if (ctx !== void 0 && ctx !== privateWireContract.rootAgentId && ctx !== privateWireContract.sidekickAgentId) {
672
+ return void 0;
673
+ }
674
+ const input = num(meta?.[privateWireContract.usageInputTokensMeta]);
675
+ const output = num(meta?.[privateWireContract.usageOutputTokensMeta]);
676
+ if (input === void 0 || output === void 0)
677
+ return void 0;
678
+ const cachedRead = num(meta?.[privateWireContract.usageCachedReadTokensMeta]) ?? 0;
679
+ const cachedWrite = num(meta?.[privateWireContract.usageCachedWriteTokensMeta]);
680
+ const signature = JSON.stringify([
681
+ input,
682
+ output,
683
+ cachedRead,
684
+ cachedWrite ?? 0,
685
+ num(update["used"]) ?? null
686
+ ]);
687
+ if (this.signatures.has(signature))
688
+ return void 0;
689
+ this.signatures.add(signature);
690
+ this.signatureOrder.push(signature);
691
+ if (this.signatureOrder.length > MAX_RECENT_SIGNATURES) {
692
+ this.signatures.delete(this.signatureOrder.shift());
693
+ }
694
+ const row = {
695
+ // Devin's inputTokens includes cache reads AND cache writes (verified on
696
+ // gpt-6-luna: input = fresh + cachedRead + cachedWrite); Core buckets
697
+ // are disjoint, so subtract both. SWE-2 rows omit cachedWriteTokens.
698
+ inputTokens: Math.max(0, input - cachedRead - (cachedWrite ?? 0)),
699
+ outputTokens: output,
700
+ cacheReadInputTokens: cachedRead
701
+ };
702
+ if (cachedWrite !== void 0)
703
+ row.cacheCreationInputTokens = cachedWrite;
704
+ const modelId = ctx === privateWireContract.sidekickAgentId ? SIDEKICK_MODEL_ID : this.modelId;
705
+ this.accumulator ??= new SessionUsageAccumulator(this.newId());
706
+ const result = this.accumulator.update(this.sessionId, `devin-request-${++this.operation}`, { [modelId]: row });
707
+ if (result === void 0)
708
+ return void 0;
709
+ const size = num(update["size"]);
710
+ if (size !== void 0)
711
+ result.usage.contextWindow = size;
712
+ if (meta !== void 0) {
713
+ const passthrough = {};
714
+ for (const key of PASSTHROUGH_META) {
715
+ if (meta[key] !== void 0)
716
+ passthrough[key] = meta[key];
717
+ }
718
+ if (Object.keys(passthrough).length > 0) {
719
+ result._meta = { ...result._meta, ...passthrough };
720
+ }
721
+ }
722
+ return result;
723
+ }
724
+ }
725
+ const SUBAGENT_SUPPORT_META = privateWireContract.subagentSupportClientCapability;
726
+ const SUBAGENT_EVENTS_CAPABILITY = { version: 1 };
727
+ const COMPACTION_CAPABILITY = { version: 1 };
728
+ const ELICITATION_CAPABILITY = { version: 1 };
729
+ const USAGE_CAPABILITY = { version: 1 };
730
+ const COMPACTION_ACTIVITY_META = {
731
+ lody: { activity: { version: 1, kind: "context_compaction" } }
732
+ };
733
+ function isRecord(value) {
734
+ return typeof value === "object" && value !== null && !Array.isArray(value);
735
+ }
736
+ function isRequest(message) {
737
+ return typeof message.method === "string" && message.id !== void 0 && message.id !== null;
738
+ }
739
+ function isResponse(message) {
740
+ return message.id !== void 0 && message.id !== null && message.method === void 0;
741
+ }
742
+ function hasCompactionSummary(summary) {
743
+ return typeof summary === "string" && summary.trim().length > 0;
744
+ }
745
+ function isManualCompactionPrompt(params) {
746
+ if (!isRecord(params) || !Array.isArray(params["prompt"]))
747
+ return false;
748
+ let text;
749
+ for (const block of params["prompt"]) {
750
+ if (!isRecord(block) || block["type"] !== "text" || typeof block["text"] !== "string") {
751
+ return false;
752
+ }
753
+ const value = block["text"].trim();
754
+ if (!value)
755
+ continue;
756
+ if (text !== void 0)
757
+ return false;
758
+ text = value;
759
+ }
760
+ const command = privateWireContract.compactionManualCommand;
761
+ return text === command || text?.startsWith(`${command} `) === true;
762
+ }
763
+ class DevinAcpProxy {
764
+ pending = /* @__PURE__ */ new Map();
765
+ sessions = /* @__PURE__ */ new Map();
766
+ usages = /* @__PURE__ */ new Map();
767
+ admitted = /* @__PURE__ */ new Set();
768
+ /** sessions inside a session/load replay window: updates pass through. */
769
+ replaying = /* @__PURE__ */ new Set();
770
+ /** sessions whose next compaction started event belongs to a manual /compact prompt. */
771
+ manualCompactionArmed = /* @__PURE__ */ new Set();
772
+ /** admitted sessions with a live native compaction. */
773
+ activeCompactions = /* @__PURE__ */ new Map();
774
+ negotiated = false;
775
+ /** client advertised _meta.lody.elicitation — translate private elicitation hints. */
776
+ lodyElicitation = false;
777
+ /** elicitation/create request id -> injected custom-answer companion fields. */
778
+ elicitationCustomFields = /* @__PURE__ */ new Map();
779
+ subagentOpts;
780
+ newId;
781
+ constructor(opts = {}) {
782
+ this.subagentOpts = opts;
783
+ this.newId = opts.newId ?? randomUUID;
784
+ }
785
+ handleClient(message) {
786
+ let msg = message;
787
+ if (!isRecord(msg))
788
+ return { toClient: [], toRuntime: [msg] };
789
+ if (isRequest(msg)) {
790
+ const sessionId = isRecord(msg.params) && typeof msg.params["sessionId"] === "string" ? msg.params["sessionId"] : void 0;
791
+ const manualCompaction = msg.method === "session/prompt" && sessionId !== void 0 && isManualCompactionPrompt(msg.params);
792
+ this.pending.set(msg.id, {
793
+ method: msg.method,
794
+ sessionId,
795
+ manualCompaction
796
+ });
797
+ if (msg.method === "initialize") {
798
+ const caps = isRecord(msg.params) ? msg.params["clientCapabilities"] : void 0;
799
+ this.negotiated = supportsLodySubagentEvents(caps);
800
+ this.lodyElicitation = clientSupportsLodyElicitation(caps);
801
+ if (this.negotiated && isRecord(msg.params)) {
802
+ msg = {
803
+ ...msg,
804
+ params: {
805
+ ...msg.params,
806
+ clientCapabilities: {
807
+ ...isRecord(caps) ? caps : {},
808
+ _meta: {
809
+ ...isRecord(caps) && isRecord(caps["_meta"]) ? caps["_meta"] : {},
810
+ [SUBAGENT_SUPPORT_META]: true
811
+ }
812
+ }
813
+ }
814
+ };
815
+ }
816
+ }
817
+ if (msg.method === "session/prompt" && sessionId) {
818
+ if (manualCompaction) {
819
+ this.manualCompactionArmed.add(sessionId);
820
+ } else {
821
+ this.manualCompactionArmed.delete(sessionId);
822
+ }
823
+ }
824
+ if ((msg.method === "session/load" || msg.method === "session/resume") && sessionId) {
825
+ this.replaying.add(sessionId);
826
+ this.manualCompactionArmed.delete(sessionId);
827
+ }
828
+ }
829
+ if (isResponse(msg)) {
830
+ const customFields = this.elicitationCustomFields.get(msg.id);
831
+ if (customFields) {
832
+ this.elicitationCustomFields.delete(msg.id);
833
+ const result = foldElicitationResponse(msg.result, customFields);
834
+ if (result !== void 0)
835
+ msg = { ...msg, result };
836
+ }
837
+ }
838
+ return { toClient: [], toRuntime: [msg] };
839
+ }
840
+ handleRuntime(message) {
841
+ const msg = message;
842
+ if (!isRecord(msg))
843
+ return { toClient: [msg], toRuntime: [] };
844
+ if (isResponse(msg)) {
845
+ const pending = this.pending.get(msg.id);
846
+ this.pending.delete(msg.id);
847
+ return this.handleRuntimeResponse(msg, pending);
848
+ }
849
+ if (isRequest(msg)) {
850
+ return this.handleRuntimeRequest(msg);
851
+ }
852
+ if (msg.method === "session/update" && isRecord(msg.params)) {
853
+ return this.handleSessionUpdate(msg);
854
+ }
855
+ if (msg.method === privateWireContract.compactionNotificationMethod) {
856
+ return this.handleCompactionNotification(msg);
857
+ }
858
+ return { toClient: [msg], toRuntime: [] };
859
+ }
860
+ handleRuntimeResponse(msg, pending) {
861
+ const toClient = [];
862
+ if (pending?.method === "initialize" && isRecord(msg.result)) {
863
+ const agentCaps = isRecord(msg.result["agentCapabilities"]) ? msg.result["agentCapabilities"] : {};
864
+ const meta = isRecord(agentCaps["_meta"]) ? agentCaps["_meta"] : {};
865
+ const lody = isRecord(meta["lody"]) ? meta["lody"] : {};
866
+ const result = {
867
+ ...msg.result,
868
+ agentCapabilities: {
869
+ ...agentCaps,
870
+ _meta: {
871
+ ...meta,
872
+ lody: {
873
+ ...lody,
874
+ subagentEvents: SUBAGENT_EVENTS_CAPABILITY,
875
+ compaction: COMPACTION_CAPABILITY,
876
+ elicitation: ELICITATION_CAPABILITY,
877
+ usage: USAGE_CAPABILITY
878
+ }
879
+ }
880
+ }
881
+ };
882
+ toClient.push({ ...msg, result });
883
+ return { toClient, toRuntime: [] };
884
+ }
885
+ if (pending?.manualCompaction && pending.sessionId && msg.error !== void 0) {
886
+ this.manualCompactionArmed.delete(pending.sessionId);
887
+ }
888
+ if (pending?.method === "session/new" || pending?.method === "session/fork") {
889
+ if (isRecord(msg.result) && typeof msg.result["sessionId"] === "string") {
890
+ this.admit(msg.result["sessionId"]);
891
+ this.usages.get(msg.result["sessionId"])?.observeConfigOptions(msg.result["configOptions"]);
892
+ }
893
+ } else if ((pending?.method === "session/load" || pending?.method === "session/resume") && pending.sessionId) {
894
+ this.replaying.delete(pending.sessionId);
895
+ if (msg.result !== void 0 && msg.error === void 0) {
896
+ this.admit(pending.sessionId);
897
+ if (isRecord(msg.result)) {
898
+ this.usages.get(pending.sessionId)?.observeConfigOptions(msg.result["configOptions"]);
899
+ }
900
+ }
901
+ } else if (pending?.method === "session/set_config_option" && pending.sessionId) {
902
+ if (isRecord(msg.result)) {
903
+ this.usages.get(pending.sessionId)?.observeConfigOptions(msg.result["configOptions"]);
904
+ }
905
+ } else if (pending?.method === "session/prompt" && pending.sessionId) {
906
+ const session = this.sessions.get(pending.sessionId);
907
+ if (session) {
908
+ const isError = msg.error !== void 0;
909
+ const stopReason = isRecord(msg.result) && typeof msg.result["stopReason"] === "string" ? msg.result["stopReason"] : void 0;
910
+ for (const o of session.handlePromptDone(stopReason, isError)) {
911
+ toClient.push(...this.render(session, o));
912
+ }
913
+ }
914
+ }
915
+ toClient.push(msg);
916
+ return { toClient, toRuntime: [] };
917
+ }
918
+ handleRuntimeRequest(msg) {
919
+ if (msg.method === "elicitation/create" && isRecord(msg.params) && this.lodyElicitation) {
920
+ const rewritten = rewriteElicitationParams(msg.params);
921
+ if (rewritten) {
922
+ if (rewritten.customFields.size > 0) {
923
+ this.elicitationCustomFields.set(msg.id, rewritten.customFields);
924
+ }
925
+ return {
926
+ toClient: [{ ...msg, params: rewritten.params }],
927
+ toRuntime: []
928
+ };
929
+ }
930
+ }
931
+ if (msg.method === "session/request_permission" && isRecord(msg.params)) {
932
+ const sessionId = typeof msg.params["sessionId"] === "string" ? msg.params["sessionId"] : void 0;
933
+ const session = sessionId ? this.sessions.get(sessionId) : void 0;
934
+ if (session && sessionId && this.admitted.has(sessionId) && !this.replaying.has(sessionId)) {
935
+ const rewritten = session.rewritePermissionParams(msg.params);
936
+ if (rewritten) {
937
+ const toClient = [];
938
+ for (const o of rewritten.events) {
939
+ toClient.push(...this.render(session, o));
940
+ }
941
+ toClient.push({ ...msg, params: rewritten.params });
942
+ return { toClient, toRuntime: [] };
943
+ }
944
+ }
945
+ }
946
+ return { toClient: [msg], toRuntime: [] };
947
+ }
948
+ handleSessionUpdate(msg) {
949
+ const params = msg.params;
950
+ const sessionId = typeof params["sessionId"] === "string" ? params["sessionId"] : void 0;
951
+ const update = params["update"];
952
+ const session = sessionId ? this.sessions.get(sessionId) : void 0;
953
+ const live = sessionId !== void 0 && this.admitted.has(sessionId) && !this.replaying.has(sessionId);
954
+ const usageOut = [];
955
+ if (live && sessionId && isRecord(update)) {
956
+ const tracker = this.usages.get(sessionId);
957
+ if (tracker && update["sessionUpdate"] === "config_option_update") {
958
+ tracker.observeConfigOptions(update["configOptions"]);
959
+ }
960
+ if (tracker && update["sessionUpdate"] === "usage_update") {
961
+ const translated = tracker.record(update);
962
+ if (translated !== void 0) {
963
+ usageOut.push({
964
+ jsonrpc: "2.0",
965
+ method: LODY_EXTENSION_METHODS.sessionUsageUpdate,
966
+ params: translated
967
+ });
968
+ }
969
+ }
970
+ }
971
+ if (!this.negotiated || !sessionId || !session || !live || !isRecord(update)) {
972
+ return { toClient: [msg, ...usageOut], toRuntime: [] };
973
+ }
974
+ const toClient = [];
975
+ for (const o of session.handleSessionUpdate(update)) {
976
+ toClient.push(...this.render(session, o));
977
+ }
978
+ toClient.push(...usageOut);
979
+ return { toClient, toRuntime: [] };
980
+ }
981
+ /**
982
+ * Devin's private `_cognition.ai/compaction` lifecycle, rendered as a Core
983
+ * context-compaction activity on a synthetic tool call. The native lifecycle
984
+ * owns completion independently of the `/compact` prompt response. Only
985
+ * admitted sessions outside a replay window produce activity; replay and
986
+ * malformed or unknown-status rows pass through untouched.
987
+ */
988
+ handleCompactionNotification(msg) {
989
+ const params = msg.params;
990
+ const sessionId = isRecord(params) && typeof params[privateWireContract.compactionSessionIdField] === "string" && params[privateWireContract.compactionSessionIdField] ? params[privateWireContract.compactionSessionIdField] : void 0;
991
+ const status = isRecord(params) ? params[privateWireContract.compactionStatusField] : void 0;
992
+ const known = status === privateWireContract.compactionStartedStatus || status === privateWireContract.compactionCompletedStatus || status === privateWireContract.compactionFailedStatus;
993
+ if (!sessionId || !known || !this.admitted.has(sessionId) || this.replaying.has(sessionId)) {
994
+ return { toClient: [msg], toRuntime: [] };
995
+ }
996
+ if (status === privateWireContract.compactionStartedStatus) {
997
+ if (this.activeCompactions.has(sessionId)) {
998
+ return { toClient: [], toRuntime: [] };
999
+ }
1000
+ const toolCallId = `devin-compaction-${this.newId()}`;
1001
+ const shown = this.manualCompactionArmed.delete(sessionId);
1002
+ this.activeCompactions.set(sessionId, { toolCallId, shown });
1003
+ if (!shown)
1004
+ return { toClient: [], toRuntime: [] };
1005
+ return {
1006
+ toClient: [this.compactionStart(sessionId, toolCallId)],
1007
+ toRuntime: []
1008
+ };
1009
+ }
1010
+ const active = this.activeCompactions.get(sessionId);
1011
+ this.activeCompactions.delete(sessionId);
1012
+ if (!active) {
1013
+ return { toClient: [], toRuntime: [] };
1014
+ }
1015
+ const manuallyArmed = this.manualCompactionArmed.delete(sessionId);
1016
+ const summary = params[privateWireContract.compactionSummaryField];
1017
+ const terminal = this.compactionTerminal(sessionId, active.toolCallId, status, summary);
1018
+ if (active.shown) {
1019
+ return { toClient: [terminal], toRuntime: [] };
1020
+ }
1021
+ if (!manuallyArmed && status === privateWireContract.compactionCompletedStatus && !hasCompactionSummary(summary)) {
1022
+ return { toClient: [], toRuntime: [] };
1023
+ }
1024
+ return {
1025
+ toClient: [this.compactionStart(sessionId, active.toolCallId), terminal],
1026
+ toRuntime: []
1027
+ };
1028
+ }
1029
+ compactionStart(sessionId, toolCallId) {
1030
+ return {
1031
+ jsonrpc: "2.0",
1032
+ method: "session/update",
1033
+ params: {
1034
+ sessionId,
1035
+ update: {
1036
+ sessionUpdate: "tool_call",
1037
+ toolCallId,
1038
+ title: "Compact context",
1039
+ kind: "other",
1040
+ status: "in_progress",
1041
+ _meta: { ...COMPACTION_ACTIVITY_META }
1042
+ }
1043
+ }
1044
+ };
1045
+ }
1046
+ compactionTerminal(sessionId, toolCallId, status, summary) {
1047
+ const update = {
1048
+ sessionUpdate: "tool_call_update",
1049
+ toolCallId,
1050
+ status,
1051
+ _meta: { ...COMPACTION_ACTIVITY_META }
1052
+ };
1053
+ if (status === privateWireContract.compactionCompletedStatus && hasCompactionSummary(summary)) {
1054
+ update["content"] = [
1055
+ { type: "content", content: { type: "text", text: summary } }
1056
+ ];
1057
+ }
1058
+ return {
1059
+ jsonrpc: "2.0",
1060
+ method: "session/update",
1061
+ params: { sessionId, update }
1062
+ };
1063
+ }
1064
+ render(session, out) {
1065
+ if (out.kind === "event") {
1066
+ return [
1067
+ {
1068
+ jsonrpc: "2.0",
1069
+ method: LODY_SUBAGENT_EVENT_METHOD,
1070
+ params: out.event
1071
+ }
1072
+ ];
1073
+ }
1074
+ return [
1075
+ {
1076
+ jsonrpc: "2.0",
1077
+ method: "session/update",
1078
+ params: { sessionId: session.sessionId, update: out.update }
1079
+ }
1080
+ ];
1081
+ }
1082
+ admit(sessionId) {
1083
+ if (!this.admitted.has(sessionId)) {
1084
+ this.admitted.add(sessionId);
1085
+ this.sessions.set(sessionId, new DevinSubagentEvents(sessionId, this.subagentOpts));
1086
+ this.usages.set(sessionId, new DevinSessionUsage(sessionId, this.newId));
1087
+ }
1088
+ }
1089
+ /** Method of the still-pending client request, for translation dispatch. */
1090
+ pendingClientMethod(id) {
1091
+ return this.pending.get(id)?.method;
1092
+ }
1093
+ }
1094
+ function spawnDevinRuntime(devinPath2, { env = process.env, spawnImpl = spawn } = {}) {
1095
+ return spawnImpl(devinPath2, ["acp"], {
1096
+ env,
1097
+ stdio: ["pipe", "pipe", "inherit"],
1098
+ windowsHide: true
1099
+ });
1100
+ }
1101
+ const devinPath = process.env.DEVIN_PATH;
1102
+ if (!devinPath) {
1103
+ console.error("DEVIN_PATH must point to the official Devin runtime");
1104
+ process.exit(1);
1105
+ }
1106
+ const child = spawnDevinRuntime(devinPath);
1107
+ const proxy = new DevinAcpProxy();
1108
+ if (!child.stdin || !child.stdout) {
1109
+ console.error("Official Devin runtime stdio is not piped");
1110
+ process.exit(1);
1111
+ }
1112
+ const childStdin = child.stdin;
1113
+ const childStdout = child.stdout;
1114
+ function exit(code) {
1115
+ process.stdout.write("", () => process.exit(code));
1116
+ }
1117
+ function write(stream, message) {
1118
+ stream.write(`${JSON.stringify(message)}
1119
+ `);
1120
+ }
1121
+ function dispatch(output) {
1122
+ for (const message of output.toRuntime)
1123
+ write(childStdin, message);
1124
+ for (const message of output.toClient)
1125
+ write(process.stdout, message);
1126
+ }
1127
+ createInterface({ input: process.stdin }).on("line", (line) => {
1128
+ try {
1129
+ dispatch(proxy.handleClient(JSON.parse(line)));
1130
+ } catch (error) {
1131
+ console.error(`Invalid ACP client message: ${error instanceof Error ? error.message : String(error)}`);
1132
+ }
1133
+ });
1134
+ createInterface({ input: childStdout }).on("line", (line) => {
1135
+ try {
1136
+ dispatch(proxy.handleRuntime(JSON.parse(line)));
1137
+ } catch (error) {
1138
+ console.error(`Invalid Devin runtime message: ${error instanceof Error ? error.message : String(error)}`);
1139
+ }
1140
+ });
1141
+ process.stdin.on("end", () => childStdin.end());
1142
+ child.on("error", (error) => {
1143
+ console.error(`Failed to launch official Devin runtime: ${error.message}`);
1144
+ exit(1);
1145
+ });
1146
+ child.on("close", (code, signal) => {
1147
+ if (signal)
1148
+ process.kill(process.pid, signal);
1149
+ else
1150
+ exit(code ?? 1);
1151
+ });
1152
+ //# sourceMappingURL=devin-acp.js.map