@khalilgharbaoui/opencode-claude-code-plugin 0.61.0 → 0.61.1
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.js +100 -43
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/claude-code-plugin/SKILL.md +1 -1
package/dist/index.js
CHANGED
|
@@ -3808,23 +3808,36 @@ import { createHash } from "crypto";
|
|
|
3808
3808
|
var fingerprints = /* @__PURE__ */ new Map();
|
|
3809
3809
|
var fingerprintSeq = 0;
|
|
3810
3810
|
var MAX_FORK_FINGERPRINTS = 64;
|
|
3811
|
-
var DIGEST_VERSION =
|
|
3811
|
+
var DIGEST_VERSION = 3;
|
|
3812
3812
|
var DCP_MESSAGE_ID_TAG = /<dcp-message-id(?:\s[^>]*)?>[^<]*<\/dcp-message-id>/g;
|
|
3813
3813
|
var DCP_COMPACT_REF_LINE = /^@(?:\d+|b\d+|blocked)@(?: \[[^\]\n]*\])?$/;
|
|
3814
|
-
|
|
3815
|
-
|
|
3814
|
+
var DCP_SYSTEM_REMINDER_BLOCK = /<dcp-system-reminder>[\s\S]*?<\/dcp-system-reminder>/g;
|
|
3815
|
+
function withoutDcpRefs(text, version) {
|
|
3816
|
+
let out = text;
|
|
3817
|
+
let removed = false;
|
|
3818
|
+
if (version >= 3 && out.includes("<dcp-system-reminder")) {
|
|
3819
|
+
out = out.replace(DCP_SYSTEM_REMINDER_BLOCK, "");
|
|
3820
|
+
removed = true;
|
|
3821
|
+
}
|
|
3822
|
+
if (out.includes("<dcp-message-id")) {
|
|
3823
|
+
out = out.replace(DCP_MESSAGE_ID_TAG, "");
|
|
3824
|
+
removed = true;
|
|
3825
|
+
}
|
|
3816
3826
|
for (; ; ) {
|
|
3817
3827
|
const trimmed = out.trimEnd();
|
|
3818
|
-
if (!trimmed.endsWith("@") && !trimmed.endsWith("]"))
|
|
3828
|
+
if (!trimmed.endsWith("@") && !trimmed.endsWith("]")) break;
|
|
3819
3829
|
const lineStart = trimmed.lastIndexOf("\n") + 1;
|
|
3820
|
-
if (!DCP_COMPACT_REF_LINE.test(trimmed.slice(lineStart)))
|
|
3830
|
+
if (!DCP_COMPACT_REF_LINE.test(trimmed.slice(lineStart))) break;
|
|
3821
3831
|
out = trimmed.slice(0, lineStart);
|
|
3832
|
+
removed = true;
|
|
3822
3833
|
}
|
|
3834
|
+
if (version < 3 || !removed) return out;
|
|
3835
|
+
return out.replace(/\n{3,}/g, "\n\n").trim();
|
|
3823
3836
|
}
|
|
3824
3837
|
function hashPart(hash, part, version) {
|
|
3825
3838
|
const p = part;
|
|
3826
3839
|
const type = typeof p?.type === "string" ? p.type : "unknown";
|
|
3827
|
-
const content = (text) => version >= 2 ? withoutDcpRefs(text) : text;
|
|
3840
|
+
const content = (text) => version >= 2 ? withoutDcpRefs(text, version) : text;
|
|
3828
3841
|
switch (type) {
|
|
3829
3842
|
case "text":
|
|
3830
3843
|
hash.update("text\0");
|
|
@@ -3840,7 +3853,9 @@ function hashPart(hash, part, version) {
|
|
|
3840
3853
|
hash.update("result\0");
|
|
3841
3854
|
hash.update(String(p?.toolName ?? ""));
|
|
3842
3855
|
hash.update("\0");
|
|
3843
|
-
hash.update(
|
|
3856
|
+
hash.update(
|
|
3857
|
+
stableJson(p?.output, version >= 2 ? (text) => withoutDcpRefs(text, version) : void 0)
|
|
3858
|
+
);
|
|
3844
3859
|
break;
|
|
3845
3860
|
case "file":
|
|
3846
3861
|
case "image": {
|
|
@@ -3888,7 +3903,7 @@ function messageDigest(msg, version) {
|
|
|
3888
3903
|
hash.update("\0");
|
|
3889
3904
|
if (typeof msg.content === "string") {
|
|
3890
3905
|
hash.update("text\0");
|
|
3891
|
-
hash.update(version >= 2 ? withoutDcpRefs(msg.content) : msg.content);
|
|
3906
|
+
hash.update(version >= 2 ? withoutDcpRefs(msg.content, version) : msg.content);
|
|
3892
3907
|
hash.update("");
|
|
3893
3908
|
} else if (Array.isArray(msg.content)) {
|
|
3894
3909
|
for (const part of msg.content) hashPart(hash, part, version);
|
|
@@ -7429,6 +7444,7 @@ function findForeignAccountSibling(opts) {
|
|
|
7429
7444
|
if (modelSiblingSignature(key, providers) !== signature) return void 0;
|
|
7430
7445
|
const account = sessionKeyAccount(key, providers);
|
|
7431
7446
|
if (account === void 0 || account === ownAccount) return void 0;
|
|
7447
|
+
if (opts.only && !opts.only(account)) return void 0;
|
|
7432
7448
|
return { siblingKey: key, account };
|
|
7433
7449
|
};
|
|
7434
7450
|
for (const key of opts.extraKeys ?? []) {
|
|
@@ -9130,6 +9146,7 @@ var PLUGIN_LOG_MESSAGES = /* @__PURE__ */ new Set([
|
|
|
9130
9146
|
"no configured account could take this turn; it ends here",
|
|
9131
9147
|
"no proxyTools entry was recognised; nothing will be proxied this turn",
|
|
9132
9148
|
"no stdout after envelope write; respawning claude process to resume conversation",
|
|
9149
|
+
"not replaying what this claude session missed: the conversation continued on an account in another group",
|
|
9133
9150
|
"opencode 2 event subscription ended; deleted sessions keep their claude process until idle eviction, and stopped turns keep their proxy calls until the next message",
|
|
9134
9151
|
"opencode's stored OAuth token for this MCP server has expired, so the bridged server carries no credential; re-authenticate it in opencode",
|
|
9135
9152
|
"pending proxy call arrived after stream close; rejecting",
|
|
@@ -9267,6 +9284,7 @@ var BUNDLE_DATA_ALLOWLIST = {
|
|
|
9267
9284
|
historyLength: "count",
|
|
9268
9285
|
matchedMessages: "count",
|
|
9269
9286
|
messages: "count",
|
|
9287
|
+
userMessages: "count",
|
|
9270
9288
|
inputTokens: "count",
|
|
9271
9289
|
lastTextLength: "count",
|
|
9272
9290
|
lines: "count",
|
|
@@ -18445,30 +18463,45 @@ var ClaudeCodeLanguageModel = class {
|
|
|
18445
18463
|
carried: conversationOnTarget
|
|
18446
18464
|
});
|
|
18447
18465
|
}
|
|
18448
|
-
let
|
|
18449
|
-
|
|
18450
|
-
|
|
18466
|
+
let crossGroupAccountRead = false;
|
|
18467
|
+
let crossGroupAccountValue;
|
|
18468
|
+
const crossGroupAccount = () => {
|
|
18469
|
+
if (crossGroupAccountRead) return crossGroupAccountValue;
|
|
18470
|
+
crossGroupAccountRead = true;
|
|
18471
|
+
if (compactionMode || !groups || accountProviders.size === 0) return void 0;
|
|
18472
|
+
if (failoverAnswer?.kind === "switch") return void 0;
|
|
18473
|
+
crossGroupAccountValue = findForeignAccountSibling({
|
|
18451
18474
|
sessionKey: sk,
|
|
18452
18475
|
accountProviders,
|
|
18453
18476
|
// The live process's own view, so the guard holds with
|
|
18454
18477
|
// `resumeAfterRestart: false`, where the store is never written.
|
|
18455
|
-
extraKeys: listClaudeSessionKeys()
|
|
18478
|
+
extraKeys: listClaudeSessionKeys(),
|
|
18479
|
+
only: (account) => !accountsShareGroup(sourceAccount, account, groups)
|
|
18480
|
+
})?.account;
|
|
18481
|
+
return crossGroupAccountValue;
|
|
18482
|
+
};
|
|
18483
|
+
const accountGroupNoteFor = (from) => formatAccountGroupNote({
|
|
18484
|
+
sourceAccount: from,
|
|
18485
|
+
sourceGroup: accountGroup(from, groups),
|
|
18486
|
+
targetAccount: sourceAccount,
|
|
18487
|
+
targetGroup: accountGroup(sourceAccount, groups)
|
|
18488
|
+
});
|
|
18489
|
+
const logAnotherAccountGroup = (from) => {
|
|
18490
|
+
log.notice("starting fresh on this account: it is in another account group", {
|
|
18491
|
+
sessionKey: sk,
|
|
18492
|
+
reason: "another-account-group",
|
|
18493
|
+
account: sourceAccount,
|
|
18494
|
+
from,
|
|
18495
|
+
group: accountGroup(sourceAccount, groups)
|
|
18456
18496
|
});
|
|
18457
|
-
|
|
18497
|
+
};
|
|
18498
|
+
let accountGroupNote = null;
|
|
18499
|
+
if (includeHistoryContext) {
|
|
18500
|
+
const from = crossGroupAccount();
|
|
18501
|
+
if (from) {
|
|
18458
18502
|
includeHistoryContext = false;
|
|
18459
|
-
accountGroupNote =
|
|
18460
|
-
|
|
18461
|
-
sourceGroup: accountGroup(foreign.account, groups),
|
|
18462
|
-
targetAccount: sourceAccount,
|
|
18463
|
-
targetGroup: accountGroup(sourceAccount, groups)
|
|
18464
|
-
});
|
|
18465
|
-
log.notice("starting fresh on this account: it is in another account group", {
|
|
18466
|
-
sessionKey: sk,
|
|
18467
|
-
reason: "another-account-group",
|
|
18468
|
-
account: sourceAccount,
|
|
18469
|
-
from: foreign.account,
|
|
18470
|
-
group: accountGroup(sourceAccount, groups)
|
|
18471
|
-
});
|
|
18503
|
+
accountGroupNote = accountGroupNoteFor(from);
|
|
18504
|
+
logAnotherAccountGroup(from);
|
|
18472
18505
|
}
|
|
18473
18506
|
}
|
|
18474
18507
|
let forkFromClaudeSessionId;
|
|
@@ -18618,28 +18651,52 @@ var ClaudeCodeLanguageModel = class {
|
|
|
18618
18651
|
});
|
|
18619
18652
|
}
|
|
18620
18653
|
const conversationChange = !compactionMode && !includeHistoryContext && failoverAnswer?.kind !== "switch" && !accountGroupNote && (!!getClaudeSessionId(sk) || !!getActiveProcess(sk)) ? classifyConversationChange(sk, filterSideQuestionHistory(options.prompt)) : null;
|
|
18621
|
-
|
|
18622
|
-
if (missed) {
|
|
18623
|
-
|
|
18624
|
-
|
|
18625
|
-
|
|
18626
|
-
|
|
18627
|
-
|
|
18654
|
+
let missed = null;
|
|
18655
|
+
if (conversationChange?.kind === "missed") {
|
|
18656
|
+
const from = crossGroupAccount();
|
|
18657
|
+
if (from) {
|
|
18658
|
+
log.notice(
|
|
18659
|
+
"not replaying what this claude session missed: the conversation continued on an account in another group",
|
|
18660
|
+
{
|
|
18661
|
+
sessionKey: sk,
|
|
18662
|
+
reason: "another-account-group",
|
|
18663
|
+
account: sourceAccount,
|
|
18664
|
+
from,
|
|
18665
|
+
group: accountGroup(sourceAccount, groups),
|
|
18666
|
+
messages: conversationChange.messages.length,
|
|
18667
|
+
userMessages: conversationChange.userMessages
|
|
18668
|
+
}
|
|
18669
|
+
);
|
|
18670
|
+
} else {
|
|
18671
|
+
missed = conversationChange;
|
|
18672
|
+
log.notice("replaying the messages this claude session missed: the conversation continued under another session key", {
|
|
18673
|
+
sessionKey: sk,
|
|
18674
|
+
messages: missed.messages.length,
|
|
18675
|
+
userMessages: missed.userMessages
|
|
18676
|
+
});
|
|
18677
|
+
}
|
|
18628
18678
|
}
|
|
18629
18679
|
let rewoundNote = null;
|
|
18630
18680
|
if (conversationChange?.kind === "rewound") {
|
|
18631
18681
|
await deleteActiveProcessAndWait(sk);
|
|
18632
18682
|
deleteClaudeSessionId(sk);
|
|
18633
|
-
|
|
18634
|
-
|
|
18635
|
-
|
|
18636
|
-
|
|
18637
|
-
|
|
18638
|
-
|
|
18639
|
-
|
|
18640
|
-
|
|
18641
|
-
|
|
18642
|
-
|
|
18683
|
+
const from = crossGroupAccount();
|
|
18684
|
+
if (from) {
|
|
18685
|
+
includeHistoryContext = false;
|
|
18686
|
+
accountGroupNote = accountGroupNote ?? accountGroupNoteFor(from);
|
|
18687
|
+
logAnotherAccountGroup(from);
|
|
18688
|
+
} else {
|
|
18689
|
+
includeHistoryContext = true;
|
|
18690
|
+
replayReason = "history-rewound";
|
|
18691
|
+
log.notice("replaying the conversation as text: the thread was edited or undone", {
|
|
18692
|
+
sessionKey: sk,
|
|
18693
|
+
reason: "history-rewound",
|
|
18694
|
+
sharedMessages: conversationChange.sharedMessages,
|
|
18695
|
+
removedMessages: conversationChange.removedMessages,
|
|
18696
|
+
removedUserMessages: conversationChange.removedUserMessages
|
|
18697
|
+
});
|
|
18698
|
+
if (mode !== "generate") rewoundNote = formatConversationRewoundNote();
|
|
18699
|
+
}
|
|
18643
18700
|
}
|
|
18644
18701
|
if (this.config.forkSessions === true && !compactionMode) {
|
|
18645
18702
|
recordForkFingerprint(sk, options.prompt, cliPath);
|