@linzumi/cli 0.0.84-beta → 0.0.85-beta
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/README.md +1 -1
- package/dist/index.js +332 -196
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -9822,7 +9822,11 @@ async function handleKandanChatEvent(args, state, runnerIdentity, payloadContext
|
|
|
9822
9822
|
seq: event.seq,
|
|
9823
9823
|
actor_slug: event.actorSlug ?? null,
|
|
9824
9824
|
actor_user_id: event.actorUserId ?? null,
|
|
9825
|
-
reason: "different_thread"
|
|
9825
|
+
reason: "different_thread",
|
|
9826
|
+
thread_id: event.threadId ?? null,
|
|
9827
|
+
bound_thread_id: state.kandanThreadId ?? null,
|
|
9828
|
+
codex_thread_id: state.codexThreadId ?? null,
|
|
9829
|
+
body_preview: runnerConsoleBodyPreview(event.body)
|
|
9826
9830
|
});
|
|
9827
9831
|
return;
|
|
9828
9832
|
}
|
|
@@ -12440,87 +12444,83 @@ async function startClaudeCodeSession(options) {
|
|
|
12440
12444
|
assistantTextByKey: /* @__PURE__ */ new Map(),
|
|
12441
12445
|
usage: void 0,
|
|
12442
12446
|
startedSessionIds: /* @__PURE__ */ new Set(),
|
|
12443
|
-
completedTurnCount: 0
|
|
12447
|
+
completedTurnCount: 0,
|
|
12448
|
+
lastCompletedTurnBody: void 0
|
|
12444
12449
|
};
|
|
12445
12450
|
const streamUsageTracker = createClaudeCodeStreamUsageTracker();
|
|
12446
|
-
|
|
12447
|
-
|
|
12448
|
-
|
|
12449
|
-
|
|
12450
|
-
state.startedSessionIds.
|
|
12451
|
-
|
|
12452
|
-
|
|
12453
|
-
|
|
12454
|
-
|
|
12455
|
-
|
|
12456
|
-
|
|
12457
|
-
|
|
12458
|
-
|
|
12459
|
-
|
|
12460
|
-
|
|
12461
|
-
|
|
12462
|
-
|
|
12463
|
-
|
|
12464
|
-
await options.onTranscriptEvent?.(event);
|
|
12465
|
-
}
|
|
12466
|
-
const resultOutcome = extractClaudeResultOutcome(message);
|
|
12467
|
-
switch (resultOutcome.type) {
|
|
12468
|
-
case "success": {
|
|
12469
|
-
if (resultOutcome.text !== void 0) {
|
|
12470
|
-
state.resultText = resultOutcome.text;
|
|
12471
|
-
}
|
|
12472
|
-
state.usage = extractClaudeUsage(message) ?? state.usage;
|
|
12473
|
-
state.completedTurnCount += 1;
|
|
12474
|
-
const queuedTurnCountBeforeTranscript = options.streamingInput === void 0 ? void 0 : options.streamingInput.queuedTurnCount();
|
|
12475
|
-
if (options.streamingInput !== void 0) {
|
|
12476
|
-
await emitClaudeCodeTurnCompleted(options, state);
|
|
12477
|
-
}
|
|
12478
|
-
if (options.streamingInput !== void 0 && queuedTurnCountBeforeTranscript !== void 0 && state.completedTurnCount >= Math.max(
|
|
12479
|
-
queuedTurnCountBeforeTranscript,
|
|
12480
|
-
options.streamingInput.queuedTurnCount()
|
|
12481
|
-
)) {
|
|
12482
|
-
options.streamingInput.close();
|
|
12483
|
-
return completeClaudeCodeSession(options, state);
|
|
12484
|
-
}
|
|
12485
|
-
if (options.streamingInput !== void 0) {
|
|
12486
|
-
await options.onTurnCompleted?.();
|
|
12487
|
-
resetClaudeAssistantAggregate(state);
|
|
12488
|
-
state.resultText = void 0;
|
|
12451
|
+
try {
|
|
12452
|
+
for await (const message of runner(options)) {
|
|
12453
|
+
state.sessionId = state.sessionId ?? extractClaudeSessionId(message);
|
|
12454
|
+
const sessionId = extractClaudeSessionId(message) ?? state.sessionId;
|
|
12455
|
+
if (sessionId !== void 0 && !state.startedSessionIds.has(sessionId)) {
|
|
12456
|
+
state.startedSessionIds.add(sessionId);
|
|
12457
|
+
await options.onTranscriptEvent?.({
|
|
12458
|
+
type: "session_started",
|
|
12459
|
+
sessionId
|
|
12460
|
+
});
|
|
12461
|
+
}
|
|
12462
|
+
for (const event of transcriptEventsForClaudeMessage(
|
|
12463
|
+
message,
|
|
12464
|
+
sessionId,
|
|
12465
|
+
streamUsageTracker
|
|
12466
|
+
)) {
|
|
12467
|
+
if (event.type === "assistant_message") {
|
|
12468
|
+
recordClaudeAssistantAggregate(state, event);
|
|
12489
12469
|
}
|
|
12490
|
-
|
|
12470
|
+
if (event.type === "usage") {
|
|
12471
|
+
state.usage = event.usage;
|
|
12472
|
+
}
|
|
12473
|
+
await options.onTranscriptEvent?.(event);
|
|
12491
12474
|
}
|
|
12492
|
-
|
|
12493
|
-
|
|
12494
|
-
|
|
12495
|
-
|
|
12496
|
-
|
|
12497
|
-
|
|
12498
|
-
|
|
12475
|
+
const resultOutcome = extractClaudeResultOutcome(message);
|
|
12476
|
+
switch (resultOutcome.type) {
|
|
12477
|
+
case "success": {
|
|
12478
|
+
if (resultOutcome.text !== void 0) {
|
|
12479
|
+
state.resultText = resultOutcome.text;
|
|
12480
|
+
}
|
|
12481
|
+
state.usage = extractClaudeUsage(message) ?? state.usage;
|
|
12482
|
+
state.completedTurnCount += 1;
|
|
12483
|
+
if (options.streamingInput !== void 0) {
|
|
12484
|
+
await emitClaudeCodeTurnCompleted(options, state);
|
|
12485
|
+
state.lastCompletedTurnBody = state.resultText ?? nonEmptyText(claudeAssistantAggregateText(state)) ?? "";
|
|
12486
|
+
await options.onTurnCompleted?.();
|
|
12487
|
+
resetClaudeAssistantAggregate(state);
|
|
12488
|
+
state.resultText = void 0;
|
|
12489
|
+
}
|
|
12490
|
+
break;
|
|
12499
12491
|
}
|
|
12500
|
-
|
|
12501
|
-
|
|
12502
|
-
|
|
12503
|
-
|
|
12492
|
+
case "interrupted": {
|
|
12493
|
+
state.completedTurnCount += 1;
|
|
12494
|
+
if (state.sessionId !== void 0) {
|
|
12495
|
+
await options.onTranscriptEvent?.({
|
|
12496
|
+
type: "turn_interrupted",
|
|
12497
|
+
sessionId: state.sessionId
|
|
12498
|
+
});
|
|
12499
|
+
}
|
|
12500
|
+
if (options.streamingInput !== void 0) {
|
|
12501
|
+
await options.onTurnCompleted?.();
|
|
12502
|
+
resetClaudeAssistantAggregate(state);
|
|
12503
|
+
state.resultText = void 0;
|
|
12504
|
+
}
|
|
12505
|
+
break;
|
|
12504
12506
|
}
|
|
12505
|
-
|
|
12507
|
+
case "error":
|
|
12508
|
+
return await failClaudeCodeSession(
|
|
12509
|
+
options,
|
|
12510
|
+
state.sessionId,
|
|
12511
|
+
`Claude Code failed: ${resultOutcome.reason}`
|
|
12512
|
+
);
|
|
12513
|
+
case "none":
|
|
12514
|
+
break;
|
|
12506
12515
|
}
|
|
12507
|
-
case "error":
|
|
12508
|
-
return await failClaudeCodeSession(
|
|
12509
|
-
options,
|
|
12510
|
-
state.sessionId,
|
|
12511
|
-
`Claude Code failed: ${resultOutcome.reason}`
|
|
12512
|
-
);
|
|
12513
|
-
case "none":
|
|
12514
|
-
break;
|
|
12515
12516
|
}
|
|
12517
|
+
} finally {
|
|
12518
|
+
options.streamingInput?.close();
|
|
12516
12519
|
}
|
|
12517
12520
|
return completeClaudeCodeSession(options, state);
|
|
12518
12521
|
}
|
|
12519
12522
|
async function emitClaudeCodeTurnCompleted(options, state) {
|
|
12520
|
-
const body = state.resultText ?? nonEmptyText(claudeAssistantAggregateText(state));
|
|
12521
|
-
if (body === void 0) {
|
|
12522
|
-
return;
|
|
12523
|
-
}
|
|
12523
|
+
const body = state.resultText ?? nonEmptyText(claudeAssistantAggregateText(state)) ?? "";
|
|
12524
12524
|
if (state.sessionId === void 0) {
|
|
12525
12525
|
return;
|
|
12526
12526
|
}
|
|
@@ -12532,7 +12532,7 @@ async function emitClaudeCodeTurnCompleted(options, state) {
|
|
|
12532
12532
|
});
|
|
12533
12533
|
}
|
|
12534
12534
|
async function completeClaudeCodeSession(options, state) {
|
|
12535
|
-
const body = state.resultText ?? nonEmptyText(claudeAssistantAggregateText(state));
|
|
12535
|
+
const body = state.resultText ?? nonEmptyText(claudeAssistantAggregateText(state)) ?? state.lastCompletedTurnBody;
|
|
12536
12536
|
if (body === void 0) {
|
|
12537
12537
|
return await failClaudeCodeSession(
|
|
12538
12538
|
options,
|
|
@@ -18127,7 +18127,7 @@ var linzumiCliVersion, linzumiCliVersionText;
|
|
|
18127
18127
|
var init_version = __esm({
|
|
18128
18128
|
"src/version.ts"() {
|
|
18129
18129
|
"use strict";
|
|
18130
|
-
linzumiCliVersion = "0.0.
|
|
18130
|
+
linzumiCliVersion = "0.0.85-beta";
|
|
18131
18131
|
linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
|
|
18132
18132
|
}
|
|
18133
18133
|
});
|
|
@@ -19250,7 +19250,9 @@ function ignoredMessage(payload) {
|
|
|
19250
19250
|
`reason=${text(payload.reason)}`,
|
|
19251
19251
|
optionalField("type", payload.type),
|
|
19252
19252
|
optionalField("thread", payload.thread_id),
|
|
19253
|
+
optionalField("bound_thread", payload.bound_thread_id),
|
|
19253
19254
|
optionalField("body_chars", payload.body_length),
|
|
19255
|
+
optionalField("body", payload.body_preview),
|
|
19254
19256
|
optionalField("attachments", payload.attachment_count),
|
|
19255
19257
|
optionalField("local_event", payload.local_runner_event_type)
|
|
19256
19258
|
].filter((part) => part !== void 0).join(" ");
|
|
@@ -22592,7 +22594,29 @@ async function openLocalCodexRunner(options, log2, cleanup, close) {
|
|
|
22592
22594
|
);
|
|
22593
22595
|
dynamicChannelSessions.clear();
|
|
22594
22596
|
dynamicChannelSessionCodexClients.clear();
|
|
22595
|
-
|
|
22597
|
+
const claudeSessions = [...activeClaudeCodeSessions.values()];
|
|
22598
|
+
for (const session of claudeSessions) {
|
|
22599
|
+
try {
|
|
22600
|
+
session.closeInput();
|
|
22601
|
+
} catch (error) {
|
|
22602
|
+
log2("claude_code.session_input_close_failed", {
|
|
22603
|
+
linzumi_thread_id: session.threadId,
|
|
22604
|
+
message: error instanceof Error ? error.message : String(error)
|
|
22605
|
+
});
|
|
22606
|
+
}
|
|
22607
|
+
}
|
|
22608
|
+
await Promise.race([
|
|
22609
|
+
Promise.allSettled(
|
|
22610
|
+
claudeSessions.flatMap((session) => {
|
|
22611
|
+
const work = session.sessionWork();
|
|
22612
|
+
return work === void 0 ? [] : [work];
|
|
22613
|
+
})
|
|
22614
|
+
),
|
|
22615
|
+
new Promise((resolve12) => {
|
|
22616
|
+
setTimeout(resolve12, 1e4).unref?.();
|
|
22617
|
+
})
|
|
22618
|
+
]);
|
|
22619
|
+
for (const session of claudeSessions) {
|
|
22596
22620
|
session.abortController.abort(new Error("local runner stopped"));
|
|
22597
22621
|
}
|
|
22598
22622
|
activeClaudeCodeSessions.clear();
|
|
@@ -24449,10 +24473,28 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
|
|
|
24449
24473
|
};
|
|
24450
24474
|
}
|
|
24451
24475
|
try {
|
|
24452
|
-
activeSession.enqueueInput({
|
|
24476
|
+
const enqueueResult = activeSession.enqueueInput({
|
|
24453
24477
|
content: contentResult.content,
|
|
24454
24478
|
sourceSeq
|
|
24455
24479
|
});
|
|
24480
|
+
if (enqueueResult === "duplicate") {
|
|
24481
|
+
log2("claude_code.message_duplicate_ignored", {
|
|
24482
|
+
linzumi_thread_id: optionalThreadControlField(control, "threadId") ?? null,
|
|
24483
|
+
claude_session_id: codexThreadId,
|
|
24484
|
+
body_preview: claudeConsoleBodyPreview(workDescription),
|
|
24485
|
+
source_seq: sourceSeq ?? null
|
|
24486
|
+
});
|
|
24487
|
+
return {
|
|
24488
|
+
instanceId,
|
|
24489
|
+
controlType: control.type,
|
|
24490
|
+
agentProvider: "claude-code",
|
|
24491
|
+
cwd: cwd.cwd,
|
|
24492
|
+
matchedRoot: cwd.matchedRoot,
|
|
24493
|
+
codexThreadId,
|
|
24494
|
+
queuedInput: true,
|
|
24495
|
+
duplicate: true
|
|
24496
|
+
};
|
|
24497
|
+
}
|
|
24456
24498
|
log2("claude_code.message_queued", {
|
|
24457
24499
|
linzumi_thread_id: optionalThreadControlField(control, "threadId") ?? null,
|
|
24458
24500
|
claude_session_id: codexThreadId,
|
|
@@ -24956,7 +24998,24 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
|
|
|
24956
24998
|
};
|
|
24957
24999
|
}
|
|
24958
25000
|
case "stop_instance":
|
|
24959
|
-
case "kill_instance":
|
|
25001
|
+
case "kill_instance": {
|
|
25002
|
+
const controlThreadId2 = "threadId" in control && typeof control.threadId === "string" ? control.threadId : void 0;
|
|
25003
|
+
const activeSession = controlThreadId2 === void 0 ? void 0 : activeClaudeCodeSessions.get(controlThreadId2);
|
|
25004
|
+
if (activeSession !== void 0) {
|
|
25005
|
+
await activeSession.interruptTurn("Claude Code stopped by Linzumi");
|
|
25006
|
+
activeSession.abortController.abort(
|
|
25007
|
+
new Error("Claude Code stopped by Linzumi")
|
|
25008
|
+
);
|
|
25009
|
+
return {
|
|
25010
|
+
instanceId,
|
|
25011
|
+
controlType: control.type,
|
|
25012
|
+
agentProvider: "claude-code",
|
|
25013
|
+
threadId: controlThreadId2,
|
|
25014
|
+
stopped: true
|
|
25015
|
+
};
|
|
25016
|
+
}
|
|
25017
|
+
return { instanceId, controlType: control.type, skipped: true };
|
|
25018
|
+
}
|
|
24960
25019
|
case "resolve_port_forward_request":
|
|
24961
25020
|
case "update_thread_interaction_access":
|
|
24962
25021
|
case "set_port_forward_enabled":
|
|
@@ -25456,10 +25515,10 @@ function createClaudeCodeInputQueue(input) {
|
|
|
25456
25515
|
claudeCodeUserInputMessage(input.content)
|
|
25457
25516
|
];
|
|
25458
25517
|
const pendingSourceSeqs = [input.sourceSeq];
|
|
25518
|
+
const deferredFollowUps = [];
|
|
25459
25519
|
const waiters = [];
|
|
25460
25520
|
const state = {
|
|
25461
|
-
closed: false
|
|
25462
|
-
queuedTurnCount: 1
|
|
25521
|
+
closed: false
|
|
25463
25522
|
};
|
|
25464
25523
|
const drainClosedWaiters = () => {
|
|
25465
25524
|
while (state.closed) {
|
|
@@ -25470,19 +25529,25 @@ function createClaudeCodeInputQueue(input) {
|
|
|
25470
25529
|
waiter({ done: true, value: void 0 });
|
|
25471
25530
|
}
|
|
25472
25531
|
};
|
|
25532
|
+
const deliverNow = (message, sourceSeq) => {
|
|
25533
|
+
pendingSourceSeqs.push(sourceSeq);
|
|
25534
|
+
const waiter = waiters.shift();
|
|
25535
|
+
if (waiter === void 0) {
|
|
25536
|
+
pendingMessages.push(message);
|
|
25537
|
+
return;
|
|
25538
|
+
}
|
|
25539
|
+
waiter({ done: false, value: message });
|
|
25540
|
+
};
|
|
25473
25541
|
const enqueue = (next) => {
|
|
25474
25542
|
if (state.closed) {
|
|
25475
25543
|
throw new Error("Claude Code streaming input is closed");
|
|
25476
25544
|
}
|
|
25477
25545
|
const message = claudeCodeUserInputMessage(next.content);
|
|
25478
|
-
pendingSourceSeqs.
|
|
25479
|
-
|
|
25480
|
-
const waiter = waiters.shift();
|
|
25481
|
-
if (waiter === void 0) {
|
|
25482
|
-
pendingMessages.push(message);
|
|
25546
|
+
if (pendingSourceSeqs.length > 0) {
|
|
25547
|
+
deferredFollowUps.push({ message, sourceSeq: next.sourceSeq });
|
|
25483
25548
|
return;
|
|
25484
25549
|
}
|
|
25485
|
-
|
|
25550
|
+
deliverNow(message, next.sourceSeq);
|
|
25486
25551
|
};
|
|
25487
25552
|
const enqueueSteer = (content) => {
|
|
25488
25553
|
if (state.closed) {
|
|
@@ -25520,14 +25585,30 @@ function createClaudeCodeInputQueue(input) {
|
|
|
25520
25585
|
};
|
|
25521
25586
|
}
|
|
25522
25587
|
},
|
|
25523
|
-
queuedTurnCount: () => state.queuedTurnCount,
|
|
25524
25588
|
close: () => {
|
|
25589
|
+
if (pendingSourceSeqs.length === 0) {
|
|
25590
|
+
while (deferredFollowUps.length > 0) {
|
|
25591
|
+
const followUp = deferredFollowUps.shift();
|
|
25592
|
+
if (followUp !== void 0) {
|
|
25593
|
+
deliverNow(followUp.message, followUp.sourceSeq);
|
|
25594
|
+
}
|
|
25595
|
+
}
|
|
25596
|
+
}
|
|
25525
25597
|
state.closed = true;
|
|
25526
25598
|
drainClosedWaiters();
|
|
25527
25599
|
},
|
|
25528
25600
|
enqueue,
|
|
25529
25601
|
enqueueSteer,
|
|
25530
|
-
completeTurn: () =>
|
|
25602
|
+
completeTurn: () => {
|
|
25603
|
+
const completed = pendingSourceSeqs.shift();
|
|
25604
|
+
if (!state.closed && pendingSourceSeqs.length === 0) {
|
|
25605
|
+
const nextFollowUp = deferredFollowUps.shift();
|
|
25606
|
+
if (nextFollowUp !== void 0) {
|
|
25607
|
+
deliverNow(nextFollowUp.message, nextFollowUp.sourceSeq);
|
|
25608
|
+
}
|
|
25609
|
+
}
|
|
25610
|
+
return completed;
|
|
25611
|
+
},
|
|
25531
25612
|
currentSourceSeq: () => pendingSourceSeqs[0]
|
|
25532
25613
|
};
|
|
25533
25614
|
}
|
|
@@ -25775,6 +25856,11 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
25775
25856
|
codexVersion: void 0
|
|
25776
25857
|
};
|
|
25777
25858
|
const abortController = new AbortController();
|
|
25859
|
+
const acceptedSourceSeqs = new Set(
|
|
25860
|
+
sourceSeq === void 0 ? [] : [sourceSeq]
|
|
25861
|
+
);
|
|
25862
|
+
const sessionWorkHandle = { value: void 0 };
|
|
25863
|
+
let startControlResponded = false;
|
|
25778
25864
|
let activeSessionId;
|
|
25779
25865
|
let sessionControls;
|
|
25780
25866
|
const planMirrorClient = createLinzumiMcpApiClient({
|
|
@@ -25909,7 +25995,7 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
25909
25995
|
rootSeq,
|
|
25910
25996
|
log: args.log
|
|
25911
25997
|
};
|
|
25912
|
-
|
|
25998
|
+
const lastRateLimitSignatureByWindow = /* @__PURE__ */ new Map();
|
|
25913
25999
|
const reportClaudeCodeRateLimit = async (event) => {
|
|
25914
26000
|
const nowMs = Date.now();
|
|
25915
26001
|
const summary = claudeCodeRateLimitSummaryText(event.rateLimit, nowMs);
|
|
@@ -25925,13 +26011,13 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
25925
26011
|
utilization_percent: event.rateLimit.utilizationPercent ?? null,
|
|
25926
26012
|
resets_at_ms: event.rateLimit.resetsAtMs ?? null
|
|
25927
26013
|
});
|
|
26014
|
+
const windowKey = event.rateLimit.rateLimitType ?? "account";
|
|
25928
26015
|
const signature = claudeRateLimitSignature(event.rateLimit);
|
|
25929
|
-
if (signature ===
|
|
26016
|
+
if (signature === lastRateLimitSignatureByWindow.get(windowKey)) {
|
|
25930
26017
|
return;
|
|
25931
26018
|
}
|
|
25932
|
-
lastRateLimitSignature = signature;
|
|
25933
26019
|
try {
|
|
25934
|
-
await
|
|
26020
|
+
await publishClaudeCodeRateLimitState({
|
|
25935
26021
|
kandan: args.kandan,
|
|
25936
26022
|
topic: args.topic,
|
|
25937
26023
|
workspace,
|
|
@@ -25940,6 +26026,7 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
25940
26026
|
claudeSessionId: event.sessionId ?? activeSessionId,
|
|
25941
26027
|
rateLimit: event.rateLimit
|
|
25942
26028
|
});
|
|
26029
|
+
lastRateLimitSignatureByWindow.set(windowKey, signature);
|
|
25943
26030
|
} catch (error) {
|
|
25944
26031
|
args.log("claude_code.rate_limit_post_failed", {
|
|
25945
26032
|
thread_id: threadId,
|
|
@@ -25947,6 +26034,10 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
25947
26034
|
});
|
|
25948
26035
|
}
|
|
25949
26036
|
};
|
|
26037
|
+
let settleFirstTurn = () => void 0;
|
|
26038
|
+
const firstTurnSettled = new Promise((resolve12) => {
|
|
26039
|
+
settleFirstTurn = resolve12;
|
|
26040
|
+
});
|
|
25950
26041
|
const onTranscriptEvent = async (event) => {
|
|
25951
26042
|
try {
|
|
25952
26043
|
await mirrorClaudeSessionStoreAppend(mirrorArgs, event);
|
|
@@ -25969,7 +26060,19 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
25969
26060
|
channel,
|
|
25970
26061
|
threadId,
|
|
25971
26062
|
currentSourceSeq: inputQueue.currentSourceSeq,
|
|
25972
|
-
enqueueInput:
|
|
26063
|
+
enqueueInput: (input) => {
|
|
26064
|
+
if (input.sourceSeq !== void 0 && acceptedSourceSeqs.has(input.sourceSeq)) {
|
|
26065
|
+
return "duplicate";
|
|
26066
|
+
}
|
|
26067
|
+
inputQueue.enqueue(input);
|
|
26068
|
+
if (input.sourceSeq !== void 0) {
|
|
26069
|
+
acceptedSourceSeqs.add(input.sourceSeq);
|
|
26070
|
+
}
|
|
26071
|
+
return "queued";
|
|
26072
|
+
},
|
|
26073
|
+
closeInput: inputQueue.close,
|
|
26074
|
+
hasActiveTurn: () => adapter.activeTurnId() !== void 0,
|
|
26075
|
+
sessionWork: () => sessionWorkHandle.value,
|
|
25973
26076
|
steerTurn: inputQueue.enqueueSteer,
|
|
25974
26077
|
interruptTurn: async (reason) => {
|
|
25975
26078
|
const aborted = adapter.interruptActiveTurn(reason);
|
|
@@ -26025,6 +26128,10 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
26025
26128
|
claude_session_id: event.sessionId,
|
|
26026
26129
|
body_preview: claudeConsoleBodyPreview(event.body)
|
|
26027
26130
|
});
|
|
26131
|
+
settleFirstTurn();
|
|
26132
|
+
}
|
|
26133
|
+
if (event.type === "turn_interrupted") {
|
|
26134
|
+
settleFirstTurn();
|
|
26028
26135
|
}
|
|
26029
26136
|
if (event.type === "rate_limit") {
|
|
26030
26137
|
await reportClaudeCodeRateLimit(event);
|
|
@@ -26071,80 +26178,97 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
26071
26178
|
request,
|
|
26072
26179
|
signal
|
|
26073
26180
|
});
|
|
26074
|
-
|
|
26075
|
-
|
|
26181
|
+
const runSession = async () => {
|
|
26182
|
+
let result2;
|
|
26076
26183
|
try {
|
|
26077
|
-
|
|
26078
|
-
|
|
26079
|
-
prompt: workDescription,
|
|
26080
|
-
developerInstructions: commanderDeveloperInstructions({
|
|
26184
|
+
try {
|
|
26185
|
+
result2 = await startClaudeCodeSession({
|
|
26081
26186
|
cwd: args.cwd,
|
|
26082
|
-
|
|
26083
|
-
|
|
26084
|
-
|
|
26085
|
-
|
|
26086
|
-
|
|
26087
|
-
|
|
26088
|
-
|
|
26089
|
-
|
|
26090
|
-
|
|
26091
|
-
|
|
26092
|
-
|
|
26093
|
-
|
|
26094
|
-
|
|
26095
|
-
|
|
26096
|
-
|
|
26097
|
-
|
|
26098
|
-
|
|
26099
|
-
|
|
26100
|
-
|
|
26101
|
-
|
|
26102
|
-
|
|
26103
|
-
|
|
26104
|
-
|
|
26105
|
-
|
|
26106
|
-
|
|
26107
|
-
|
|
26108
|
-
|
|
26109
|
-
|
|
26110
|
-
|
|
26111
|
-
|
|
26112
|
-
|
|
26113
|
-
|
|
26114
|
-
|
|
26115
|
-
|
|
26116
|
-
|
|
26117
|
-
|
|
26187
|
+
prompt: workDescription,
|
|
26188
|
+
developerInstructions: commanderDeveloperInstructions({
|
|
26189
|
+
cwd: args.cwd,
|
|
26190
|
+
agentLabel: "Claude Code",
|
|
26191
|
+
planTool: "todo-write",
|
|
26192
|
+
developerPrompt,
|
|
26193
|
+
linzumiContext
|
|
26194
|
+
}),
|
|
26195
|
+
model: claudeCodeModelForRuntimeModel(runtimeSettings.model),
|
|
26196
|
+
resumeSessionId: args.resumeSessionId,
|
|
26197
|
+
abortController,
|
|
26198
|
+
streamingInput: inputQueue,
|
|
26199
|
+
runner: args.options.claudeCodeRunner,
|
|
26200
|
+
canUseTool,
|
|
26201
|
+
...mcpServers === void 0 ? {} : { mcpServers },
|
|
26202
|
+
...liveBashCapture === void 0 ? {} : {
|
|
26203
|
+
preToolUseHookMatchers: liveBashCapture.hookMatchers,
|
|
26204
|
+
wrapApprovedToolInput: (toolUseId, toolName2, input) => toolName2 === "Bash" ? liveBashCapture.wrapApprovedTool(toolUseId, input) : void 0
|
|
26205
|
+
},
|
|
26206
|
+
env: sessionEnv,
|
|
26207
|
+
// The built-in Linzumi MCP is trusted like the codex side: its tools
|
|
26208
|
+
// run without an approval round-trip. SDK allowedTools matches MCP
|
|
26209
|
+
// tools as mcp__<server>__<tool>; the __* suffix covers the server.
|
|
26210
|
+
allowedTools: ["mcp__linzumi__*"],
|
|
26211
|
+
onSessionControls: (controls) => {
|
|
26212
|
+
sessionControls = controls;
|
|
26213
|
+
},
|
|
26214
|
+
onTurnCompleted: () => {
|
|
26215
|
+
inputQueue.completeTurn();
|
|
26216
|
+
settleFirstTurn();
|
|
26217
|
+
},
|
|
26218
|
+
onTranscriptEvent
|
|
26219
|
+
});
|
|
26220
|
+
} finally {
|
|
26221
|
+
inputQueue.close();
|
|
26222
|
+
mcpAuthCleanup?.();
|
|
26223
|
+
liveBashCapture?.close();
|
|
26224
|
+
if (activeSessionId !== void 0) {
|
|
26225
|
+
args.activeClaudeCodeSessions.delete(activeSessionId);
|
|
26226
|
+
await args.disposeClaudeCodeForwardPortSession?.(activeSessionId);
|
|
26227
|
+
}
|
|
26118
26228
|
}
|
|
26229
|
+
} catch (error) {
|
|
26230
|
+
adapter.submitLifecycle(
|
|
26231
|
+
"codexDied",
|
|
26232
|
+
error instanceof Error ? error.message : String(error)
|
|
26233
|
+
);
|
|
26234
|
+
await adapter.close(5e3).catch(() => void 0);
|
|
26235
|
+
await Promise.race([
|
|
26236
|
+
planMirror.settle().catch(() => void 0),
|
|
26237
|
+
new Promise((resolve12) => {
|
|
26238
|
+
setTimeout(resolve12, 5e3).unref?.();
|
|
26239
|
+
})
|
|
26240
|
+
]);
|
|
26241
|
+
logStartFailureTerminal(
|
|
26242
|
+
error instanceof Error ? error.message : String(error)
|
|
26243
|
+
);
|
|
26244
|
+
if (!startControlResponded) {
|
|
26245
|
+
args.setStartupStage("claude_code_session_failed");
|
|
26246
|
+
}
|
|
26247
|
+
throw error;
|
|
26119
26248
|
}
|
|
26120
|
-
|
|
26121
|
-
|
|
26122
|
-
|
|
26123
|
-
|
|
26124
|
-
);
|
|
26125
|
-
await adapter.close(5e3).catch(() => void 0);
|
|
26249
|
+
if (!startControlResponded) {
|
|
26250
|
+
args.setStartupStage("posting_claude_code_output");
|
|
26251
|
+
}
|
|
26252
|
+
await adapter.awaitTurnsSettled(3e4);
|
|
26253
|
+
await adapter.close(3e4);
|
|
26126
26254
|
await Promise.race([
|
|
26127
|
-
planMirror.settle()
|
|
26255
|
+
planMirror.settle(),
|
|
26128
26256
|
new Promise((resolve12) => {
|
|
26129
|
-
setTimeout(resolve12,
|
|
26257
|
+
setTimeout(resolve12, 1e4).unref?.();
|
|
26130
26258
|
})
|
|
26131
26259
|
]);
|
|
26132
|
-
|
|
26133
|
-
|
|
26134
|
-
|
|
26135
|
-
|
|
26136
|
-
|
|
26137
|
-
|
|
26138
|
-
|
|
26139
|
-
|
|
26140
|
-
|
|
26141
|
-
|
|
26142
|
-
planMirror.settle(),
|
|
26143
|
-
new Promise((resolve12) => {
|
|
26144
|
-
setTimeout(resolve12, 1e4).unref?.();
|
|
26145
|
-
})
|
|
26260
|
+
return result2;
|
|
26261
|
+
};
|
|
26262
|
+
const sessionWork = runSession();
|
|
26263
|
+
sessionWorkHandle.value = sessionWork;
|
|
26264
|
+
const settled = await Promise.race([
|
|
26265
|
+
sessionWork.then((result2) => ({
|
|
26266
|
+
type: "session_ended",
|
|
26267
|
+
result: result2
|
|
26268
|
+
})),
|
|
26269
|
+
firstTurnSettled.then(() => ({ type: "first_turn_settled" }))
|
|
26146
26270
|
]);
|
|
26147
|
-
|
|
26271
|
+
const respondWithSessionId = (sessionId) => ({
|
|
26148
26272
|
controlResponse: {
|
|
26149
26273
|
instanceId: args.instanceId,
|
|
26150
26274
|
controlType: args.control.type,
|
|
@@ -26152,16 +26276,52 @@ async function startClaudeCodeProviderInstance(args) {
|
|
|
26152
26276
|
cwd: args.cwd,
|
|
26153
26277
|
matchedRoot: args.matchedRoot,
|
|
26154
26278
|
response: {
|
|
26155
|
-
session: { id:
|
|
26279
|
+
session: { id: sessionId }
|
|
26156
26280
|
}
|
|
26157
26281
|
},
|
|
26158
26282
|
providerSession: {
|
|
26159
26283
|
provider: "claude-code",
|
|
26160
26284
|
cwd: args.cwd,
|
|
26161
26285
|
matchedRoot: args.matchedRoot,
|
|
26162
|
-
sessionId
|
|
26286
|
+
sessionId
|
|
26163
26287
|
}
|
|
26164
|
-
};
|
|
26288
|
+
});
|
|
26289
|
+
if (settled.type === "session_ended") {
|
|
26290
|
+
return respondWithSessionId(settled.result.sessionId);
|
|
26291
|
+
}
|
|
26292
|
+
args.setStartupStage("posting_claude_code_output");
|
|
26293
|
+
startControlResponded = true;
|
|
26294
|
+
await adapter.awaitTurnsSettled(3e4);
|
|
26295
|
+
try {
|
|
26296
|
+
await adapter.flush(3e4);
|
|
26297
|
+
} catch (error) {
|
|
26298
|
+
args.log("claude_code.first_turn_flush_timeout", {
|
|
26299
|
+
linzumi_thread_id: threadId,
|
|
26300
|
+
claude_session_id: activeSessionId ?? null,
|
|
26301
|
+
message: error instanceof Error ? error.message : String(error)
|
|
26302
|
+
});
|
|
26303
|
+
}
|
|
26304
|
+
void sessionWork.then(
|
|
26305
|
+
() => {
|
|
26306
|
+
args.log("claude_code.session_loop_ended", {
|
|
26307
|
+
linzumi_thread_id: threadId,
|
|
26308
|
+
claude_session_id: activeSessionId ?? null
|
|
26309
|
+
});
|
|
26310
|
+
},
|
|
26311
|
+
(error) => {
|
|
26312
|
+
args.log("claude_code.session_loop_failed", {
|
|
26313
|
+
linzumi_thread_id: threadId,
|
|
26314
|
+
claude_session_id: activeSessionId ?? null,
|
|
26315
|
+
message: error instanceof Error ? error.message : String(error)
|
|
26316
|
+
});
|
|
26317
|
+
}
|
|
26318
|
+
);
|
|
26319
|
+
const liveSessionId = activeSessionId ?? args.resumeSessionId;
|
|
26320
|
+
if (liveSessionId !== void 0) {
|
|
26321
|
+
return respondWithSessionId(liveSessionId);
|
|
26322
|
+
}
|
|
26323
|
+
const result = await sessionWork;
|
|
26324
|
+
return respondWithSessionId(result.sessionId);
|
|
26165
26325
|
}
|
|
26166
26326
|
function claudePermissionModeForApprovalPolicy(approvalPolicy) {
|
|
26167
26327
|
switch (approvalPolicy) {
|
|
@@ -26403,50 +26563,26 @@ function claudeRateLimitSignature(rateLimit) {
|
|
|
26403
26563
|
rateLimit.resetsAtMs ?? "na"
|
|
26404
26564
|
].join(":");
|
|
26405
26565
|
}
|
|
26406
|
-
async function
|
|
26407
|
-
|
|
26408
|
-
const summary = claudeCodeRateLimitSummaryText(args.rateLimit, nowMs);
|
|
26409
|
-
const headline = `Claude Code rate limit: ${summary}`;
|
|
26410
|
-
const resetLabel = claudeCodeRateLimitResetLabel(
|
|
26411
|
-
args.rateLimit.resetsAtMs,
|
|
26412
|
-
nowMs
|
|
26413
|
-
);
|
|
26414
|
-
const richUi = args.rateLimit.utilizationPercent === void 0 ? [{ primitive: "label", label: headline }] : [
|
|
26415
|
-
{
|
|
26416
|
-
primitive: "progress",
|
|
26417
|
-
value: Math.min(
|
|
26418
|
-
100,
|
|
26419
|
-
Math.max(0, Math.round(args.rateLimit.utilizationPercent))
|
|
26420
|
-
),
|
|
26421
|
-
max: 100,
|
|
26422
|
-
label: `Claude Code rate limit${resetLabel === void 0 ? "" : ` - ${resetLabel}`}`
|
|
26423
|
-
}
|
|
26424
|
-
];
|
|
26425
|
-
await args.kandan.push(args.topic, "session:post_thread_message", {
|
|
26566
|
+
async function publishClaudeCodeRateLimitState(args) {
|
|
26567
|
+
await args.kandan.push(args.topic, "claude_rate_limit_state", {
|
|
26426
26568
|
workspace: args.workspace,
|
|
26427
26569
|
channel: args.channel,
|
|
26428
26570
|
thread_id: args.threadId,
|
|
26429
|
-
|
|
26430
|
-
|
|
26431
|
-
|
|
26432
|
-
|
|
26433
|
-
|
|
26434
|
-
|
|
26435
|
-
|
|
26436
|
-
|
|
26437
|
-
|
|
26438
|
-
|
|
26571
|
+
agent_provider: "claude-code",
|
|
26572
|
+
...args.claudeSessionId === void 0 ? {} : { claude_session_id: args.claudeSessionId },
|
|
26573
|
+
// "account" mirrors the server-side default for SDK frames that omit a
|
|
26574
|
+
// window type; sending it explicitly keeps the wire contract obvious.
|
|
26575
|
+
rate_limit_type: args.rateLimit.rateLimitType ?? "account",
|
|
26576
|
+
status: args.rateLimit.status ?? "allowed",
|
|
26577
|
+
...args.rateLimit.utilizationPercent === void 0 ? {} : {
|
|
26578
|
+
utilization_percent: Math.min(
|
|
26579
|
+
100,
|
|
26580
|
+
Math.max(0, Math.round(args.rateLimit.utilizationPercent))
|
|
26581
|
+
)
|
|
26439
26582
|
},
|
|
26440
|
-
|
|
26441
|
-
args.threadId,
|
|
26442
|
-
args.rateLimit
|
|
26443
|
-
)
|
|
26583
|
+
...args.rateLimit.resetsAtMs === void 0 ? {} : { resets_at_ms: args.rateLimit.resetsAtMs }
|
|
26444
26584
|
});
|
|
26445
26585
|
}
|
|
26446
|
-
function claudeRateLimitClientMessageId(threadId, rateLimit) {
|
|
26447
|
-
const digest = createHash5("sha256").update(`${threadId}:${claudeRateLimitSignature(rateLimit)}`).digest("hex").slice(0, 32);
|
|
26448
|
-
return `claude-rate-limit-${digest}`;
|
|
26449
|
-
}
|
|
26450
26586
|
async function publishStartInstanceMessageState(kandan, topic, control, status, reason, diagnostics = {}) {
|
|
26451
26587
|
const payload = startInstanceMessageStatePayload(
|
|
26452
26588
|
control,
|
package/package.json
CHANGED