@khalilgharbaoui/opencode-claude-code-plugin 0.46.1 → 0.47.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.
- package/dist/index.d.ts +26 -0
- package/dist/index.js +147 -30
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/claude-code-plugin/SKILL.md +8 -5
package/dist/index.d.ts
CHANGED
|
@@ -435,6 +435,8 @@ interface ClaudeCodeConfig {
|
|
|
435
435
|
resumeAfterRestart?: boolean;
|
|
436
436
|
/** Carry a conversation's Claude session over when its model or effort changes. Default true. */
|
|
437
437
|
resumeAcrossModelChanges?: boolean;
|
|
438
|
+
/** Carry a conversation's Claude transcript over on an account switch. Default true. */
|
|
439
|
+
crossAccountResume?: boolean;
|
|
438
440
|
logging?: LoggingConfig;
|
|
439
441
|
}
|
|
440
442
|
interface LoggingConfig {
|
|
@@ -856,6 +858,30 @@ interface ClaudeCodeProviderSettings {
|
|
|
856
858
|
* false` turns this off too.
|
|
857
859
|
*/
|
|
858
860
|
resumeAcrossModelChanges?: boolean;
|
|
861
|
+
/**
|
|
862
|
+
* Continue the same Claude conversation when it moves to another account,
|
|
863
|
+
* instead of replaying the whole thread as text into a fresh session there.
|
|
864
|
+
* Default `true`; it does nothing at all on a single-account install.
|
|
865
|
+
*
|
|
866
|
+
* An account is a `CLAUDE_CONFIG_DIR`, and a conversation is one transcript
|
|
867
|
+
* file inside it, so the move is a file copy into the target account's own
|
|
868
|
+
* `projects/<encoded cwd>/` plus the `--resume` that already exists. Claude
|
|
869
|
+
* Code 2.1.288 resumes a copied transcript with its context intact, resolves
|
|
870
|
+
* a session by FILENAME, and appends to the copy without touching the
|
|
871
|
+
* original (h #g218).
|
|
872
|
+
*
|
|
873
|
+
* Every refusal falls back to the replay and says which in the log: no
|
|
874
|
+
* transcript to carry, something that is not a plain file at the target
|
|
875
|
+
* path, or a copy that failed. The source transcript is never moved,
|
|
876
|
+
* deleted or written to, and an existing file is never overwritten (the
|
|
877
|
+
* carry takes a fresh session id instead).
|
|
878
|
+
*
|
|
879
|
+
* What was measured is the file layout, with a second config dir holding a
|
|
880
|
+
* copy of the same credentials; whether a different Anthropic account's
|
|
881
|
+
* token answers a conversation produced under another one is not yet
|
|
882
|
+
* verified live. Set `false` to keep the replay.
|
|
883
|
+
*/
|
|
884
|
+
crossAccountResume?: boolean;
|
|
859
885
|
/**
|
|
860
886
|
* Routing for Claude's built-in `WebSearch` tool.
|
|
861
887
|
*
|
package/dist/index.js
CHANGED
|
@@ -1490,7 +1490,7 @@ function createAccountFailoverQuestionCall(sessionKey2, input, toolCallId = `${A
|
|
|
1490
1490
|
options: [
|
|
1491
1491
|
...candidates.map((candidate) => ({
|
|
1492
1492
|
label: candidate,
|
|
1493
|
-
description: `Run on "${candidate}" until ${until}. The conversation is replayed as a fresh Claude session
|
|
1493
|
+
description: input.carryTranscript === false ? `Run on "${candidate}" until ${until}. The conversation is replayed as a fresh Claude session, and any MCP server configured only in "${source}"'s Claude profile will be missing.` : `Run on "${candidate}" until ${until}. The conversation continues where it stopped if its Claude transcript can be carried across, and is replayed as a fresh Claude session if it cannot; either way, any MCP server configured only in "${source}"'s Claude profile will be missing.`
|
|
1494
1494
|
})),
|
|
1495
1495
|
{
|
|
1496
1496
|
label: STOP_ANSWER,
|
|
@@ -1601,20 +1601,20 @@ function stripAccountFailoverParts(prompt) {
|
|
|
1601
1601
|
}
|
|
1602
1602
|
return changed ? out : prompt;
|
|
1603
1603
|
}
|
|
1604
|
-
function failoverContinuationText(target) {
|
|
1604
|
+
function failoverContinuationText(target, resumed = false) {
|
|
1605
1605
|
return [
|
|
1606
|
-
`The Claude account this conversation was running on hit its usage limit, so it has been moved to the "${target}" account and you are now in a fresh Claude session.`,
|
|
1607
|
-
"
|
|
1606
|
+
resumed ? `The Claude account this conversation was running on hit its usage limit, so it has been moved to the "${target}" account. This is the same conversation, continued: everything you already know still stands.` : `The Claude account this conversation was running on hit its usage limit, so it has been moved to the "${target}" account and you are now in a fresh Claude session. The conversation so far is above.`,
|
|
1607
|
+
"Continue the task from where it stopped: do not start over, do not re-plan, and do not repeat work that is already done.",
|
|
1608
1608
|
"Do not mention the account switch unless you are asked about it."
|
|
1609
1609
|
].join(" ");
|
|
1610
1610
|
}
|
|
1611
|
-
function buildFailoverContinuationPrompt(prompt, target) {
|
|
1611
|
+
function buildFailoverContinuationPrompt(prompt, target, resumed = false) {
|
|
1612
1612
|
const stripped = stripAccountFailoverParts(prompt);
|
|
1613
1613
|
return [
|
|
1614
1614
|
...stripped,
|
|
1615
1615
|
{
|
|
1616
1616
|
role: "user",
|
|
1617
|
-
content: [{ type: "text", text: failoverContinuationText(target) }]
|
|
1617
|
+
content: [{ type: "text", text: failoverContinuationText(target, resumed) }]
|
|
1618
1618
|
}
|
|
1619
1619
|
];
|
|
1620
1620
|
}
|
|
@@ -5994,6 +5994,7 @@ var PLUGIN_LOG_MESSAGES = /* @__PURE__ */ new Set([
|
|
|
5994
5994
|
"btw: a turn is running but no claude process appeared for it",
|
|
5995
5995
|
"btw: early aside failed; the message will ask again",
|
|
5996
5996
|
"cannot interrupt this transport; waiting for the turn to end",
|
|
5997
|
+
"carried this conversation's claude transcript to the other account",
|
|
5997
5998
|
"carrying the claude conversation over to the new session key",
|
|
5998
5999
|
"claude --version output unparseable",
|
|
5999
6000
|
"claude account is out of usage; the turn ends with a note",
|
|
@@ -6091,6 +6092,7 @@ var PLUGIN_LOG_MESSAGES = /* @__PURE__ */ new Set([
|
|
|
6091
6092
|
"remote URL images are not supported by Claude CLI, skipping",
|
|
6092
6093
|
"replaying stdout the child emitted between turns",
|
|
6093
6094
|
"replaying the conversation as text: no claude session was available to continue",
|
|
6095
|
+
"replaying this conversation as text on the other account",
|
|
6094
6096
|
"result fallback timer fired \u2014 closing stream without result event",
|
|
6095
6097
|
"resuming the claude session from before the restart instead of replaying it",
|
|
6096
6098
|
"shared Claude capability already exists; leaving untouched",
|
|
@@ -6135,6 +6137,8 @@ var BUNDLE_DATA_ALLOWLIST = {
|
|
|
6135
6137
|
emitted: "flag",
|
|
6136
6138
|
enabled: "flag",
|
|
6137
6139
|
executed: "flag",
|
|
6140
|
+
failedOver: "flag",
|
|
6141
|
+
renamed: "flag",
|
|
6138
6142
|
isUsingOverage: "flag",
|
|
6139
6143
|
hadProxyActivity: "flag",
|
|
6140
6144
|
hadReasoning: "flag",
|
|
@@ -6513,8 +6517,8 @@ function redactLogLine(raw, context) {
|
|
|
6513
6517
|
if (!parsed.data || Object.keys(parsed.data).length === 0) return head;
|
|
6514
6518
|
return `${head} ${JSON.stringify(sanitizeLogData(parsed.data, context))}`;
|
|
6515
6519
|
}
|
|
6516
|
-
function readLogTail(
|
|
6517
|
-
const fd = openSync(
|
|
6520
|
+
function readLogTail(path13, maxBytes = BUNDLE_TAIL_BYTES) {
|
|
6521
|
+
const fd = openSync(path13, "r");
|
|
6518
6522
|
try {
|
|
6519
6523
|
const size = fstatSync(fd).size;
|
|
6520
6524
|
const length = Math.min(size, maxBytes);
|
|
@@ -9127,6 +9131,14 @@ function classifyScreen(text) {
|
|
|
9127
9131
|
}
|
|
9128
9132
|
return null;
|
|
9129
9133
|
}
|
|
9134
|
+
function interactiveTranscriptPath(opts) {
|
|
9135
|
+
return path10.join(
|
|
9136
|
+
resolveConfigDir(opts.configDir),
|
|
9137
|
+
"projects",
|
|
9138
|
+
encodeCwd(path10.resolve(opts.cwd)),
|
|
9139
|
+
`${opts.sessionId}.jsonl`
|
|
9140
|
+
);
|
|
9141
|
+
}
|
|
9130
9142
|
function configDirEnv(configDir) {
|
|
9131
9143
|
return configDir ? { CLAUDE_CONFIG_DIR: configDir } : {};
|
|
9132
9144
|
}
|
|
@@ -10637,14 +10649,74 @@ function spawnInteractiveProcess(opts) {
|
|
|
10637
10649
|
return ap;
|
|
10638
10650
|
}
|
|
10639
10651
|
|
|
10652
|
+
// src/account-transcript.ts
|
|
10653
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
10654
|
+
import { constants as fsConstants } from "fs";
|
|
10655
|
+
import { chmod as chmod2, copyFile, lstat as lstat2, mkdir as mkdir2 } from "fs/promises";
|
|
10656
|
+
import path11 from "path";
|
|
10657
|
+
var transcriptPath = interactiveTranscriptPath;
|
|
10658
|
+
function configDirForAccount(account) {
|
|
10659
|
+
const normalized = normalizeAccountName(account || DEFAULT_ACCOUNT);
|
|
10660
|
+
return resolveConfigDir(
|
|
10661
|
+
normalized === DEFAULT_ACCOUNT ? void 0 : accountConfigDirPath(normalized)
|
|
10662
|
+
);
|
|
10663
|
+
}
|
|
10664
|
+
async function carryTranscriptToAccount(input) {
|
|
10665
|
+
const { sessionId, cwd, targetConfigDir } = input;
|
|
10666
|
+
const targetOwn = transcriptPath({ configDir: targetConfigDir, cwd, sessionId });
|
|
10667
|
+
const targetOwnStat = await statTranscript(targetOwn);
|
|
10668
|
+
if (targetOwnStat.kind === "other") {
|
|
10669
|
+
return { kind: "refused", reason: "target-not-a-file", detail: targetOwn };
|
|
10670
|
+
}
|
|
10671
|
+
let live;
|
|
10672
|
+
for (const dir of dedupe2([targetConfigDir, ...input.accountConfigDirs])) {
|
|
10673
|
+
const candidate = transcriptPath({ configDir: dir, cwd, sessionId });
|
|
10674
|
+
const stat = candidate === targetOwn ? targetOwnStat : await statTranscript(candidate);
|
|
10675
|
+
if (stat.kind !== "file") continue;
|
|
10676
|
+
if (!live || stat.size > live.size) live = { file: candidate, size: stat.size };
|
|
10677
|
+
}
|
|
10678
|
+
if (!live) return { kind: "refused", reason: "no-transcript-anywhere" };
|
|
10679
|
+
if (live.file === targetOwn) return { kind: "already-there", sessionId };
|
|
10680
|
+
const renamed = targetOwnStat.kind === "file";
|
|
10681
|
+
const carriedId = renamed ? (input.newSessionId ?? randomUUID6)() : sessionId;
|
|
10682
|
+
const target = renamed ? transcriptPath({ configDir: targetConfigDir, cwd, sessionId: carriedId }) : targetOwn;
|
|
10683
|
+
try {
|
|
10684
|
+
await mkdir2(path11.dirname(target), { recursive: true, mode: 448 });
|
|
10685
|
+
await copyFile(live.file, target, fsConstants.COPYFILE_EXCL);
|
|
10686
|
+
await chmod2(target, 384);
|
|
10687
|
+
} catch (err) {
|
|
10688
|
+
return { kind: "refused", reason: "copy-failed", detail: String(err) };
|
|
10689
|
+
}
|
|
10690
|
+
return { kind: "carried", sessionId: carriedId, from: live.file, to: target, renamed };
|
|
10691
|
+
}
|
|
10692
|
+
async function statTranscript(file) {
|
|
10693
|
+
try {
|
|
10694
|
+
const stat = await lstat2(file);
|
|
10695
|
+
return stat.isFile() ? { kind: "file", size: stat.size } : { kind: "other", size: 0 };
|
|
10696
|
+
} catch {
|
|
10697
|
+
return { kind: "none", size: 0 };
|
|
10698
|
+
}
|
|
10699
|
+
}
|
|
10700
|
+
function dedupe2(dirs) {
|
|
10701
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10702
|
+
const out = [];
|
|
10703
|
+
for (const dir of dirs) {
|
|
10704
|
+
const resolved = path11.resolve(dir);
|
|
10705
|
+
if (seen.has(resolved)) continue;
|
|
10706
|
+
seen.add(resolved);
|
|
10707
|
+
out.push(resolved);
|
|
10708
|
+
}
|
|
10709
|
+
return out;
|
|
10710
|
+
}
|
|
10711
|
+
|
|
10640
10712
|
// src/prompts.ts
|
|
10641
10713
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync6 } from "fs";
|
|
10642
10714
|
import { homedir as homedir8 } from "os";
|
|
10643
|
-
import { randomUUID as
|
|
10715
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
10644
10716
|
import { basename as basename2, dirname as dirname6, isAbsolute as isAbsolute3, join as join11 } from "path";
|
|
10645
|
-
function readPromptFileIfPresent(
|
|
10717
|
+
function readPromptFileIfPresent(path13) {
|
|
10646
10718
|
try {
|
|
10647
|
-
const content = readFileSync6(
|
|
10719
|
+
const content = readFileSync6(path13, "utf8").trim();
|
|
10648
10720
|
return content || void 0;
|
|
10649
10721
|
} catch {
|
|
10650
10722
|
return void 0;
|
|
@@ -10749,9 +10821,9 @@ function extractSystemMessages(prompt) {
|
|
|
10749
10821
|
}
|
|
10750
10822
|
var CLAUDE_NATIVE_INSTRUCTION_FILES = /* @__PURE__ */ new Set(["CLAUDE.md", "CLAUDE.local.md"]);
|
|
10751
10823
|
function userAuthoredInstructions(forwarded, opts = {}) {
|
|
10752
|
-
const readFile2 = opts.readFile ?? ((
|
|
10824
|
+
const readFile2 = opts.readFile ?? ((path13) => {
|
|
10753
10825
|
try {
|
|
10754
|
-
return readFileSync6(
|
|
10826
|
+
return readFileSync6(path13, "utf8");
|
|
10755
10827
|
} catch {
|
|
10756
10828
|
return null;
|
|
10757
10829
|
}
|
|
@@ -10763,16 +10835,16 @@ function userAuthoredInstructions(forwarded, opts = {}) {
|
|
|
10763
10835
|
}
|
|
10764
10836
|
const seen = /* @__PURE__ */ new Set();
|
|
10765
10837
|
for (const match of forwarded.matchAll(/^Instructions from: (.+)$/gm)) {
|
|
10766
|
-
const
|
|
10767
|
-
if (seen.has(
|
|
10768
|
-
if (CLAUDE_NATIVE_INSTRUCTION_FILES.has(basename2(
|
|
10769
|
-
seen.add(
|
|
10770
|
-
const file = readFile2(
|
|
10838
|
+
const path13 = match[1].trim();
|
|
10839
|
+
if (seen.has(path13) || !isAbsolute3(path13)) continue;
|
|
10840
|
+
if (CLAUDE_NATIVE_INSTRUCTION_FILES.has(basename2(path13))) continue;
|
|
10841
|
+
seen.add(path13);
|
|
10842
|
+
const file = readFile2(path13);
|
|
10771
10843
|
if (!file?.trim()) continue;
|
|
10772
10844
|
const start = match.index + match[0].length + 1;
|
|
10773
10845
|
const content = forwarded.startsWith(file, start) ? file : forwarded.startsWith(file.trimEnd(), start) ? file.trimEnd() : null;
|
|
10774
10846
|
if (content === null) continue;
|
|
10775
|
-
out.push({ text: `Instructions from: ${
|
|
10847
|
+
out.push({ text: `Instructions from: ${path13}
|
|
10776
10848
|
${content}`, content });
|
|
10777
10849
|
}
|
|
10778
10850
|
return out;
|
|
@@ -10809,10 +10881,10 @@ ${options.compressionSummary.trim()}`
|
|
|
10809
10881
|
if (includeMultiStepHint) parts.push(MULTI_STEP_TASK_HINT);
|
|
10810
10882
|
const content = parts.join("\n\n");
|
|
10811
10883
|
if (!content) return void 0;
|
|
10812
|
-
const
|
|
10884
|
+
const path13 = join11(pluginTmpDir(), `opencode-cc-sys-${randomUUID7()}.md`);
|
|
10813
10885
|
try {
|
|
10814
|
-
writeFileSync6(
|
|
10815
|
-
return
|
|
10886
|
+
writeFileSync6(path13, content, { encoding: "utf8", mode: 384 });
|
|
10887
|
+
return path13;
|
|
10816
10888
|
} catch (err) {
|
|
10817
10889
|
log.warn("failed to write system prompt file", { error: String(err) });
|
|
10818
10890
|
return void 0;
|
|
@@ -13828,12 +13900,51 @@ var ClaudeCodeLanguageModel = class {
|
|
|
13828
13900
|
failedOver: failover.failedOver
|
|
13829
13901
|
});
|
|
13830
13902
|
deleteActiveProcess(sk);
|
|
13903
|
+
}
|
|
13904
|
+
let conversationOnTarget = false;
|
|
13905
|
+
const multiAccount = (this.config.failoverAccounts?.length ?? 0) > 1;
|
|
13906
|
+
const sessionBeforeAccountCheck = getClaudeSessionId(sk);
|
|
13907
|
+
if (!compactionMode && multiAccount && this.config.crossAccountResume !== false && sessionBeforeAccountCheck) {
|
|
13908
|
+
const carry = await carryTranscriptToAccount({
|
|
13909
|
+
sessionId: sessionBeforeAccountCheck,
|
|
13910
|
+
cwd,
|
|
13911
|
+
targetConfigDir: resolveConfigDir(this.skillBridgeSpawn(failover).configDir),
|
|
13912
|
+
// Every account's own directory, plus this model's configured one:
|
|
13913
|
+
// `configDir` is an option, so an account's directory is not always
|
|
13914
|
+
// the `~/.claude-<name>` the name alone would build.
|
|
13915
|
+
accountConfigDirs: [
|
|
13916
|
+
...(this.config.failoverAccounts ?? []).map(configDirForAccount),
|
|
13917
|
+
resolveConfigDir(this.config.configDir)
|
|
13918
|
+
]
|
|
13919
|
+
});
|
|
13920
|
+
if (carry.kind === "carried" || carry.kind === "already-there") {
|
|
13921
|
+
if (carry.sessionId !== sessionBeforeAccountCheck) {
|
|
13922
|
+
setClaudeSessionId(sk, carry.sessionId);
|
|
13923
|
+
}
|
|
13924
|
+
conversationOnTarget = true;
|
|
13925
|
+
if (carry.kind === "carried") {
|
|
13926
|
+
log.notice("carried this conversation's claude transcript to the other account", {
|
|
13927
|
+
sessionKey: sk,
|
|
13928
|
+
renamed: carry.renamed,
|
|
13929
|
+
sessionId: carry.sessionId,
|
|
13930
|
+
failedOver: failover.failedOver
|
|
13931
|
+
});
|
|
13932
|
+
}
|
|
13933
|
+
} else if (!getActiveProcess(sk)) {
|
|
13934
|
+
log.notice("replaying this conversation as text on the other account", {
|
|
13935
|
+
sessionKey: sk,
|
|
13936
|
+
reason: carry.reason,
|
|
13937
|
+
failedOver: failover.failedOver
|
|
13938
|
+
});
|
|
13939
|
+
deleteClaudeSessionId(sk);
|
|
13940
|
+
}
|
|
13941
|
+
} else if (!compactionMode && sessionBeforeAccountCheck && processForAccount?.cliPath && processForAccount.cliPath !== cliPath) {
|
|
13831
13942
|
deleteClaudeSessionId(sk);
|
|
13832
13943
|
}
|
|
13833
13944
|
const hasExistingSession = !!getClaudeSessionId(sk);
|
|
13834
13945
|
const hasActiveProcess = !!getActiveProcess(sk);
|
|
13835
13946
|
let includeHistoryContext = !hasExistingSession && !hasActiveProcess && hasPriorConversation;
|
|
13836
|
-
if (failoverAnswer?.kind === "switch" && hasPriorConversation) {
|
|
13947
|
+
if (failoverAnswer?.kind === "switch" && hasPriorConversation && !conversationOnTarget) {
|
|
13837
13948
|
includeHistoryContext = true;
|
|
13838
13949
|
}
|
|
13839
13950
|
let forkFromClaudeSessionId;
|
|
@@ -13879,12 +13990,12 @@ var ClaudeCodeLanguageModel = class {
|
|
|
13879
13990
|
let replayReason = "no-session-for-key";
|
|
13880
13991
|
if (this.config.resumeAfterRestart !== false && includeHistoryContext && !compactionMode && !forkFromClaudeSessionId && failoverAnswer?.kind !== "switch") {
|
|
13881
13992
|
const configDir = resolveConfigDir(this.config.configDir);
|
|
13882
|
-
const
|
|
13993
|
+
const transcriptPath2 = (id) => join12(configDir, "projects", encodeCwd(cwd), `${id}.jsonl`);
|
|
13883
13994
|
const resumePoint = findResumePoint({
|
|
13884
13995
|
sessionKey: sk,
|
|
13885
13996
|
prompt: options.prompt,
|
|
13886
13997
|
cliPath,
|
|
13887
|
-
transcriptPath,
|
|
13998
|
+
transcriptPath: transcriptPath2,
|
|
13888
13999
|
onRefused: (reason) => {
|
|
13889
14000
|
replayReason = reason;
|
|
13890
14001
|
}
|
|
@@ -13901,7 +14012,7 @@ var ClaudeCodeLanguageModel = class {
|
|
|
13901
14012
|
sessionKey: sk,
|
|
13902
14013
|
prompt: options.prompt,
|
|
13903
14014
|
cliPath,
|
|
13904
|
-
transcriptPath,
|
|
14015
|
+
transcriptPath: transcriptPath2,
|
|
13905
14016
|
// `claudeSessionIsWriting`, not `getActiveProcess`: this walks every
|
|
13906
14017
|
// sibling key, and that one refreshes LRU order and cancels idle
|
|
13907
14018
|
// timers on everything it touches (the same reason the fork lookup
|
|
@@ -13946,7 +14057,11 @@ var ClaudeCodeLanguageModel = class {
|
|
|
13946
14057
|
log.info("sending plan approval decision to claude", { sk });
|
|
13947
14058
|
}
|
|
13948
14059
|
const previousPendingProxyCalls = compactionMode ? [] : getPendingProxyCalls(sk);
|
|
13949
|
-
const effectivePrompt = failoverAnswer?.kind === "switch" ? buildFailoverContinuationPrompt(
|
|
14060
|
+
const effectivePrompt = failoverAnswer?.kind === "switch" ? buildFailoverContinuationPrompt(
|
|
14061
|
+
options.prompt,
|
|
14062
|
+
failoverAnswer.target,
|
|
14063
|
+
conversationOnTarget
|
|
14064
|
+
) : options.prompt;
|
|
13950
14065
|
const userMsg = exitPlanModeQuestionResult ?? getClaudeUserMessage(effectivePrompt, includeHistoryContext, {
|
|
13951
14066
|
compactionMode,
|
|
13952
14067
|
compactionInstructions: useInteractive && compactionMode ? extractSystemMessages(effectivePrompt).join("\n\n") : void 0,
|
|
@@ -14628,7 +14743,8 @@ var ClaudeCodeLanguageModel = class {
|
|
|
14628
14743
|
candidates: failoverAccounts,
|
|
14629
14744
|
resetsAt: state.accountLimitHit?.resetsAt,
|
|
14630
14745
|
window: state.accountLimitHit?.window,
|
|
14631
|
-
reason: state.accountLimitHit || !state.accountBlock ? void 0 : describeAccountBlock(state.accountBlock)
|
|
14746
|
+
reason: state.accountLimitHit || !state.accountBlock ? void 0 : describeAccountBlock(state.accountBlock),
|
|
14747
|
+
carryTranscript: self.config.crossAccountResume !== false
|
|
14632
14748
|
});
|
|
14633
14749
|
log.warn(
|
|
14634
14750
|
`Claude account "${sourceAccount}" ${state.accountLimitHit || !state.accountBlock ? "is out of usage" : `cannot serve (${state.accountBlock})`}; asking which account to continue on.`,
|
|
@@ -15346,7 +15462,7 @@ function registerOpencodeLogSink(client) {
|
|
|
15346
15462
|
}
|
|
15347
15463
|
|
|
15348
15464
|
// src/v2-client.ts
|
|
15349
|
-
import
|
|
15465
|
+
import path12 from "path";
|
|
15350
15466
|
function formatAgentTypeList(agents) {
|
|
15351
15467
|
const lines = agents.flatMap((agent) => {
|
|
15352
15468
|
if (agent.hidden === true || agent.mode === "primary") return [];
|
|
@@ -15375,7 +15491,7 @@ function toV1Session(info) {
|
|
|
15375
15491
|
if (!info || typeof info !== "object") return void 0;
|
|
15376
15492
|
const session = info;
|
|
15377
15493
|
const root = session.location?.directory;
|
|
15378
|
-
const directory = typeof root === "string" ? typeof session.subpath === "string" && session.subpath.length > 0 ?
|
|
15494
|
+
const directory = typeof root === "string" ? typeof session.subpath === "string" && session.subpath.length > 0 ? path12.resolve(root, session.subpath) : root : void 0;
|
|
15379
15495
|
return { ...info, directory, parentID: session.parentID };
|
|
15380
15496
|
}
|
|
15381
15497
|
function toV1Messages(messages) {
|
|
@@ -15934,6 +16050,7 @@ function createClaudeCode(settings = {}) {
|
|
|
15934
16050
|
forkSessions: settings.forkSessions === true,
|
|
15935
16051
|
resumeAfterRestart: settings.resumeAfterRestart !== false,
|
|
15936
16052
|
resumeAcrossModelChanges: settings.resumeAcrossModelChanges !== false,
|
|
16053
|
+
crossAccountResume: settings.crossAccountResume !== false,
|
|
15937
16054
|
transport: settings.transport,
|
|
15938
16055
|
interactive: settings.interactive,
|
|
15939
16056
|
interactiveBypass: settings.interactiveBypass,
|