@junctionpanel/server 0.1.40 → 0.1.42
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/server/client/daemon-client.d.ts.map +1 -1
- package/dist/server/client/daemon-client.js +19 -8
- package/dist/server/client/daemon-client.js.map +1 -1
- package/dist/server/server/agent/agent-manager.d.ts +1 -0
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
- package/dist/server/server/agent/agent-manager.js +28 -6
- package/dist/server/server/agent/agent-manager.js.map +1 -1
- package/dist/server/server/agent/agent-projections.d.ts.map +1 -1
- package/dist/server/server/agent/agent-projections.js +3 -0
- package/dist/server/server/agent/agent-projections.js.map +1 -1
- package/dist/server/server/agent/agent-sdk-types.d.ts +2 -0
- package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +22 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.js +226 -93
- package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
- package/dist/server/shared/messages.d.ts +233 -0
- package/dist/server/shared/messages.d.ts.map +1 -1
- package/dist/server/shared/messages.js +3 -0
- package/dist/server/shared/messages.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-app-server-agent.d.ts","sourceRoot":"","sources":["../../../../../src/server/agent/providers/codex-app-server-agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,oBAAoB,EACpB,WAAW,EAEX,oBAAoB,EAGpB,uBAAuB,EAEvB,gBAAgB,EAIhB,YAAY,EACZ,kBAAkB,
|
|
1
|
+
{"version":3,"file":"codex-app-server-agent.d.ts","sourceRoot":"","sources":["../../../../../src/server/agent/providers/codex-app-server-agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -695,6 +695,60 @@ function formatProposedPlanChunk(text, options) {
|
|
|
695
695
|
}
|
|
696
696
|
return parts.join("");
|
|
697
697
|
}
|
|
698
|
+
function buildCompletedCodexTimelineItem(item, options) {
|
|
699
|
+
const timelineItem = threadItemToTimeline(item, {
|
|
700
|
+
includeUserMessage: false,
|
|
701
|
+
cwd: options.cwd ?? null,
|
|
702
|
+
});
|
|
703
|
+
if (!timelineItem) {
|
|
704
|
+
return null;
|
|
705
|
+
}
|
|
706
|
+
const normalizedItemType = normalizeCodexThreadItemType(typeof item.type === "string" ? item.type : undefined);
|
|
707
|
+
const itemId = item.id;
|
|
708
|
+
if (timelineItem.type === "tool_call" && normalizedItemType === "commandExecution") {
|
|
709
|
+
const callId = timelineItem.callId || itemId;
|
|
710
|
+
if (callId && options.state.emittedExecCommandCompletedCallIds.has(callId)) {
|
|
711
|
+
return null;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
if (itemId && options.state.emittedItemCompletedIds.has(itemId)) {
|
|
715
|
+
return null;
|
|
716
|
+
}
|
|
717
|
+
if (timelineItem.type === "assistant_message" && itemId) {
|
|
718
|
+
const buffered = options.state.pendingAgentMessages.get(itemId);
|
|
719
|
+
if (buffered && buffered.length > 0) {
|
|
720
|
+
timelineItem.text = buffered;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
if (timelineItem.type === "assistant_message" && normalizedItemType === "plan" && itemId) {
|
|
724
|
+
const bufferedPlanText = options.state.pendingPlanTexts.get(itemId) ?? "";
|
|
725
|
+
const finalPlanText = typeof item.text === "string" ? item.text : "";
|
|
726
|
+
if (bufferedPlanText.length > 0) {
|
|
727
|
+
const trailingText = finalPlanText.startsWith(bufferedPlanText)
|
|
728
|
+
? finalPlanText.slice(bufferedPlanText.length)
|
|
729
|
+
: "";
|
|
730
|
+
timelineItem.text = formatProposedPlanChunk(trailingText, {
|
|
731
|
+
close: true,
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
else if (finalPlanText.trim().length > 0) {
|
|
735
|
+
timelineItem.text = formatProposedPlanBlock(finalPlanText);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
if (timelineItem.type === "reasoning" && itemId) {
|
|
739
|
+
const buffered = options.state.pendingReasoning.get(itemId);
|
|
740
|
+
if (buffered && buffered.length > 0) {
|
|
741
|
+
timelineItem.text = buffered.join("");
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
if (itemId) {
|
|
745
|
+
options.state.emittedItemCompletedIds.add(itemId);
|
|
746
|
+
options.state.pendingAgentMessages.delete(itemId);
|
|
747
|
+
options.state.pendingReasoning.delete(itemId);
|
|
748
|
+
options.state.pendingPlanTexts.delete(itemId);
|
|
749
|
+
}
|
|
750
|
+
return timelineItem;
|
|
751
|
+
}
|
|
698
752
|
function planStepsToTodoItems(steps) {
|
|
699
753
|
return steps.map((entry) => ({
|
|
700
754
|
text: entry.step,
|
|
@@ -1492,6 +1546,8 @@ export const __codexAppServerInternals = {
|
|
|
1492
1546
|
shouldRetryInitializeWithoutExperimentalApi,
|
|
1493
1547
|
shouldRetryTurnStartWithoutCollaborationMode,
|
|
1494
1548
|
formatProposedPlanBlock,
|
|
1549
|
+
formatProposedPlanChunk,
|
|
1550
|
+
buildCompletedCodexTimelineItem,
|
|
1495
1551
|
normalizeCodexQuestionDescriptors,
|
|
1496
1552
|
parseUpdatedQuestionAnswers,
|
|
1497
1553
|
buildCodexPermissionsResponse,
|
|
@@ -1536,6 +1592,7 @@ class CodexAppServerAgentSession {
|
|
|
1536
1592
|
this.nativePlanModeSupported = null;
|
|
1537
1593
|
this.pendingPlanTexts = new Map();
|
|
1538
1594
|
this.cachedSkills = [];
|
|
1595
|
+
this.turnCompletionInFlight = false;
|
|
1539
1596
|
this.logger = logger.child({ module: "agent", provider: CODEX_PROVIDER });
|
|
1540
1597
|
if (config.modeId === undefined) {
|
|
1541
1598
|
throw new Error("Codex agent requires modeId to be specified");
|
|
@@ -2269,12 +2326,171 @@ class CodexAppServerAgentSession {
|
|
|
2269
2326
|
return await codexAppServerTurnInputFromPrompt(blocks, this.logger);
|
|
2270
2327
|
}
|
|
2271
2328
|
emitEvent(event) {
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2329
|
+
this.eventQueue?.push(event);
|
|
2330
|
+
}
|
|
2331
|
+
clearTurnState() {
|
|
2332
|
+
this.currentTurnId = null;
|
|
2333
|
+
this.emittedItemStartedIds.clear();
|
|
2334
|
+
this.emittedItemCompletedIds.clear();
|
|
2335
|
+
this.emittedExecCommandStartedCallIds.clear();
|
|
2336
|
+
this.emittedExecCommandCompletedCallIds.clear();
|
|
2337
|
+
this.pendingAgentMessages.clear();
|
|
2338
|
+
this.pendingReasoning.clear();
|
|
2339
|
+
this.pendingCommandOutputDeltas.clear();
|
|
2340
|
+
this.pendingFileChangeOutputDeltas.clear();
|
|
2341
|
+
this.pendingPlanTexts.clear();
|
|
2342
|
+
this.warnedIncompleteEditToolCallIds.clear();
|
|
2343
|
+
this.turnCompletionInFlight = false;
|
|
2344
|
+
}
|
|
2345
|
+
hasPendingBufferedCompletionContent() {
|
|
2346
|
+
return (this.pendingAgentMessages.size > 0 ||
|
|
2347
|
+
this.pendingReasoning.size > 0 ||
|
|
2348
|
+
this.pendingPlanTexts.size > 0);
|
|
2349
|
+
}
|
|
2350
|
+
emitCompletedThreadItem(item, source) {
|
|
2351
|
+
const timelineItem = buildCompletedCodexTimelineItem(item, {
|
|
2352
|
+
cwd: this.config.cwd ?? null,
|
|
2353
|
+
state: {
|
|
2354
|
+
pendingAgentMessages: this.pendingAgentMessages,
|
|
2355
|
+
pendingReasoning: this.pendingReasoning,
|
|
2356
|
+
pendingPlanTexts: this.pendingPlanTexts,
|
|
2357
|
+
emittedExecCommandCompletedCallIds: this.emittedExecCommandCompletedCallIds,
|
|
2358
|
+
emittedItemCompletedIds: this.emittedItemCompletedIds,
|
|
2359
|
+
},
|
|
2360
|
+
});
|
|
2361
|
+
if (!timelineItem) {
|
|
2362
|
+
return false;
|
|
2363
|
+
}
|
|
2364
|
+
const itemId = item.id;
|
|
2365
|
+
if (timelineItem.type === "tool_call") {
|
|
2366
|
+
this.warnOnIncompleteEditToolCall(timelineItem, source, item);
|
|
2367
|
+
}
|
|
2368
|
+
this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
|
|
2369
|
+
if (itemId) {
|
|
2370
|
+
this.emittedItemStartedIds.delete(itemId);
|
|
2371
|
+
this.pendingCommandOutputDeltas.delete(itemId);
|
|
2372
|
+
this.pendingFileChangeOutputDeltas.delete(itemId);
|
|
2373
|
+
}
|
|
2374
|
+
return true;
|
|
2375
|
+
}
|
|
2376
|
+
async reconcileTurnCompletionFromThreadRead() {
|
|
2377
|
+
if (!this.client || !this.currentThreadId) {
|
|
2378
|
+
return 0;
|
|
2379
|
+
}
|
|
2380
|
+
const response = (await this.client.request("thread/read", {
|
|
2381
|
+
threadId: this.currentThreadId,
|
|
2382
|
+
includeTurns: true,
|
|
2383
|
+
}));
|
|
2384
|
+
const turns = Array.isArray(response?.thread?.turns) ? response.thread.turns : [];
|
|
2385
|
+
const lastTurn = turns[turns.length - 1];
|
|
2386
|
+
const items = Array.isArray(lastTurn?.items) ? lastTurn.items : [];
|
|
2387
|
+
let emitted = 0;
|
|
2388
|
+
for (const item of items) {
|
|
2389
|
+
if (this.emitCompletedThreadItem(item, "thread_read_completion")) {
|
|
2390
|
+
emitted += 1;
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
return emitted;
|
|
2394
|
+
}
|
|
2395
|
+
flushPendingCompletionFallback() {
|
|
2396
|
+
let emitted = 0;
|
|
2397
|
+
for (const [itemId, chunks] of Array.from(this.pendingReasoning.entries())) {
|
|
2398
|
+
const text = chunks.join("");
|
|
2399
|
+
if (text.length === 0) {
|
|
2400
|
+
this.pendingReasoning.delete(itemId);
|
|
2401
|
+
continue;
|
|
2275
2402
|
}
|
|
2403
|
+
this.emitEvent({
|
|
2404
|
+
type: "timeline",
|
|
2405
|
+
provider: CODEX_PROVIDER,
|
|
2406
|
+
item: { type: "reasoning", text },
|
|
2407
|
+
});
|
|
2408
|
+
this.emittedItemCompletedIds.add(itemId);
|
|
2409
|
+
this.pendingReasoning.delete(itemId);
|
|
2410
|
+
emitted += 1;
|
|
2411
|
+
}
|
|
2412
|
+
for (const [itemId, text] of Array.from(this.pendingAgentMessages.entries())) {
|
|
2413
|
+
if (text.length === 0) {
|
|
2414
|
+
this.pendingAgentMessages.delete(itemId);
|
|
2415
|
+
continue;
|
|
2416
|
+
}
|
|
2417
|
+
this.emitEvent({
|
|
2418
|
+
type: "timeline",
|
|
2419
|
+
provider: CODEX_PROVIDER,
|
|
2420
|
+
item: { type: "assistant_message", text },
|
|
2421
|
+
});
|
|
2422
|
+
this.emittedItemCompletedIds.add(itemId);
|
|
2423
|
+
this.pendingAgentMessages.delete(itemId);
|
|
2424
|
+
emitted += 1;
|
|
2425
|
+
}
|
|
2426
|
+
for (const [itemId, text] of Array.from(this.pendingPlanTexts.entries())) {
|
|
2427
|
+
if (text.trim().length === 0) {
|
|
2428
|
+
this.pendingPlanTexts.delete(itemId);
|
|
2429
|
+
continue;
|
|
2430
|
+
}
|
|
2431
|
+
this.emitEvent({
|
|
2432
|
+
type: "timeline",
|
|
2433
|
+
provider: CODEX_PROVIDER,
|
|
2434
|
+
item: {
|
|
2435
|
+
type: "assistant_message",
|
|
2436
|
+
text: formatProposedPlanChunk("", { close: true }),
|
|
2437
|
+
},
|
|
2438
|
+
});
|
|
2439
|
+
this.emittedItemCompletedIds.add(itemId);
|
|
2440
|
+
this.pendingPlanTexts.delete(itemId);
|
|
2441
|
+
emitted += 1;
|
|
2442
|
+
}
|
|
2443
|
+
return emitted;
|
|
2444
|
+
}
|
|
2445
|
+
emitTerminalTurnEvent(parsed) {
|
|
2446
|
+
if (parsed.status === "failed") {
|
|
2447
|
+
this.emitEvent({
|
|
2448
|
+
type: "turn_failed",
|
|
2449
|
+
provider: CODEX_PROVIDER,
|
|
2450
|
+
error: parsed.errorMessage ?? "Codex turn failed",
|
|
2451
|
+
});
|
|
2452
|
+
return;
|
|
2453
|
+
}
|
|
2454
|
+
if (parsed.status === "interrupted") {
|
|
2455
|
+
this.emitEvent({ type: "turn_canceled", provider: CODEX_PROVIDER, reason: "interrupted" });
|
|
2456
|
+
return;
|
|
2457
|
+
}
|
|
2458
|
+
this.emitEvent({ type: "turn_completed", provider: CODEX_PROVIDER, usage: this.latestUsage });
|
|
2459
|
+
}
|
|
2460
|
+
async finalizeTurnCompletion(parsed) {
|
|
2461
|
+
let terminalEventEmitted = false;
|
|
2462
|
+
try {
|
|
2463
|
+
if (parsed.status === "completed" && this.hasPendingBufferedCompletionContent()) {
|
|
2464
|
+
this.logger.trace({
|
|
2465
|
+
pendingAgentMessages: this.pendingAgentMessages.size,
|
|
2466
|
+
pendingReasoning: this.pendingReasoning.size,
|
|
2467
|
+
pendingPlanTexts: this.pendingPlanTexts.size,
|
|
2468
|
+
threadId: this.currentThreadId,
|
|
2469
|
+
turnId: this.currentTurnId,
|
|
2470
|
+
}, "Codex turn completed with buffered items still pending; reconciling before closing stream");
|
|
2471
|
+
try {
|
|
2472
|
+
const emitted = await this.reconcileTurnCompletionFromThreadRead();
|
|
2473
|
+
this.logger.trace({ emitted, threadId: this.currentThreadId, turnId: this.currentTurnId }, "Reconciled Codex turn completion from thread/read");
|
|
2474
|
+
}
|
|
2475
|
+
catch (error) {
|
|
2476
|
+
this.logger.warn({ error, threadId: this.currentThreadId, turnId: this.currentTurnId }, "Failed to reconcile Codex turn completion from thread/read");
|
|
2477
|
+
}
|
|
2478
|
+
const fallbackEmitted = this.flushPendingCompletionFallback();
|
|
2479
|
+
if (fallbackEmitted > 0) {
|
|
2480
|
+
this.logger.warn({ fallbackEmitted, threadId: this.currentThreadId, turnId: this.currentTurnId }, "Flushed buffered Codex completion items without canonical item/completed notifications");
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
this.emitTerminalTurnEvent(parsed);
|
|
2484
|
+
terminalEventEmitted = true;
|
|
2485
|
+
}
|
|
2486
|
+
finally {
|
|
2487
|
+
if (!terminalEventEmitted) {
|
|
2488
|
+
this.logger.warn({ status: parsed.status, threadId: this.currentThreadId, turnId: this.currentTurnId }, "Codex turn completion exited before emitting a terminal event; emitting fallback terminal event");
|
|
2489
|
+
this.emitTerminalTurnEvent(parsed);
|
|
2490
|
+
}
|
|
2491
|
+
this.clearTurnState();
|
|
2492
|
+
this.eventQueue?.end();
|
|
2276
2493
|
}
|
|
2277
|
-
this.eventQueue?.push(event);
|
|
2278
2494
|
}
|
|
2279
2495
|
handleNotification(method, params) {
|
|
2280
2496
|
const parsed = CodexNotificationSchema.parse({ method, params });
|
|
@@ -2284,40 +2500,17 @@ class CodexAppServerAgentSession {
|
|
|
2284
2500
|
return;
|
|
2285
2501
|
}
|
|
2286
2502
|
if (parsed.kind === "turn_started") {
|
|
2503
|
+
this.clearTurnState();
|
|
2287
2504
|
this.currentTurnId = parsed.turnId;
|
|
2288
|
-
this.emittedItemStartedIds.clear();
|
|
2289
|
-
this.emittedItemCompletedIds.clear();
|
|
2290
|
-
this.emittedExecCommandStartedCallIds.clear();
|
|
2291
|
-
this.emittedExecCommandCompletedCallIds.clear();
|
|
2292
|
-
this.pendingCommandOutputDeltas.clear();
|
|
2293
|
-
this.pendingFileChangeOutputDeltas.clear();
|
|
2294
|
-
this.warnedIncompleteEditToolCallIds.clear();
|
|
2295
2505
|
this.emitEvent({ type: "turn_started", provider: CODEX_PROVIDER });
|
|
2296
2506
|
return;
|
|
2297
2507
|
}
|
|
2298
2508
|
if (parsed.kind === "turn_completed") {
|
|
2299
|
-
if (
|
|
2300
|
-
|
|
2301
|
-
type: "turn_failed",
|
|
2302
|
-
provider: CODEX_PROVIDER,
|
|
2303
|
-
error: parsed.errorMessage ?? "Codex turn failed",
|
|
2304
|
-
});
|
|
2305
|
-
}
|
|
2306
|
-
else if (parsed.status === "interrupted") {
|
|
2307
|
-
this.emitEvent({ type: "turn_canceled", provider: CODEX_PROVIDER, reason: "interrupted" });
|
|
2509
|
+
if (this.turnCompletionInFlight) {
|
|
2510
|
+
return;
|
|
2308
2511
|
}
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
}
|
|
2312
|
-
this.emittedItemStartedIds.clear();
|
|
2313
|
-
this.emittedItemCompletedIds.clear();
|
|
2314
|
-
this.emittedExecCommandStartedCallIds.clear();
|
|
2315
|
-
this.emittedExecCommandCompletedCallIds.clear();
|
|
2316
|
-
this.pendingCommandOutputDeltas.clear();
|
|
2317
|
-
this.pendingFileChangeOutputDeltas.clear();
|
|
2318
|
-
this.pendingPlanTexts.clear();
|
|
2319
|
-
this.warnedIncompleteEditToolCallIds.clear();
|
|
2320
|
-
this.eventQueue?.end();
|
|
2512
|
+
this.turnCompletionInFlight = true;
|
|
2513
|
+
void this.finalizeTurnCompletion(parsed);
|
|
2321
2514
|
return;
|
|
2322
2515
|
}
|
|
2323
2516
|
if (parsed.kind === "plan_updated") {
|
|
@@ -2473,67 +2666,7 @@ class CodexAppServerAgentSession {
|
|
|
2473
2666
|
if (parsed.source === "codex_event") {
|
|
2474
2667
|
return;
|
|
2475
2668
|
}
|
|
2476
|
-
|
|
2477
|
-
includeUserMessage: false,
|
|
2478
|
-
cwd: this.config.cwd ?? null,
|
|
2479
|
-
});
|
|
2480
|
-
if (timelineItem) {
|
|
2481
|
-
const normalizedItemType = normalizeCodexThreadItemType(typeof parsed.item.type === "string" ? parsed.item.type : undefined);
|
|
2482
|
-
const itemId = parsed.item.id;
|
|
2483
|
-
// For commandExecution items, codex/event/exec_command_* is authoritative.
|
|
2484
|
-
// Keep item/completed as fallback only when no exec_command completion was seen.
|
|
2485
|
-
if (timelineItem.type === "tool_call" &&
|
|
2486
|
-
normalizedItemType === "commandExecution") {
|
|
2487
|
-
const callId = timelineItem.callId || itemId;
|
|
2488
|
-
if (callId && this.emittedExecCommandCompletedCallIds.has(callId)) {
|
|
2489
|
-
return;
|
|
2490
|
-
}
|
|
2491
|
-
}
|
|
2492
|
-
if (itemId && this.emittedItemCompletedIds.has(itemId)) {
|
|
2493
|
-
return;
|
|
2494
|
-
}
|
|
2495
|
-
if (timelineItem.type === "assistant_message" && itemId) {
|
|
2496
|
-
const buffered = this.pendingAgentMessages.get(itemId);
|
|
2497
|
-
if (buffered && buffered.length > 0) {
|
|
2498
|
-
timelineItem.text = buffered;
|
|
2499
|
-
}
|
|
2500
|
-
}
|
|
2501
|
-
if (timelineItem.type === "assistant_message" &&
|
|
2502
|
-
normalizedItemType === "plan" &&
|
|
2503
|
-
itemId) {
|
|
2504
|
-
const bufferedPlanText = this.pendingPlanTexts.get(itemId) ?? "";
|
|
2505
|
-
const finalPlanText = typeof parsed.item.text === "string" ? parsed.item.text : "";
|
|
2506
|
-
if (bufferedPlanText.length > 0) {
|
|
2507
|
-
const trailingText = finalPlanText.startsWith(bufferedPlanText)
|
|
2508
|
-
? finalPlanText.slice(bufferedPlanText.length)
|
|
2509
|
-
: "";
|
|
2510
|
-
timelineItem.text = formatProposedPlanChunk(trailingText, {
|
|
2511
|
-
close: true,
|
|
2512
|
-
});
|
|
2513
|
-
this.pendingPlanTexts.delete(itemId);
|
|
2514
|
-
}
|
|
2515
|
-
else if (finalPlanText.trim().length > 0) {
|
|
2516
|
-
timelineItem.text = formatProposedPlanBlock(finalPlanText);
|
|
2517
|
-
}
|
|
2518
|
-
}
|
|
2519
|
-
if (timelineItem.type === "reasoning" && itemId) {
|
|
2520
|
-
const buffered = this.pendingReasoning.get(itemId);
|
|
2521
|
-
if (buffered && buffered.length > 0) {
|
|
2522
|
-
timelineItem.text = buffered.join("");
|
|
2523
|
-
}
|
|
2524
|
-
}
|
|
2525
|
-
if (timelineItem.type === "tool_call") {
|
|
2526
|
-
this.warnOnIncompleteEditToolCall(timelineItem, "item_completed", parsed.item);
|
|
2527
|
-
}
|
|
2528
|
-
this.emitEvent({ type: "timeline", provider: CODEX_PROVIDER, item: timelineItem });
|
|
2529
|
-
if (itemId) {
|
|
2530
|
-
this.emittedItemCompletedIds.add(itemId);
|
|
2531
|
-
this.emittedItemStartedIds.delete(itemId);
|
|
2532
|
-
this.pendingCommandOutputDeltas.delete(itemId);
|
|
2533
|
-
this.pendingFileChangeOutputDeltas.delete(itemId);
|
|
2534
|
-
this.pendingPlanTexts.delete(itemId);
|
|
2535
|
-
}
|
|
2536
|
-
}
|
|
2669
|
+
this.emitCompletedThreadItem(parsed.item, "item_completed");
|
|
2537
2670
|
return;
|
|
2538
2671
|
}
|
|
2539
2672
|
if (parsed.kind === "item_started") {
|