@gkorepanov/ccodex 0.4.2 → 0.4.3
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/config/compatibility.json +1 -1
- package/dist/claude/environment.d.ts +1 -0
- package/dist/claude/environment.js +6 -0
- package/dist/claude/environment.js.map +1 -0
- package/dist/claude/modelCatalog.js +2 -1
- package/dist/claude/modelCatalog.js.map +1 -1
- package/dist/claude/service.d.ts +1 -1
- package/dist/claude/service.js +7 -4
- package/dist/claude/service.js.map +1 -1
- package/dist/claude/session/providerRuntime.d.ts +1 -1
- package/dist/claude/session/providerRuntime.js +1 -1
- package/dist/claude/session/providerRuntime.js.map +1 -1
- package/dist/claude/session/providerRuntimeFactory.d.ts +1 -0
- package/dist/claude/session/providerRuntimeFactory.js +6 -3
- package/dist/claude/session/providerRuntimeFactory.js.map +1 -1
- package/dist/claude/session/runtime.d.ts +8 -0
- package/dist/claude/session/runtime.js +33 -5
- package/dist/claude/session/runtime.js.map +1 -1
- package/dist/claude/session/scopeState.d.ts +5 -3
- package/dist/claude/session/scopeState.js +3 -0
- package/dist/claude/session/scopeState.js.map +1 -1
- package/dist/claude/session/session.d.ts +4 -0
- package/dist/claude/session/session.js +239 -56
- package/dist/claude/session/session.js.map +1 -1
- package/dist/claude/session/shellRunner.js +2 -1
- package/dist/claude/session/shellRunner.js.map +1 -1
- package/dist/claude/toolMapper.js +8 -3
- package/dist/claude/toolMapper.js.map +1 -1
- package/dist/config/config.d.ts +1 -0
- package/dist/config/config.js +4 -1
- package/dist/config/config.js.map +1 -1
- package/dist/gateway/clientConnection.js +26 -26
- package/dist/gateway/clientConnection.js.map +1 -1
- package/examples/config.toml +1 -0
- package/legal/THIRD_PARTY_NOTICES.md +1 -28
- package/package.json +4 -4
|
@@ -9,7 +9,7 @@ import { ClaudeMailbox, createDeferred, } from "./mailbox.js";
|
|
|
9
9
|
import { remapBoundaries } from "./repository.js";
|
|
10
10
|
import { isImageRead, planSteps, projectToolCompletion, startTool, updateToolInput, } from "../toolMapper.js";
|
|
11
11
|
import { isFileMutationTool, toolPolicy } from "../permissionPolicy.js";
|
|
12
|
-
import { newChildScope, newMainStreamState, scopeProjection, streamItem, toolAt, } from "./scopeState.js";
|
|
12
|
+
import { newChildScope, newMainStreamState, scopeProjection, streamItem, taskUsesProvider, toolAt, } from "./scopeState.js";
|
|
13
13
|
import { systemNoticeText } from "../../gateway/transientNotice.js";
|
|
14
14
|
import { isClaudeStatusCommand } from "../statusCommand.js";
|
|
15
15
|
import { isCCodexStateCommand } from "../../state/stateCommand.js";
|
|
@@ -23,6 +23,7 @@ import { mapUserInput } from "../inputMapper.js";
|
|
|
23
23
|
import { bashCommandActions } from "../commandActions.js";
|
|
24
24
|
import { safeSessionPermissionUpdates } from "./permissionUpdates.js";
|
|
25
25
|
import { StaleClaudeRuntimeSettingsError, createProviderRuntime, providerPermissionMode, providerRuntimeSettings, runtimeTransportSettings, } from "./providerRuntimeFactory.js";
|
|
26
|
+
import { isRetryableClaudeRuntimeStartupError, } from "./providerRuntime.js";
|
|
26
27
|
import { assistantHasTools, backgroundOutputFile, backgroundTaskId, isNoQueryAcknowledgement, serverToolResult, toolResults, } from "./providerFacts.js";
|
|
27
28
|
const nullSource = { providerEventId: null, providerEventType: null };
|
|
28
29
|
const providerJournalMaxEvents = 20_000;
|
|
@@ -193,10 +194,26 @@ export class ClaudeSession {
|
|
|
193
194
|
}
|
|
194
195
|
async ensureRuntime(reinitialize = false) {
|
|
195
196
|
const owner = await this.requireRuntimeOwner();
|
|
196
|
-
|
|
197
|
+
try {
|
|
198
|
+
await owner.ready;
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
await owner.activation.promise;
|
|
202
|
+
throw error;
|
|
203
|
+
}
|
|
197
204
|
if (reinitialize)
|
|
198
205
|
await owner.runtime.reinitialize();
|
|
199
206
|
}
|
|
207
|
+
async ensureEphemeralRuntime() {
|
|
208
|
+
try {
|
|
209
|
+
await this.ensureRuntime();
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
if (!isRetryableClaudeRuntimeStartupError(error))
|
|
213
|
+
throw error;
|
|
214
|
+
await this.ensureRuntime();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
200
217
|
async materializeRuntime() {
|
|
201
218
|
for (;;) {
|
|
202
219
|
const claim = await this.submitLineage({
|
|
@@ -558,6 +575,7 @@ export class ClaudeSession {
|
|
|
558
575
|
reasoningSummary: record.reasoningSummary,
|
|
559
576
|
collaborationMode: record.collaborationMode,
|
|
560
577
|
outputSchema: record.outputSchema,
|
|
578
|
+
interactiveQuestions: this.runtimeDependencies.interactiveQuestions ?? true,
|
|
561
579
|
};
|
|
562
580
|
}
|
|
563
581
|
async createRuntimeGeneration(startup) {
|
|
@@ -592,7 +610,8 @@ export class ClaudeSession {
|
|
|
592
610
|
const ready = this.waitForProviderRuntime(runtime);
|
|
593
611
|
await Promise.resolve();
|
|
594
612
|
if (runtime.hasExited) {
|
|
595
|
-
|
|
613
|
+
await ready;
|
|
614
|
+
throw runtime.initializationFailure(new Error(`Claude runtime '${this.threadId}' became unavailable during initialization.`));
|
|
596
615
|
}
|
|
597
616
|
const transportSettings = runtimeTransportSettings(startup);
|
|
598
617
|
const rateLimitGeneration = dependencies.rateLimits.register({
|
|
@@ -650,6 +669,9 @@ export class ClaudeSession {
|
|
|
650
669
|
}),
|
|
651
670
|
]);
|
|
652
671
|
}
|
|
672
|
+
catch (error) {
|
|
673
|
+
throw runtime.initializationFailure(error);
|
|
674
|
+
}
|
|
653
675
|
finally {
|
|
654
676
|
if (timer)
|
|
655
677
|
clearTimeout(timer);
|
|
@@ -1152,7 +1174,6 @@ export class ClaudeSession {
|
|
|
1152
1174
|
}
|
|
1153
1175
|
catch (error) {
|
|
1154
1176
|
failure = error instanceof Error ? error.message : String(error);
|
|
1155
|
-
throw error;
|
|
1156
1177
|
}
|
|
1157
1178
|
finally {
|
|
1158
1179
|
await this.submitProviderProjection(fact.runtimeGeneration, {
|
|
@@ -1164,6 +1185,15 @@ export class ClaudeSession {
|
|
|
1164
1185
|
...(failure ? { error: failure } : {}),
|
|
1165
1186
|
});
|
|
1166
1187
|
}
|
|
1188
|
+
if (failure) {
|
|
1189
|
+
await this.submitProviderProjection(fact.runtimeGeneration, {
|
|
1190
|
+
type: "runtimeExited",
|
|
1191
|
+
runtimeGeneration: fact.runtimeGeneration,
|
|
1192
|
+
message: `Claude provider projection failed: ${failure}`,
|
|
1193
|
+
codexErrorInfo: null,
|
|
1194
|
+
});
|
|
1195
|
+
runtime.beginClose();
|
|
1196
|
+
}
|
|
1167
1197
|
});
|
|
1168
1198
|
}
|
|
1169
1199
|
async projectProviderMessage(projection, runtime, runtimeGeneration, message) {
|
|
@@ -1265,7 +1295,9 @@ export class ClaudeSession {
|
|
|
1265
1295
|
description: message.summary,
|
|
1266
1296
|
outputFile: message.output_file,
|
|
1267
1297
|
}, owner);
|
|
1268
|
-
|
|
1298
|
+
if (owner === this.threadId) {
|
|
1299
|
+
await this.providerSubmitLifecycle(projection, runtimeGeneration, { type: "taskNotification" });
|
|
1300
|
+
}
|
|
1269
1301
|
await this.applyProviderMainStream(projection, runtimeGeneration, {
|
|
1270
1302
|
kind: "taskComplete",
|
|
1271
1303
|
taskId: message.task_id,
|
|
@@ -1321,9 +1353,12 @@ export class ClaudeSession {
|
|
|
1321
1353
|
return "stateOnly";
|
|
1322
1354
|
}
|
|
1323
1355
|
if (message.type === "stream_event") {
|
|
1324
|
-
const
|
|
1325
|
-
if (
|
|
1326
|
-
await this.providerChildStreamEvent(projection, runtimeGeneration,
|
|
1356
|
+
const child = await this.providerChildThreadFor(runtimeGeneration, message.parent_tool_use_id);
|
|
1357
|
+
if (child?.active) {
|
|
1358
|
+
await this.providerChildStreamEvent(projection, runtimeGeneration, child.threadId, message);
|
|
1359
|
+
}
|
|
1360
|
+
else if (child) {
|
|
1361
|
+
return "retainedOnly";
|
|
1327
1362
|
}
|
|
1328
1363
|
else {
|
|
1329
1364
|
await this.providerMainStreamEvent(projection, runtimeGeneration, message);
|
|
@@ -1346,12 +1381,14 @@ export class ClaudeSession {
|
|
|
1346
1381
|
if (message.supersedes?.length) {
|
|
1347
1382
|
await this.providerEvictMessages(projection, runtimeGeneration, message.supersedes);
|
|
1348
1383
|
}
|
|
1349
|
-
const
|
|
1350
|
-
if (
|
|
1351
|
-
const itemIds = await this.providerProjectAssistant(projection, runtimeGeneration, message,
|
|
1352
|
-
await this.providerLinkItems(runtimeGeneration, message.uuid,
|
|
1384
|
+
const child = await this.providerChildThreadFor(runtimeGeneration, message.parent_tool_use_id);
|
|
1385
|
+
if (child?.active) {
|
|
1386
|
+
const itemIds = await this.providerProjectAssistant(projection, runtimeGeneration, message, child.threadId);
|
|
1387
|
+
await this.providerLinkItems(runtimeGeneration, message.uuid, child.threadId, itemIds);
|
|
1353
1388
|
return "projected";
|
|
1354
1389
|
}
|
|
1390
|
+
if (child)
|
|
1391
|
+
return "retainedOnly";
|
|
1355
1392
|
if (activeTurnId) {
|
|
1356
1393
|
if (message.error) {
|
|
1357
1394
|
await this.submitProviderProjection(runtimeGeneration, {
|
|
@@ -1387,14 +1424,16 @@ export class ClaudeSession {
|
|
|
1387
1424
|
if ("uuid" in message && typeof message.uuid === "string") {
|
|
1388
1425
|
runtime.releaseMessage(message.uuid);
|
|
1389
1426
|
}
|
|
1390
|
-
const
|
|
1391
|
-
if (
|
|
1392
|
-
const itemIds = await this.providerProjectToolResults(projection, runtimeGeneration, message,
|
|
1427
|
+
const child = await this.providerChildThreadFor(runtimeGeneration, message.parent_tool_use_id);
|
|
1428
|
+
if (child?.active) {
|
|
1429
|
+
const itemIds = await this.providerProjectToolResults(projection, runtimeGeneration, message, child.threadId);
|
|
1393
1430
|
if ("uuid" in message && typeof message.uuid === "string") {
|
|
1394
|
-
await this.providerLinkItems(runtimeGeneration, message.uuid,
|
|
1431
|
+
await this.providerLinkItems(runtimeGeneration, message.uuid, child.threadId, itemIds);
|
|
1395
1432
|
}
|
|
1396
1433
|
return "projected";
|
|
1397
1434
|
}
|
|
1435
|
+
if (child)
|
|
1436
|
+
return "retainedOnly";
|
|
1398
1437
|
if (activeTurnId && "uuid" in message && typeof message.uuid === "string") {
|
|
1399
1438
|
await this.submitProviderProjection(runtimeGeneration, {
|
|
1400
1439
|
type: "providerBoundary",
|
|
@@ -1717,6 +1756,12 @@ export class ClaudeSession {
|
|
|
1717
1756
|
if (name === "AskUserQuestion") {
|
|
1718
1757
|
return this.askProviderUser(projection, runtimeGeneration, input, options);
|
|
1719
1758
|
}
|
|
1759
|
+
if (providerPermissionMode(settings) === "auto") {
|
|
1760
|
+
return {
|
|
1761
|
+
behavior: "deny",
|
|
1762
|
+
message: options.decisionReason ?? options.description ?? `Claude Auto did not allow tool '${name}'.`,
|
|
1763
|
+
};
|
|
1764
|
+
}
|
|
1720
1765
|
if (name === "ExitPlanMode") {
|
|
1721
1766
|
return {
|
|
1722
1767
|
behavior: "deny",
|
|
@@ -2024,11 +2069,14 @@ export class ClaudeSession {
|
|
|
2024
2069
|
async providerChildThreadFor(runtimeGeneration, providerId) {
|
|
2025
2070
|
if (!providerId)
|
|
2026
2071
|
return undefined;
|
|
2027
|
-
|
|
2072
|
+
const inspection = await this.submitProviderProjection(runtimeGeneration, {
|
|
2028
2073
|
type: "inspectRuntime",
|
|
2029
2074
|
runtimeGeneration,
|
|
2030
2075
|
providerId,
|
|
2031
|
-
})
|
|
2076
|
+
});
|
|
2077
|
+
return inspection.childThreadId
|
|
2078
|
+
? { threadId: inspection.childThreadId, active: inspection.interruptible }
|
|
2079
|
+
: undefined;
|
|
2032
2080
|
}
|
|
2033
2081
|
async providerLinkItems(runtimeGeneration, providerMessageId, ownerThreadId, itemIds) {
|
|
2034
2082
|
await this.submitProviderProjection(runtimeGeneration, {
|
|
@@ -4106,8 +4154,22 @@ export class ClaudeSession {
|
|
|
4106
4154
|
if (command.runtimeGeneration !== this.runtimeGeneration
|
|
4107
4155
|
|| this.interruptFence || this.dropLateFacts)
|
|
4108
4156
|
return undefined;
|
|
4109
|
-
|
|
4110
|
-
|
|
4157
|
+
{
|
|
4158
|
+
const ownerThreadId = command.ownerThreadId ?? this.threadId;
|
|
4159
|
+
if (!this.scopes.has(ownerThreadId)) {
|
|
4160
|
+
if (command.fact.kind === "inspect")
|
|
4161
|
+
return undefined;
|
|
4162
|
+
switch (command.fact.kind) {
|
|
4163
|
+
case "taskStart":
|
|
4164
|
+
case "taskProgress":
|
|
4165
|
+
case "taskMembership":
|
|
4166
|
+
case "taskOutput":
|
|
4167
|
+
case "taskComplete":
|
|
4168
|
+
case "taskStop":
|
|
4169
|
+
return this.projectDetachedTaskFact(command.fact, command.source);
|
|
4170
|
+
}
|
|
4171
|
+
}
|
|
4172
|
+
}
|
|
4111
4173
|
{
|
|
4112
4174
|
if (command.fact.kind === "taskComplete" && !command.fact.outputDrained) {
|
|
4113
4175
|
const task = this.tasks.get(command.fact.taskId);
|
|
@@ -4331,27 +4393,14 @@ export class ClaudeSession {
|
|
|
4331
4393
|
if (this.dropLateFacts || this.adminOperation && this.adminOperation.kind !== "rename"
|
|
4332
4394
|
|| this.repository.archived(command.threadId))
|
|
4333
4395
|
return false;
|
|
4334
|
-
const
|
|
4335
|
-
if (!
|
|
4396
|
+
const state = this.scopes.get(command.threadId);
|
|
4397
|
+
if (!state || command.requestedTurnId && command.requestedTurnId !== state.turnId
|
|
4398
|
+
|| this.repository.readTurn(command.threadId, state.turnId)?.status !== "inProgress")
|
|
4336
4399
|
return false;
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
?? uuidv7();
|
|
4342
|
-
const params = {
|
|
4343
|
-
error: {
|
|
4344
|
-
message: command.message,
|
|
4345
|
-
codexErrorInfo: command.codexErrorInfo,
|
|
4346
|
-
additionalDetails: null,
|
|
4347
|
-
},
|
|
4348
|
-
willRetry: false,
|
|
4349
|
-
threadId: command.threadId,
|
|
4350
|
-
turnId,
|
|
4351
|
-
};
|
|
4352
|
-
if (this.repository.appendEvent(command.threadId, turnId, "error", params)) {
|
|
4353
|
-
this.output.emit(command.threadId, "error", params);
|
|
4354
|
-
}
|
|
4400
|
+
this.projectMainStream(command.threadId, {
|
|
4401
|
+
kind: "instantAgent",
|
|
4402
|
+
text: systemNoticeText(command.message, "error"),
|
|
4403
|
+
}, nullSource);
|
|
4355
4404
|
return true;
|
|
4356
4405
|
}
|
|
4357
4406
|
case "startCompact": {
|
|
@@ -5188,8 +5237,13 @@ export class ClaudeSession {
|
|
|
5188
5237
|
this.pendingNoQuery = this.pendingInputs = 0;
|
|
5189
5238
|
this.preparedRuntimeInputs.clear();
|
|
5190
5239
|
this.disposeRuntimeOperations();
|
|
5191
|
-
if (active)
|
|
5240
|
+
if (active) {
|
|
5192
5241
|
active.commandCompleted = true;
|
|
5242
|
+
active.acknowledged = active.notifications;
|
|
5243
|
+
active.goals = 0;
|
|
5244
|
+
active.goalInFlight = false;
|
|
5245
|
+
delete active.request;
|
|
5246
|
+
}
|
|
5193
5247
|
this.settleForcedScopes(source);
|
|
5194
5248
|
if (fact.type === "runtimeExit" && generation !== undefined) {
|
|
5195
5249
|
this.runtimeGeneration = undefined;
|
|
@@ -5199,8 +5253,10 @@ export class ClaudeSession {
|
|
|
5199
5253
|
else if (fact.type === "timer" && active?.result && this.hasNotifications()
|
|
5200
5254
|
&& fact.generation === active.notifications && fact.generation > active.diagnosed) {
|
|
5201
5255
|
active.diagnosed = fact.generation;
|
|
5202
|
-
this.
|
|
5203
|
-
|
|
5256
|
+
this.runtimeDependencies?.logger.warn("claude.lifecycle.notification-unacknowledged", {
|
|
5257
|
+
threadId: this.threadId,
|
|
5258
|
+
generation: fact.generation,
|
|
5259
|
+
});
|
|
5204
5260
|
}
|
|
5205
5261
|
this.maybeFinish(source, fact.type === "sync");
|
|
5206
5262
|
}
|
|
@@ -5759,7 +5815,7 @@ export class ClaudeSession {
|
|
|
5759
5815
|
let owner = this.toolOwner(command.providerId);
|
|
5760
5816
|
if (!owner && command.ownerProviderId) {
|
|
5761
5817
|
owner = this.toolOwner(command.ownerProviderId);
|
|
5762
|
-
const task = [...this.tasks.values()].find((candidate) => candidate
|
|
5818
|
+
const task = [...this.tasks.values()].find((candidate) => taskUsesProvider(candidate, command.ownerProviderId) || candidate.taskId === command.ownerProviderId);
|
|
5763
5819
|
if (task?.childThreadId)
|
|
5764
5820
|
owner = this.scopes.get(task.childThreadId);
|
|
5765
5821
|
}
|
|
@@ -5892,11 +5948,12 @@ export class ClaudeSession {
|
|
|
5892
5948
|
}
|
|
5893
5949
|
let ownerThreadId = command.ownerThreadId ?? this.threadId;
|
|
5894
5950
|
let targetThreadId = ownerThreadId;
|
|
5951
|
+
let providerTask;
|
|
5895
5952
|
if (command.providerId) {
|
|
5896
5953
|
const scope = [...this.scopes.values()].find((candidate) => candidate.tools.has(command.providerId));
|
|
5897
|
-
|
|
5898
|
-
ownerThreadId =
|
|
5899
|
-
targetThreadId = ownerThreadId;
|
|
5954
|
+
providerTask = [...this.tasks.values()].find((candidate) => taskUsesProvider(candidate, command.providerId) || candidate.taskId === command.providerId);
|
|
5955
|
+
ownerThreadId = providerTask?.ownerThreadId ?? scope?.ownerThreadId ?? ownerThreadId;
|
|
5956
|
+
targetThreadId = providerTask?.childThreadId ?? ownerThreadId;
|
|
5900
5957
|
}
|
|
5901
5958
|
const childTask = command.childThreadId
|
|
5902
5959
|
? [...this.tasks.values()].find((candidate) => candidate.childThreadId === command.childThreadId)
|
|
@@ -5923,12 +5980,14 @@ export class ClaudeSession {
|
|
|
5923
5980
|
modelContextWindow: this.requireRecord(false).modelContextWindow,
|
|
5924
5981
|
interruptible: command.expectedTurnId
|
|
5925
5982
|
? targetState?.turnId === command.expectedTurnId
|
|
5926
|
-
: childTask ? !childTask.terminal && Boolean(targetState)
|
|
5983
|
+
: childTask ? !childTask.terminal && Boolean(targetState)
|
|
5984
|
+
: providerTask?.childThreadId ? !providerTask.terminal && Boolean(targetState)
|
|
5985
|
+
: Boolean(targetState),
|
|
5927
5986
|
ownerThreadId,
|
|
5928
5987
|
ownerTurnId: ownerState?.turnId ?? null,
|
|
5929
5988
|
taskIds,
|
|
5930
5989
|
childThreadId: command.providerId
|
|
5931
|
-
? [...this.tasks.values()].find((task) => task
|
|
5990
|
+
? [...this.tasks.values()].find((task) => taskUsesProvider(task, command.providerId) || task.taskId === command.providerId)?.childThreadId ?? null
|
|
5932
5991
|
: null,
|
|
5933
5992
|
taskId: childTask?.taskId ?? null,
|
|
5934
5993
|
quiescent: this.isQuiescent(),
|
|
@@ -6346,8 +6405,9 @@ export class ClaudeSession {
|
|
|
6346
6405
|
const existing = tool && turn.items.find((item) => item.id === tool.itemId);
|
|
6347
6406
|
const subagent = Boolean(fact.subagentType) || fact.taskType === "agent" || fact.taskType === "subagent";
|
|
6348
6407
|
if (!task && !existing && !subagent) {
|
|
6408
|
+
const providerId = fact.providerId ?? fact.taskId;
|
|
6349
6409
|
task = { taskId: fact.taskId, ownerThreadId: state.ownerThreadId,
|
|
6350
|
-
itemId: `claude-task:${fact.taskId}`, providerId:
|
|
6410
|
+
itemId: `claude-task:${fact.taskId}`, providerId, providerIds: new Set([providerId]),
|
|
6351
6411
|
turnId: turn.id, childThreadId: undefined, outputFile: fact.outputFile, terminal: false };
|
|
6352
6412
|
this.tasks.set(task.taskId, task);
|
|
6353
6413
|
}
|
|
@@ -6357,8 +6417,9 @@ export class ClaudeSession {
|
|
|
6357
6417
|
status: "inProgress", senderThreadId: state.ownerThreadId, receiverThreadIds: [],
|
|
6358
6418
|
prompt: fact.prompt ?? fact.description, model: null, reasoningEffort: null, agentsStates: {},
|
|
6359
6419
|
};
|
|
6420
|
+
const providerId = fact.providerId ?? item.id;
|
|
6360
6421
|
const createdTask = { taskId: fact.taskId, ownerThreadId: state.ownerThreadId, itemId: item.id,
|
|
6361
|
-
providerId:
|
|
6422
|
+
providerId, providerIds: new Set([providerId]), turnId: turn.id, childThreadId: undefined,
|
|
6362
6423
|
outputFile: fact.outputFile, terminal: false };
|
|
6363
6424
|
task = createdTask;
|
|
6364
6425
|
this.tasks.set(createdTask.taskId, createdTask);
|
|
@@ -6375,6 +6436,25 @@ export class ClaudeSession {
|
|
|
6375
6436
|
item.agentsStates = { [childThread.id]: { status: "running", message: fact.description } };
|
|
6376
6437
|
}
|
|
6377
6438
|
}
|
|
6439
|
+
const resumed = task?.terminal && subagent && task.childThreadId && fact.providerId
|
|
6440
|
+
&& !taskUsesProvider(task, fact.providerId);
|
|
6441
|
+
if (resumed && task?.childThreadId) {
|
|
6442
|
+
childThread = this.resumeChildScope(task.childThreadId, fact, source);
|
|
6443
|
+
task.terminal = false;
|
|
6444
|
+
task.providerId = fact.providerId;
|
|
6445
|
+
task.providerIds.add(fact.providerId);
|
|
6446
|
+
task.itemId = existing?.id ?? task.itemId;
|
|
6447
|
+
task.turnId = turn.id;
|
|
6448
|
+
task.outputFile = fact.outputFile;
|
|
6449
|
+
if (existing?.type === "collabAgentToolCall") {
|
|
6450
|
+
existing.receiverThreadIds = [task.childThreadId];
|
|
6451
|
+
existing.agentsStates = {
|
|
6452
|
+
[task.childThreadId]: { status: "running", message: fact.description },
|
|
6453
|
+
};
|
|
6454
|
+
if (tool)
|
|
6455
|
+
this.beginTool(turn, state, tool, true, source);
|
|
6456
|
+
}
|
|
6457
|
+
}
|
|
6378
6458
|
if (task && tool) {
|
|
6379
6459
|
tool.backgroundTaskId = task.taskId;
|
|
6380
6460
|
if (task.outputFile)
|
|
@@ -6402,8 +6482,24 @@ export class ClaudeSession {
|
|
|
6402
6482
|
handled = taskIds.length > 0;
|
|
6403
6483
|
}
|
|
6404
6484
|
else if (task) {
|
|
6405
|
-
const ownerState = this.
|
|
6485
|
+
const ownerState = this.scopes.get(task.ownerThreadId);
|
|
6406
6486
|
const ownerTurn = this.repository.readTurn(task.ownerThreadId, task.turnId);
|
|
6487
|
+
if (!ownerState || !ownerTurn || ownerTurn.status !== "inProgress") {
|
|
6488
|
+
if (fact.kind === "taskComplete" && !task.terminal) {
|
|
6489
|
+
this.stopBackgroundTailer(task);
|
|
6490
|
+
task.outputFile = fact.outputFile ?? task.outputFile;
|
|
6491
|
+
task.terminal = true;
|
|
6492
|
+
if (task.childThreadId)
|
|
6493
|
+
this.finishChildScope(task.childThreadId, fact.status, fact.summary, source);
|
|
6494
|
+
}
|
|
6495
|
+
return scopeProjection(turn, {
|
|
6496
|
+
handled: fact.kind === "taskComplete",
|
|
6497
|
+
taskIds: [task.taskId],
|
|
6498
|
+
outputFile: task.outputFile,
|
|
6499
|
+
childThreadId: task.childThreadId,
|
|
6500
|
+
terminal: task.terminal,
|
|
6501
|
+
});
|
|
6502
|
+
}
|
|
6407
6503
|
const item = ownerTurn.items.find((candidate) => candidate.id === task.itemId);
|
|
6408
6504
|
if (fact.kind === "taskProgress") {
|
|
6409
6505
|
if (item?.type === "collabAgentToolCall")
|
|
@@ -6444,10 +6540,12 @@ export class ClaudeSession {
|
|
|
6444
6540
|
status: fact.status === "completed" ? "completed" : fact.status === "stopped" ? "interrupted" : "errored",
|
|
6445
6541
|
message: fact.summary,
|
|
6446
6542
|
};
|
|
6447
|
-
ownerState.completedItems.
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6543
|
+
if (item.tool !== "sendInput" || !ownerState.completedItems.has(item.id)) {
|
|
6544
|
+
ownerState.completedItems.add(item.id);
|
|
6545
|
+
this.publishTurn(ownerTurn, "item/completed", {
|
|
6546
|
+
item, threadId: task.ownerThreadId, turnId: ownerTurn.id, completedAtMs: Date.now(),
|
|
6547
|
+
}, source);
|
|
6548
|
+
}
|
|
6451
6549
|
}
|
|
6452
6550
|
if (task.childThreadId)
|
|
6453
6551
|
this.finishChildScope(task.childThreadId, fact.status, fact.summary, source);
|
|
@@ -6488,11 +6586,49 @@ export class ClaudeSession {
|
|
|
6488
6586
|
tool: task ? this.scopes.get(task.ownerThreadId)?.tools.get(task.providerId) : undefined,
|
|
6489
6587
|
});
|
|
6490
6588
|
}
|
|
6589
|
+
projectDetachedTaskFact(fact, source) {
|
|
6590
|
+
if (!("taskId" in fact))
|
|
6591
|
+
return undefined;
|
|
6592
|
+
const task = this.tasks.get(fact.taskId);
|
|
6593
|
+
if (!task)
|
|
6594
|
+
return undefined;
|
|
6595
|
+
const turn = this.repository.readTurn(task.ownerThreadId, task.turnId);
|
|
6596
|
+
if (!turn)
|
|
6597
|
+
return undefined;
|
|
6598
|
+
if (fact.kind === "taskStart") {
|
|
6599
|
+
task.outputFile = fact.outputFile ?? task.outputFile;
|
|
6600
|
+
}
|
|
6601
|
+
else if (fact.kind === "taskComplete" && !task.terminal) {
|
|
6602
|
+
this.stopBackgroundTailer(task);
|
|
6603
|
+
task.outputFile = fact.outputFile ?? task.outputFile;
|
|
6604
|
+
task.terminal = true;
|
|
6605
|
+
if (task.childThreadId)
|
|
6606
|
+
this.finishChildScope(task.childThreadId, fact.status, fact.summary, source);
|
|
6607
|
+
}
|
|
6608
|
+
return scopeProjection(turn, {
|
|
6609
|
+
handled: true,
|
|
6610
|
+
taskIds: [task.taskId],
|
|
6611
|
+
outputFile: task.outputFile,
|
|
6612
|
+
childThreadId: task.childThreadId,
|
|
6613
|
+
terminal: task.terminal,
|
|
6614
|
+
});
|
|
6615
|
+
}
|
|
6491
6616
|
updateTool(turn, state, tool, input, source) {
|
|
6492
6617
|
const item = turn.items.find((candidate) => candidate.id === tool.itemId);
|
|
6493
6618
|
if (!item)
|
|
6494
6619
|
return;
|
|
6495
6620
|
updateToolInput(item, tool, input, state.record.thread.cwd);
|
|
6621
|
+
if (item.type === "collabAgentToolCall" && item.tool === "sendInput") {
|
|
6622
|
+
const target = typeof input.to === "string" ? input.to
|
|
6623
|
+
: typeof input.recipient === "string" ? input.recipient : undefined;
|
|
6624
|
+
const task = target ? this.tasks.get(target) : undefined;
|
|
6625
|
+
if (task?.childThreadId) {
|
|
6626
|
+
item.receiverThreadIds = [task.childThreadId];
|
|
6627
|
+
item.agentsStates = {
|
|
6628
|
+
[task.childThreadId]: { status: task.terminal ? "completed" : "running", message: null },
|
|
6629
|
+
};
|
|
6630
|
+
}
|
|
6631
|
+
}
|
|
6496
6632
|
if (tool.name === "TaskOutput") {
|
|
6497
6633
|
const id = typeof input.task_id === "string" ? input.task_id
|
|
6498
6634
|
: typeof input.taskId === "string" ? input.taskId : undefined;
|
|
@@ -6511,6 +6647,9 @@ export class ClaudeSession {
|
|
|
6511
6647
|
if (!item || tool.started || tool.foldedTaskId || isImageRead(tool, record.thread.cwd)
|
|
6512
6648
|
|| item.type === "commandExecution" && !item.command)
|
|
6513
6649
|
return;
|
|
6650
|
+
if (item.type === "collabAgentToolCall" && item.tool === "sendInput"
|
|
6651
|
+
&& (!item.prompt || item.receiverThreadIds.length === 0))
|
|
6652
|
+
return;
|
|
6514
6653
|
if (tool.name === "Bash" && tool.input.run_in_background === true && !tool.backgroundTaskId)
|
|
6515
6654
|
return;
|
|
6516
6655
|
if (!force
|
|
@@ -6565,6 +6704,50 @@ export class ClaudeSession {
|
|
|
6565
6704
|
this.publishAt(childThreadId, turn.id, "item/completed", { item, threadId: childThreadId, turnId: turn.id, completedAtMs: Date.now() }, source);
|
|
6566
6705
|
return thread;
|
|
6567
6706
|
}
|
|
6707
|
+
resumeChildScope(childThreadId, fact, source) {
|
|
6708
|
+
const record = this.repository.read(childThreadId, false);
|
|
6709
|
+
if (!record)
|
|
6710
|
+
throw new Error(`Unknown Claude child thread '${childThreadId}'.`);
|
|
6711
|
+
const startedAt = Math.floor(Date.now() / 1_000);
|
|
6712
|
+
const text = fact.prompt ?? fact.description;
|
|
6713
|
+
const item = {
|
|
6714
|
+
type: "userMessage", id: uuidv7(), clientId: null,
|
|
6715
|
+
content: [{ type: "text", text, text_elements: [] }],
|
|
6716
|
+
};
|
|
6717
|
+
const turn = {
|
|
6718
|
+
id: uuidv7(), items: [item], itemsView: "full", status: "inProgress", error: null,
|
|
6719
|
+
startedAt, completedAt: null, durationMs: null,
|
|
6720
|
+
};
|
|
6721
|
+
const updated = {
|
|
6722
|
+
...record,
|
|
6723
|
+
thread: {
|
|
6724
|
+
...record.thread,
|
|
6725
|
+
preview: text,
|
|
6726
|
+
status: { type: "active", activeFlags: [] },
|
|
6727
|
+
updatedAt: startedAt,
|
|
6728
|
+
recencyAt: startedAt,
|
|
6729
|
+
},
|
|
6730
|
+
};
|
|
6731
|
+
const status = { threadId: childThreadId, status: updated.thread.status };
|
|
6732
|
+
this.commitState(updated, [{
|
|
6733
|
+
turnId: turn.id,
|
|
6734
|
+
method: "thread/status/changed",
|
|
6735
|
+
params: status,
|
|
6736
|
+
providerEventId: source.providerEventId,
|
|
6737
|
+
providerEventType: source.providerEventType,
|
|
6738
|
+
}], turn, true);
|
|
6739
|
+
const state = newMainStreamState(childThreadId, turn.id, updated);
|
|
6740
|
+
state.completedItems.add(item.id);
|
|
6741
|
+
this.scopes.set(childThreadId, state);
|
|
6742
|
+
this.publishAt(childThreadId, turn.id, "turn/started", { threadId: childThreadId, turn }, source);
|
|
6743
|
+
this.publishAt(childThreadId, turn.id, "item/started", {
|
|
6744
|
+
item, threadId: childThreadId, turnId: turn.id, startedAtMs: Date.now(),
|
|
6745
|
+
}, source);
|
|
6746
|
+
this.publishAt(childThreadId, turn.id, "item/completed", {
|
|
6747
|
+
item, threadId: childThreadId, turnId: turn.id, completedAtMs: Date.now(),
|
|
6748
|
+
}, source);
|
|
6749
|
+
return updated.thread;
|
|
6750
|
+
}
|
|
6568
6751
|
finishChildScope(childThreadId, status, summary, source) {
|
|
6569
6752
|
const state = this.scopes.get(childThreadId);
|
|
6570
6753
|
const record = this.repository.read(childThreadId, false);
|