@khalilgharbaoui/opencode-claude-code-plugin 0.26.2 → 0.26.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/README.md +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +131 -74
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/claude-code-plugin/SKILL.md +10 -2
package/README.md
CHANGED
|
@@ -250,6 +250,7 @@ What a pick does, in full:
|
|
|
250
250
|
- **The conversation is replayed, not resumed.** Claude transcripts live under each account's own `CLAUDE_CONFIG_DIR`, so `--resume` cannot cross accounts. The plugin starts a fresh Claude session on the target and replays the thread from opencode's history, then tells it to carry on. That costs input tokens on the new account, and anything the CLI held but opencode did not is gone.
|
|
251
251
|
- **Per-profile MCP servers do not come along.** A server configured only in the limited account's Claude profile is simply absent on the target.
|
|
252
252
|
- **`stop`, dismissing the form, or any answer that is not one of the offered accounts** ends the turn exactly the way the rate-limit error ends it today.
|
|
253
|
+
- **An account that cannot serve at all gets the same form.** When Claude Code reports that an account's login expired (`authentication_failed`), or that it is on hold, unverified or has a billing problem, the plugin writes a note naming the account and what to do, and offers the switch if another account is configured. For an expired login the note gives the exact command, for example `CLAUDE_CONFIG_DIR=~/.claude-work claude auth login`. The switch lasts until opencode restarts, so restart after logging in again to move back. With a single account you get the note alone.
|
|
253
254
|
|
|
254
255
|
Only two things open the form: a `rate_limit_event` the CLI marked `rejected`, and the two known account-limit error texts (`Third-party apps now draw from your extra usage…`, `You've hit your individual spend limit`). A generic 4xx, a timeout or a bad flag never does, deliberately: a transient failure must not quietly move where your usage is billed.
|
|
255
256
|
|
package/dist/index.d.ts
CHANGED
|
@@ -804,6 +804,12 @@ interface ClaudeStreamMessage {
|
|
|
804
804
|
agent_id?: string;
|
|
805
805
|
description?: string;
|
|
806
806
|
};
|
|
807
|
+
/**
|
|
808
|
+
* On an `assistant` message the CLI synthesised to report a failure: the
|
|
809
|
+
* kind of failure (`authentication_failed`, `billing_error`, ...). Read by
|
|
810
|
+
* `accountBlockKind`; schema confirmed on Claude Code 2.1.280.
|
|
811
|
+
*/
|
|
812
|
+
error?: string;
|
|
807
813
|
message?: {
|
|
808
814
|
role?: string;
|
|
809
815
|
model?: string;
|
package/dist/index.js
CHANGED
|
@@ -514,6 +514,9 @@ function translateStreamForHost(stream, dialect = "v1") {
|
|
|
514
514
|
);
|
|
515
515
|
}
|
|
516
516
|
|
|
517
|
+
// src/account-failover.ts
|
|
518
|
+
import { homedir as homedir2 } from "os";
|
|
519
|
+
|
|
517
520
|
// src/accounts.ts
|
|
518
521
|
import { chmod, lstat, mkdir, readlink, symlink, writeFile } from "fs/promises";
|
|
519
522
|
import path from "path";
|
|
@@ -1082,6 +1085,35 @@ var ACCOUNT_LIMIT_PATTERNS = [
|
|
|
1082
1085
|
/third-party apps now draw from your extra usage/i,
|
|
1083
1086
|
/you[’'`]?ve hit your individual spend limit/i
|
|
1084
1087
|
];
|
|
1088
|
+
var ACCOUNT_BLOCK_MARKER = "\u258C **claude account:**";
|
|
1089
|
+
var ACCOUNT_BLOCKS = {
|
|
1090
|
+
authentication_failed: { what: "is not logged in (its login expired or was revoked)", login: true },
|
|
1091
|
+
oauth_org_not_allowed: { what: "belongs to an organization that does not allow this login", login: false },
|
|
1092
|
+
account_on_hold: { what: "is on hold", login: false },
|
|
1093
|
+
verification_required: { what: "needs to be verified at claude.ai", login: false },
|
|
1094
|
+
billing_error: { what: "has a billing problem", login: false }
|
|
1095
|
+
};
|
|
1096
|
+
function accountBlockKind(msg) {
|
|
1097
|
+
if (msg.type !== "assistant" || typeof msg.error !== "string") return null;
|
|
1098
|
+
return Object.prototype.hasOwnProperty.call(ACCOUNT_BLOCKS, msg.error) ? msg.error : null;
|
|
1099
|
+
}
|
|
1100
|
+
function describeAccountBlock(kind) {
|
|
1101
|
+
return ACCOUNT_BLOCKS[kind].what;
|
|
1102
|
+
}
|
|
1103
|
+
function loginCommandFor(configDir, home = homedir2()) {
|
|
1104
|
+
if (!configDir) return "claude auth login";
|
|
1105
|
+
const shown = configDir === home || configDir.startsWith(`${home}/`) ? `~${configDir.slice(home.length)}` : configDir;
|
|
1106
|
+
return `CLAUDE_CONFIG_DIR=${shown} claude auth login`;
|
|
1107
|
+
}
|
|
1108
|
+
function formatAccountBlockNote(input) {
|
|
1109
|
+
const block = ACCOUNT_BLOCKS[input.kind];
|
|
1110
|
+
const account = normalizeAccountName(input.account || DEFAULT_ACCOUNT);
|
|
1111
|
+
const fix = block.login ? `Log in again with \`${loginCommandFor(input.configDir)}\`, then resend your message.` : "Check the account at claude.ai, then resend your message.";
|
|
1112
|
+
const then = input.offeringSwitch ? " Or pick another account below." : "";
|
|
1113
|
+
return `
|
|
1114
|
+
${ACCOUNT_BLOCK_MARKER} the Claude account "${account}" ${block.what}. ${fix}${then}
|
|
1115
|
+
`;
|
|
1116
|
+
}
|
|
1085
1117
|
function isAccountLimitError(input) {
|
|
1086
1118
|
if (input.rateLimit && isRateLimitRejected(input.rateLimit)) return true;
|
|
1087
1119
|
const text = input.resultText;
|
|
@@ -1187,7 +1219,7 @@ function createAccountFailoverQuestionCall(sessionKey2, input, toolCallId = `${A
|
|
|
1187
1219
|
const candidates = input.candidates.map((c) => normalizeAccountName(c));
|
|
1188
1220
|
const resets = describeReset(input.resetsAt);
|
|
1189
1221
|
const until = resets ?? "opencode restarts";
|
|
1190
|
-
const question = [
|
|
1222
|
+
const question = input.reason ? `The Claude account "${source}" ${input.reason}. Continue this task on another configured account? Leaving this unanswered waits, at no cost.` : [
|
|
1191
1223
|
`The Claude account "${source}" is out of usage`,
|
|
1192
1224
|
input.window ? ` in ${input.window}` : "",
|
|
1193
1225
|
resets ? `, which resets at ${resets}` : "",
|
|
@@ -4693,7 +4725,8 @@ var PLUGIN_NOTE_MARKERS = [
|
|
|
4693
4725
|
RESULT_ERROR_MARKER,
|
|
4694
4726
|
DOCTOR_MARKER,
|
|
4695
4727
|
STREAM_TIMEOUT_MARKER,
|
|
4696
|
-
FAILOVER_MARKER
|
|
4728
|
+
FAILOVER_MARKER,
|
|
4729
|
+
ACCOUNT_BLOCK_MARKER
|
|
4697
4730
|
];
|
|
4698
4731
|
function isPluginNote(part) {
|
|
4699
4732
|
if (!part || part.type !== "text" || typeof part.text !== "string") return false;
|
|
@@ -6289,7 +6322,7 @@ function spawnInteractiveProcess(opts) {
|
|
|
6289
6322
|
// src/claude-code-language-model.ts
|
|
6290
6323
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
6291
6324
|
import { unlink as unlink3 } from "fs/promises";
|
|
6292
|
-
import { homedir as
|
|
6325
|
+
import { homedir as homedir6, tmpdir as tmpdir2 } from "os";
|
|
6293
6326
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
6294
6327
|
import { dirname as dirname5, join as join8 } from "path";
|
|
6295
6328
|
async function isProxyCallStillServed(callId) {
|
|
@@ -6653,7 +6686,7 @@ ${options.compressionSummary.trim()}`
|
|
|
6653
6686
|
for (const s of extraSystemContent) {
|
|
6654
6687
|
if (s.trim()) parts.push(s.trim());
|
|
6655
6688
|
}
|
|
6656
|
-
const configRoot = process.env.XDG_CONFIG_HOME ?? join8(
|
|
6689
|
+
const configRoot = process.env.XDG_CONFIG_HOME ?? join8(homedir6(), ".config");
|
|
6657
6690
|
const globalAgents = readPromptFileIfPresent(join8(configRoot, "opencode", "AGENTS.md"));
|
|
6658
6691
|
const workspaceAgents = nearestWorkspaceAgentsPrompt(cwd);
|
|
6659
6692
|
const forwarded = extraSystemContent.join("\n\n");
|
|
@@ -8591,6 +8624,7 @@ ${plan}
|
|
|
8591
8624
|
let resultMeta = {};
|
|
8592
8625
|
let resultFailure;
|
|
8593
8626
|
let accountLimitHit = null;
|
|
8627
|
+
let accountBlock = null;
|
|
8594
8628
|
const drainBuffer = [];
|
|
8595
8629
|
let drainTimer = null;
|
|
8596
8630
|
const DRAIN_QUIET_MS = 100;
|
|
@@ -8752,20 +8786,21 @@ ${plan}
|
|
|
8752
8786
|
});
|
|
8753
8787
|
}
|
|
8754
8788
|
activeProcess?.pendingProxyCompletions?.clear();
|
|
8755
|
-
if (accountLimitHit && failoverAskActive && msg.is_error === true) {
|
|
8789
|
+
if ((accountLimitHit || accountBlock) && failoverAskActive && msg.is_error === true) {
|
|
8756
8790
|
const call = createAccountFailoverQuestionCall(sk, {
|
|
8757
8791
|
sourceAccount,
|
|
8758
8792
|
candidates: failoverAccounts,
|
|
8759
|
-
resetsAt: accountLimitHit
|
|
8760
|
-
window: accountLimitHit
|
|
8793
|
+
resetsAt: accountLimitHit?.resetsAt,
|
|
8794
|
+
window: accountLimitHit?.window,
|
|
8795
|
+
reason: accountLimitHit || !accountBlock ? void 0 : describeAccountBlock(accountBlock)
|
|
8761
8796
|
});
|
|
8762
8797
|
log.warn(
|
|
8763
|
-
`Claude account "${sourceAccount}" is out of usage; asking which account to continue on.`,
|
|
8798
|
+
`Claude account "${sourceAccount}" ${accountLimitHit || !accountBlock ? "is out of usage" : `cannot serve (${accountBlock})`}; asking which account to continue on.`,
|
|
8764
8799
|
{
|
|
8765
8800
|
sessionKey: sk,
|
|
8766
8801
|
candidates: failoverAccounts,
|
|
8767
8802
|
toolCallId: call.toolCallId,
|
|
8768
|
-
resetsAt: accountLimitHit
|
|
8803
|
+
resetsAt: accountLimitHit?.resetsAt ?? null
|
|
8769
8804
|
}
|
|
8770
8805
|
);
|
|
8771
8806
|
finishWithQuestionCall(call);
|
|
@@ -8903,6 +8938,8 @@ ${plan}
|
|
|
8903
8938
|
endTextBlock();
|
|
8904
8939
|
}
|
|
8905
8940
|
}
|
|
8941
|
+
const block = accountBlockKind(msg);
|
|
8942
|
+
if (block) accountBlock = block;
|
|
8906
8943
|
if (msg.type === "rate_limit_event") {
|
|
8907
8944
|
const info = parseRateLimitEvent(msg);
|
|
8908
8945
|
if (info && isRateLimitRejected(info)) {
|
|
@@ -8919,58 +8956,58 @@ ${plan}
|
|
|
8919
8956
|
return;
|
|
8920
8957
|
}
|
|
8921
8958
|
if (msg.type === "content_block_start" && msg.content_block && msg.index !== void 0) {
|
|
8922
|
-
const
|
|
8959
|
+
const block2 = msg.content_block;
|
|
8923
8960
|
const idx = msg.index;
|
|
8924
|
-
if (
|
|
8961
|
+
if (block2.type === "thinking") {
|
|
8925
8962
|
noteReasoning();
|
|
8926
8963
|
const reasoningId = generateId();
|
|
8927
8964
|
reasoningIds.set(idx, reasoningId);
|
|
8928
8965
|
}
|
|
8929
|
-
if (
|
|
8966
|
+
if (block2.type === "text") {
|
|
8930
8967
|
textBlockIndices.add(idx);
|
|
8931
8968
|
resetLastVisibleTextBlock();
|
|
8932
|
-
if (
|
|
8969
|
+
if (block2.text) {
|
|
8933
8970
|
if (!currentTextId) startTextBlock();
|
|
8934
8971
|
controller.enqueue({
|
|
8935
8972
|
type: "text-delta",
|
|
8936
8973
|
id: currentTextId,
|
|
8937
|
-
delta:
|
|
8974
|
+
delta: block2.text
|
|
8938
8975
|
});
|
|
8939
|
-
noteVisibleText(
|
|
8976
|
+
noteVisibleText(block2.text);
|
|
8940
8977
|
hasReceivedContent = true;
|
|
8941
8978
|
}
|
|
8942
8979
|
}
|
|
8943
|
-
if (
|
|
8980
|
+
if (block2.type === "tool_use" && block2.id && block2.name) {
|
|
8944
8981
|
noteToolActivity();
|
|
8945
8982
|
const entry = {
|
|
8946
|
-
id:
|
|
8947
|
-
name:
|
|
8983
|
+
id: block2.id,
|
|
8984
|
+
name: block2.name,
|
|
8948
8985
|
inputJson: "",
|
|
8949
8986
|
started: false
|
|
8950
8987
|
};
|
|
8951
8988
|
toolCallMap.set(idx, entry);
|
|
8952
|
-
if (
|
|
8989
|
+
if (block2.name !== "AskUserQuestion" && block2.name !== "ask_user_question" && block2.name !== "ExitPlanMode" && !block2.name.startsWith(PROXY_TOOL_PREFIX)) {
|
|
8953
8990
|
const { name: mappedName, skip, executed } = mapTool(
|
|
8954
|
-
|
|
8991
|
+
block2.name,
|
|
8955
8992
|
void 0,
|
|
8956
8993
|
{
|
|
8957
8994
|
webSearch: self.config.webSearch,
|
|
8958
8995
|
sessionId: getClaudeSessionId(sk),
|
|
8959
|
-
toolUseId:
|
|
8996
|
+
toolUseId: block2.id
|
|
8960
8997
|
}
|
|
8961
8998
|
);
|
|
8962
8999
|
if (!skip) {
|
|
8963
9000
|
entry.started = true;
|
|
8964
9001
|
controller.enqueue({
|
|
8965
9002
|
type: "tool-input-start",
|
|
8966
|
-
id:
|
|
9003
|
+
id: block2.id,
|
|
8967
9004
|
toolName: mappedName,
|
|
8968
9005
|
providerExecuted: executed
|
|
8969
9006
|
});
|
|
8970
9007
|
log.info("tool started", {
|
|
8971
|
-
name:
|
|
9008
|
+
name: block2.name,
|
|
8972
9009
|
mappedName,
|
|
8973
|
-
id:
|
|
9010
|
+
id: block2.id
|
|
8974
9011
|
});
|
|
8975
9012
|
}
|
|
8976
9013
|
}
|
|
@@ -9161,8 +9198,8 @@ ${plan}
|
|
|
9161
9198
|
hadStreamThinking: hadThinkingTextFromStream
|
|
9162
9199
|
});
|
|
9163
9200
|
if (!hadThinkingTextFromStream) {
|
|
9164
|
-
for (const
|
|
9165
|
-
if (
|
|
9201
|
+
for (const block2 of thinkingBlocks) {
|
|
9202
|
+
if (block2.thinking && block2.thinking.length > 0) {
|
|
9166
9203
|
noteReasoning();
|
|
9167
9204
|
hadThinkingTextFromStream = true;
|
|
9168
9205
|
const thinkingId = generateId();
|
|
@@ -9173,7 +9210,7 @@ ${plan}
|
|
|
9173
9210
|
controller.enqueue({
|
|
9174
9211
|
type: "reasoning-delta",
|
|
9175
9212
|
id: thinkingId,
|
|
9176
|
-
delta:
|
|
9213
|
+
delta: block2.thinking
|
|
9177
9214
|
});
|
|
9178
9215
|
controller.enqueue({
|
|
9179
9216
|
type: "reasoning-end",
|
|
@@ -9200,20 +9237,20 @@ ${plan}
|
|
|
9200
9237
|
if (hasToolUse) {
|
|
9201
9238
|
clearFallbackTimer();
|
|
9202
9239
|
}
|
|
9203
|
-
for (const
|
|
9204
|
-
if (
|
|
9240
|
+
for (const block2 of msg.message.content) {
|
|
9241
|
+
if (block2.type === "text" && block2.text) {
|
|
9205
9242
|
resetLastVisibleTextBlock();
|
|
9206
9243
|
const blockId = startTextBlock();
|
|
9207
9244
|
controller.enqueue({
|
|
9208
9245
|
type: "text-delta",
|
|
9209
9246
|
id: blockId,
|
|
9210
|
-
delta:
|
|
9247
|
+
delta: block2.text
|
|
9211
9248
|
});
|
|
9212
9249
|
endTextBlock();
|
|
9213
|
-
noteVisibleText(
|
|
9250
|
+
noteVisibleText(block2.text);
|
|
9214
9251
|
hasReceivedContent = true;
|
|
9215
9252
|
}
|
|
9216
|
-
if (
|
|
9253
|
+
if (block2.type === "thinking" && block2.thinking) {
|
|
9217
9254
|
noteReasoning();
|
|
9218
9255
|
const thinkingId = generateId();
|
|
9219
9256
|
controller.enqueue({
|
|
@@ -9223,17 +9260,17 @@ ${plan}
|
|
|
9223
9260
|
controller.enqueue({
|
|
9224
9261
|
type: "reasoning-delta",
|
|
9225
9262
|
id: thinkingId,
|
|
9226
|
-
delta:
|
|
9263
|
+
delta: block2.thinking
|
|
9227
9264
|
});
|
|
9228
9265
|
controller.enqueue({
|
|
9229
9266
|
type: "reasoning-end",
|
|
9230
9267
|
id: thinkingId
|
|
9231
9268
|
});
|
|
9232
9269
|
}
|
|
9233
|
-
if (
|
|
9270
|
+
if (block2.type === "tool_use" && block2.id && block2.name) {
|
|
9234
9271
|
noteToolActivity();
|
|
9235
|
-
const parsedInput =
|
|
9236
|
-
if (isAskUserQuestionTool(
|
|
9272
|
+
const parsedInput = block2.input ?? {};
|
|
9273
|
+
if (isAskUserQuestionTool(block2.name)) {
|
|
9237
9274
|
const askId = startTextBlock();
|
|
9238
9275
|
controller.enqueue({
|
|
9239
9276
|
type: "text-delta",
|
|
@@ -9241,12 +9278,12 @@ ${plan}
|
|
|
9241
9278
|
delta: formatAskUserQuestion(parsedInput)
|
|
9242
9279
|
});
|
|
9243
9280
|
endTextBlock();
|
|
9244
|
-
} else if (
|
|
9281
|
+
} else if (block2.name === "ExitPlanMode") {
|
|
9245
9282
|
const plan = parsedInput?.plan || "";
|
|
9246
9283
|
if (planModeQuestionActive) {
|
|
9247
9284
|
const questionCall = createExitPlanModeQuestionCall(
|
|
9248
9285
|
sk,
|
|
9249
|
-
|
|
9286
|
+
block2.id,
|
|
9250
9287
|
plan
|
|
9251
9288
|
);
|
|
9252
9289
|
const planId2 = startTextBlock();
|
|
@@ -9271,8 +9308,8 @@ ${plan}
|
|
|
9271
9308
|
`
|
|
9272
9309
|
});
|
|
9273
9310
|
endTextBlock();
|
|
9274
|
-
} else if (isWebSearchTool(
|
|
9275
|
-
toolCallsById.delete(
|
|
9311
|
+
} else if (isWebSearchTool(block2.name) && isWebSearchHandledByCli(self.config.webSearch)) {
|
|
9312
|
+
toolCallsById.delete(block2.id);
|
|
9276
9313
|
const query = typeof parsedInput?.query === "string" ? parsedInput.query : JSON.stringify(parsedInput);
|
|
9277
9314
|
const searchId = startTextBlock();
|
|
9278
9315
|
controller.enqueue({
|
|
@@ -9283,11 +9320,11 @@ ${plan}
|
|
|
9283
9320
|
`
|
|
9284
9321
|
});
|
|
9285
9322
|
endTextBlock();
|
|
9286
|
-
} else if (
|
|
9323
|
+
} else if (block2.name.startsWith(PROXY_TOOL_PREFIX)) {
|
|
9287
9324
|
noteProxyActivity();
|
|
9288
9325
|
log.debug("ignoring proxy tool_use from assistant message", {
|
|
9289
|
-
name:
|
|
9290
|
-
id:
|
|
9326
|
+
name: block2.name,
|
|
9327
|
+
id: block2.id
|
|
9291
9328
|
});
|
|
9292
9329
|
} else {
|
|
9293
9330
|
const {
|
|
@@ -9295,61 +9332,61 @@ ${plan}
|
|
|
9295
9332
|
input: mappedInput,
|
|
9296
9333
|
executed,
|
|
9297
9334
|
skip
|
|
9298
|
-
} = mapTool(
|
|
9335
|
+
} = mapTool(block2.name, parsedInput, {
|
|
9299
9336
|
webSearch: self.config.webSearch,
|
|
9300
9337
|
sessionId: getClaudeSessionId(sk),
|
|
9301
|
-
toolUseId:
|
|
9338
|
+
toolUseId: block2.id
|
|
9302
9339
|
});
|
|
9303
9340
|
if (!skip) {
|
|
9304
|
-
toolCallsById.set(
|
|
9305
|
-
id:
|
|
9306
|
-
name:
|
|
9341
|
+
toolCallsById.set(block2.id, {
|
|
9342
|
+
id: block2.id,
|
|
9343
|
+
name: block2.name,
|
|
9307
9344
|
input: parsedInput
|
|
9308
9345
|
});
|
|
9309
|
-
if (!executed) skipResultForIds.add(
|
|
9346
|
+
if (!executed) skipResultForIds.add(block2.id);
|
|
9310
9347
|
controller.enqueue({
|
|
9311
9348
|
type: "tool-input-start",
|
|
9312
|
-
id:
|
|
9349
|
+
id: block2.id,
|
|
9313
9350
|
toolName: mappedName,
|
|
9314
9351
|
providerExecuted: executed
|
|
9315
9352
|
});
|
|
9316
9353
|
controller.enqueue({
|
|
9317
9354
|
type: "tool-call",
|
|
9318
|
-
toolCallId:
|
|
9355
|
+
toolCallId: block2.id,
|
|
9319
9356
|
toolName: mappedName,
|
|
9320
9357
|
input: JSON.stringify(mappedInput),
|
|
9321
9358
|
providerExecuted: executed
|
|
9322
9359
|
});
|
|
9323
9360
|
}
|
|
9324
9361
|
log.info("tool_use from assistant message", {
|
|
9325
|
-
name:
|
|
9362
|
+
name: block2.name,
|
|
9326
9363
|
mappedName,
|
|
9327
|
-
id:
|
|
9364
|
+
id: block2.id,
|
|
9328
9365
|
executed
|
|
9329
9366
|
});
|
|
9330
9367
|
}
|
|
9331
9368
|
}
|
|
9332
|
-
if (
|
|
9369
|
+
if (block2.type === "tool_result") {
|
|
9333
9370
|
log.debug("tool_result", {
|
|
9334
|
-
toolUseId:
|
|
9371
|
+
toolUseId: block2.tool_use_id
|
|
9335
9372
|
});
|
|
9336
9373
|
}
|
|
9337
9374
|
}
|
|
9338
9375
|
}
|
|
9339
9376
|
if (msg.type === "user" && msg.message?.content) {
|
|
9340
|
-
for (const
|
|
9341
|
-
if (
|
|
9342
|
-
if (skipResultForIds.has(
|
|
9377
|
+
for (const block2 of msg.message.content) {
|
|
9378
|
+
if (block2.type === "tool_result" && block2.tool_use_id) {
|
|
9379
|
+
if (skipResultForIds.has(block2.tool_use_id)) {
|
|
9343
9380
|
log.debug("skipping tool-result (opencode runs it)", {
|
|
9344
|
-
toolUseId:
|
|
9381
|
+
toolUseId: block2.tool_use_id
|
|
9345
9382
|
});
|
|
9346
9383
|
continue;
|
|
9347
9384
|
}
|
|
9348
9385
|
let resultText = "";
|
|
9349
|
-
if (typeof
|
|
9350
|
-
resultText =
|
|
9351
|
-
} else if (Array.isArray(
|
|
9352
|
-
resultText =
|
|
9386
|
+
if (typeof block2.content === "string") {
|
|
9387
|
+
resultText = block2.content;
|
|
9388
|
+
} else if (Array.isArray(block2.content)) {
|
|
9389
|
+
resultText = block2.content.filter(
|
|
9353
9390
|
(c) => c.type === "text" && typeof c.text === "string"
|
|
9354
9391
|
).map((c) => c.text).join("\n");
|
|
9355
9392
|
}
|
|
@@ -9357,11 +9394,11 @@ ${plan}
|
|
|
9357
9394
|
if (claudeSessionId) {
|
|
9358
9395
|
const list2 = applyTaskCreateToolResult(
|
|
9359
9396
|
claudeSessionId,
|
|
9360
|
-
|
|
9397
|
+
block2.tool_use_id,
|
|
9361
9398
|
resultText
|
|
9362
9399
|
);
|
|
9363
9400
|
if (list2) {
|
|
9364
|
-
const synthId = `todowrite_${
|
|
9401
|
+
const synthId = `todowrite_${block2.tool_use_id}`;
|
|
9365
9402
|
controller.enqueue({
|
|
9366
9403
|
type: "tool-input-start",
|
|
9367
9404
|
id: synthId,
|
|
@@ -9385,12 +9422,12 @@ ${plan}
|
|
|
9385
9422
|
noteToolActivity();
|
|
9386
9423
|
}
|
|
9387
9424
|
}
|
|
9388
|
-
const toolCall = toolCallsById.get(
|
|
9425
|
+
const toolCall = toolCallsById.get(block2.tool_use_id);
|
|
9389
9426
|
if (toolCall) {
|
|
9390
|
-
const isError =
|
|
9427
|
+
const isError = block2.is_error === true;
|
|
9391
9428
|
controller.enqueue({
|
|
9392
9429
|
type: "tool-result",
|
|
9393
|
-
toolCallId:
|
|
9430
|
+
toolCallId: block2.tool_use_id,
|
|
9394
9431
|
toolName: toolCall.name,
|
|
9395
9432
|
result: {
|
|
9396
9433
|
output: resultText,
|
|
@@ -9402,11 +9439,11 @@ ${plan}
|
|
|
9402
9439
|
});
|
|
9403
9440
|
noteToolActivity();
|
|
9404
9441
|
log.info("tool result emitted", {
|
|
9405
|
-
toolUseId:
|
|
9442
|
+
toolUseId: block2.tool_use_id,
|
|
9406
9443
|
name: toolCall.name,
|
|
9407
9444
|
isError
|
|
9408
9445
|
});
|
|
9409
|
-
toolCallsById.delete(
|
|
9446
|
+
toolCallsById.delete(block2.tool_use_id);
|
|
9410
9447
|
}
|
|
9411
9448
|
}
|
|
9412
9449
|
}
|
|
@@ -9432,6 +9469,26 @@ ${plan}
|
|
|
9432
9469
|
})) {
|
|
9433
9470
|
accountLimitHit = {};
|
|
9434
9471
|
}
|
|
9472
|
+
if (accountBlock && msg.is_error) {
|
|
9473
|
+
resultFailure ??= accountBlock;
|
|
9474
|
+
const offeringSwitch = failoverAskActive;
|
|
9475
|
+
controller.enqueue({
|
|
9476
|
+
type: "text-delta",
|
|
9477
|
+
id: startTextBlock(),
|
|
9478
|
+
delta: formatAccountBlockNote({
|
|
9479
|
+
kind: accountBlock,
|
|
9480
|
+
account: sourceAccount,
|
|
9481
|
+
configDir: self.config.configDir,
|
|
9482
|
+
offeringSwitch
|
|
9483
|
+
})
|
|
9484
|
+
});
|
|
9485
|
+
endTextBlock();
|
|
9486
|
+
log.warn(`Claude account "${sourceAccount}" cannot serve requests`, {
|
|
9487
|
+
sessionKey: sk,
|
|
9488
|
+
kind: accountBlock,
|
|
9489
|
+
offeringSwitch
|
|
9490
|
+
});
|
|
9491
|
+
}
|
|
9435
9492
|
const failure = describeResultFailure(msg);
|
|
9436
9493
|
if (failure) {
|
|
9437
9494
|
resultFailure = msg.subtype;
|
|
@@ -9877,7 +9934,7 @@ import {
|
|
|
9877
9934
|
rmSync as rmSync3,
|
|
9878
9935
|
writeFileSync as writeFileSync5
|
|
9879
9936
|
} from "fs";
|
|
9880
|
-
import { homedir as
|
|
9937
|
+
import { homedir as homedir7 } from "os";
|
|
9881
9938
|
import { join as join9, resolve as resolve4 } from "path";
|
|
9882
9939
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
9883
9940
|
var STALE_PACKAGE_NAME = "opencode-claude-code-plugin";
|
|
@@ -9887,12 +9944,12 @@ function candidateCacheRoots() {
|
|
|
9887
9944
|
const xdg = process.env.XDG_CACHE_HOME;
|
|
9888
9945
|
return [
|
|
9889
9946
|
xdg ? join9(xdg, "opencode") : null,
|
|
9890
|
-
join9(
|
|
9891
|
-
join9(
|
|
9947
|
+
join9(homedir7(), ".cache", "opencode"),
|
|
9948
|
+
join9(homedir7(), "Library", "Caches", "opencode")
|
|
9892
9949
|
].filter((p) => Boolean(p));
|
|
9893
9950
|
}
|
|
9894
9951
|
function userOpencodeJsonPath() {
|
|
9895
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME ?? join9(
|
|
9952
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME ?? join9(homedir7(), ".config");
|
|
9896
9953
|
return join9(xdgConfig, "opencode", "opencode.json");
|
|
9897
9954
|
}
|
|
9898
9955
|
function userIntendsToUseUnscoped() {
|