@khalilgharbaoui/opencode-claude-code-plugin 0.56.0 → 0.57.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.js +252 -49
- package/dist/index.js.map +1 -1
- package/dist/tui.js +751 -140
- package/dist/tui.js.map +1 -1
- package/package.json +1 -1
- package/skills/claude-code-plugin/SKILL.md +20 -3
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/claude-code-language-model.ts
|
|
2
|
-
import { join as
|
|
2
|
+
import { join as join18 } from "path";
|
|
3
3
|
|
|
4
4
|
// src/ids.ts
|
|
5
5
|
import { randomInt } from "crypto";
|
|
@@ -717,6 +717,7 @@ var MAX_USAGE_ACCOUNTS = 32;
|
|
|
717
717
|
var MAX_USAGE_WINDOWS = 8;
|
|
718
718
|
var NAME = /^[a-z0-9_-]{1,64}$/;
|
|
719
719
|
var STATUS = /^[a-z_]{1,32}$/;
|
|
720
|
+
var TIER = /^[A-Za-z0-9][A-Za-z0-9 ]{0,23}$/;
|
|
720
721
|
var MAX_RESETS_TEXT = 80;
|
|
721
722
|
var pathOverride = null;
|
|
722
723
|
var cache = null;
|
|
@@ -750,11 +751,28 @@ function validEntry(value) {
|
|
|
750
751
|
noted
|
|
751
752
|
};
|
|
752
753
|
}
|
|
753
|
-
|
|
754
|
+
var emptyStore = () => ({ usage: /* @__PURE__ */ new Map(), known: /* @__PURE__ */ new Map() });
|
|
755
|
+
function readKnown(parsed) {
|
|
754
756
|
const out = /* @__PURE__ */ new Map();
|
|
757
|
+
const known = parsed.known;
|
|
758
|
+
if (!known || typeof known !== "object" || Array.isArray(known)) return out;
|
|
759
|
+
for (const [account, raw] of Object.entries(known)) {
|
|
760
|
+
if (out.size >= MAX_USAGE_ACCOUNTS) break;
|
|
761
|
+
if (!NAME.test(account) || !raw || typeof raw !== "object" || Array.isArray(raw)) continue;
|
|
762
|
+
const record = raw;
|
|
763
|
+
if (!finite(record.at)) continue;
|
|
764
|
+
const tier = typeof record.tier === "string" && TIER.test(record.tier) ? record.tier : void 0;
|
|
765
|
+
out.set(account, { ...tier ? { tier } : {}, at: record.at });
|
|
766
|
+
}
|
|
767
|
+
return out;
|
|
768
|
+
}
|
|
769
|
+
function parseStore(file, now) {
|
|
770
|
+
const out = emptyStore();
|
|
755
771
|
try {
|
|
756
772
|
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
757
|
-
|
|
773
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return out;
|
|
774
|
+
out.known = readKnown(parsed);
|
|
775
|
+
const accounts = parsed.accounts;
|
|
758
776
|
if (!accounts || typeof accounts !== "object" || Array.isArray(accounts)) return out;
|
|
759
777
|
const cutoff = now - USAGE_READING_MAX_AGE_MS;
|
|
760
778
|
for (const [account, windows] of Object.entries(accounts)) {
|
|
@@ -765,12 +783,15 @@ function readStore(file, now) {
|
|
|
765
783
|
const entry = validEntry(raw);
|
|
766
784
|
if (entry && entry.observedAt >= cutoff) kept.set(window, entry);
|
|
767
785
|
}
|
|
768
|
-
if (kept.size > 0) out.set(account, kept);
|
|
786
|
+
if (kept.size > 0) out.usage.set(account, kept);
|
|
769
787
|
}
|
|
770
788
|
} catch {
|
|
771
789
|
}
|
|
772
790
|
return out;
|
|
773
791
|
}
|
|
792
|
+
function readStore(file, now) {
|
|
793
|
+
return parseStore(file, now).usage;
|
|
794
|
+
}
|
|
774
795
|
function newestObserved(windows) {
|
|
775
796
|
let newest = 0;
|
|
776
797
|
for (const entry of windows.values()) newest = Math.max(newest, entry.observedAt);
|
|
@@ -784,13 +805,14 @@ function bounded(usage, now) {
|
|
|
784
805
|
}).filter(([, windows]) => windows.size > 0).sort((a, b) => newestObserved(a[1]) - newestObserved(b[1])).slice(-MAX_USAGE_ACCOUNTS);
|
|
785
806
|
return new Map(accounts);
|
|
786
807
|
}
|
|
787
|
-
function writeStore(file, usage) {
|
|
808
|
+
function writeStore(file, usage, known) {
|
|
788
809
|
const accounts = {};
|
|
789
810
|
for (const [account, windows] of usage) accounts[account] = Object.fromEntries(windows);
|
|
811
|
+
const registered2 = known.size > 0 ? { known: Object.fromEntries(known) } : {};
|
|
790
812
|
try {
|
|
791
813
|
mkdirSync2(join2(file, ".."), { recursive: true, mode: 448 });
|
|
792
814
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
793
|
-
writeFileSync(tmp, JSON.stringify({ version: 1, accounts }), { mode: 384 });
|
|
815
|
+
writeFileSync(tmp, JSON.stringify({ version: 1, accounts, ...registered2 }), { mode: 384 });
|
|
794
816
|
renameSync2(tmp, file);
|
|
795
817
|
return true;
|
|
796
818
|
} catch {
|
|
@@ -845,7 +867,8 @@ function resolveUsageSwitchAt(value) {
|
|
|
845
867
|
function recordUsageReading(account, window, reading, now = Date.now()) {
|
|
846
868
|
if (!NAME.test(account) || !NAME.test(window)) return null;
|
|
847
869
|
const file = accountUsageStorePath();
|
|
848
|
-
const
|
|
870
|
+
const store = parseStore(file, now);
|
|
871
|
+
const merged = store.usage;
|
|
849
872
|
const previous = merged.get(account)?.get(window) ?? cached(now).get(account)?.get(window);
|
|
850
873
|
const entry = applyReading(previous, reading, now);
|
|
851
874
|
const windows = merged.get(account) ?? /* @__PURE__ */ new Map();
|
|
@@ -853,12 +876,13 @@ function recordUsageReading(account, window, reading, now = Date.now()) {
|
|
|
853
876
|
merged.set(account, windows);
|
|
854
877
|
const kept = bounded(merged, now);
|
|
855
878
|
cache = { path: file, usage: kept };
|
|
856
|
-
return writeStore(file, kept) ? entry : null;
|
|
879
|
+
return writeStore(file, kept, store.known) ? entry : null;
|
|
857
880
|
}
|
|
858
881
|
function markUsageNoted(account, window, thresholds, now = Date.now()) {
|
|
859
882
|
if (!NAME.test(account) || !NAME.test(window) || thresholds.length === 0) return false;
|
|
860
883
|
const file = accountUsageStorePath();
|
|
861
|
-
const
|
|
884
|
+
const store = parseStore(file, now);
|
|
885
|
+
const merged = store.usage;
|
|
862
886
|
const entry = merged.get(account)?.get(window) ?? cached(now).get(account)?.get(window);
|
|
863
887
|
if (!entry) return false;
|
|
864
888
|
const updated = {
|
|
@@ -870,7 +894,28 @@ function markUsageNoted(account, window, thresholds, now = Date.now()) {
|
|
|
870
894
|
merged.set(account, windows);
|
|
871
895
|
const kept = bounded(merged, now);
|
|
872
896
|
cache = { path: file, usage: kept };
|
|
873
|
-
return writeStore(file, kept);
|
|
897
|
+
return writeStore(file, kept, store.known);
|
|
898
|
+
}
|
|
899
|
+
function sameKnown(a, b) {
|
|
900
|
+
if (a.size !== b.size) return false;
|
|
901
|
+
for (const [account, record] of a) {
|
|
902
|
+
const other = b.get(account);
|
|
903
|
+
if (!other || other.tier !== record.tier) return false;
|
|
904
|
+
}
|
|
905
|
+
return true;
|
|
906
|
+
}
|
|
907
|
+
function registerKnownAccounts(accounts, now = Date.now()) {
|
|
908
|
+
const file = accountUsageStorePath();
|
|
909
|
+
const store = parseStore(file, now);
|
|
910
|
+
const known = /* @__PURE__ */ new Map();
|
|
911
|
+
for (const entry of accounts) {
|
|
912
|
+
if (known.size >= MAX_USAGE_ACCOUNTS) break;
|
|
913
|
+
if (!NAME.test(entry.account)) continue;
|
|
914
|
+
const tier = entry.tier && TIER.test(entry.tier) ? entry.tier : void 0;
|
|
915
|
+
known.set(entry.account, { ...tier ? { tier } : {}, at: now });
|
|
916
|
+
}
|
|
917
|
+
if (sameKnown(store.known, known)) return true;
|
|
918
|
+
return writeStore(file, bounded(store.usage, now), known);
|
|
874
919
|
}
|
|
875
920
|
function usageCrossings(account, thresholds, now = Date.now()) {
|
|
876
921
|
if (thresholds.length === 0) return [];
|
|
@@ -13267,7 +13312,7 @@ function isRecord5(value) {
|
|
|
13267
13312
|
if (!record || typeof record !== "object" || Array.isArray(record)) return false;
|
|
13268
13313
|
if (typeof record.at !== "number" || !Number.isFinite(record.at)) return false;
|
|
13269
13314
|
const ok = (field) => field === void 0 || typeof field === "string";
|
|
13270
|
-
if (!ok(record.model) || !ok(record.effort) || !ok(record.account)) return false;
|
|
13315
|
+
if (!ok(record.model) || !ok(record.effort) || !ok(record.account) || !ok(record.agent)) return false;
|
|
13271
13316
|
return !!record.model;
|
|
13272
13317
|
}
|
|
13273
13318
|
function readEntries(file) {
|
|
@@ -13283,6 +13328,7 @@ function readEntries(file) {
|
|
|
13283
13328
|
model: record.model,
|
|
13284
13329
|
...record.effort ? { effort: record.effort } : {},
|
|
13285
13330
|
...record.account ? { account: record.account } : {},
|
|
13331
|
+
...record.agent ? { agent: record.agent } : {},
|
|
13286
13332
|
at: record.at
|
|
13287
13333
|
});
|
|
13288
13334
|
}
|
|
@@ -13296,11 +13342,13 @@ function recordSessionSpawn(sessionID, spawn2, now = Date.now()) {
|
|
|
13296
13342
|
model: spawn2.model,
|
|
13297
13343
|
...spawn2.effort ? { effort: spawn2.effort } : {},
|
|
13298
13344
|
...spawn2.account ? { account: spawn2.account } : {},
|
|
13345
|
+
...spawn2.agent ? { agent: spawn2.agent } : {},
|
|
13299
13346
|
at: now
|
|
13300
13347
|
};
|
|
13301
13348
|
const fingerprint = `${record.model}
|
|
13302
13349
|
${record.effort ?? ""}
|
|
13303
|
-
${record.account ?? ""}
|
|
13350
|
+
${record.account ?? ""}
|
|
13351
|
+
${record.agent ?? ""}`;
|
|
13304
13352
|
if (lastWritten.get(sessionID) === fingerprint) return false;
|
|
13305
13353
|
const file = spawnRecordStorePath();
|
|
13306
13354
|
const merged = readEntries(file);
|
|
@@ -13323,6 +13371,133 @@ ${record.account ?? ""}`;
|
|
|
13323
13371
|
return true;
|
|
13324
13372
|
}
|
|
13325
13373
|
|
|
13374
|
+
// src/turn-history.ts
|
|
13375
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync10, renameSync as renameSync6, statSync as statSync9, writeFileSync as writeFileSync9 } from "fs";
|
|
13376
|
+
import { homedir as homedir13 } from "os";
|
|
13377
|
+
import { join as join16 } from "path";
|
|
13378
|
+
var MAX_TURN_SAMPLES = 48;
|
|
13379
|
+
var MAX_TURN_KEYS = 64;
|
|
13380
|
+
var TURN_SAMPLE_MAX_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
13381
|
+
var CHARS_BANDWIDTH = Math.log(4);
|
|
13382
|
+
var pathOverride5 = null;
|
|
13383
|
+
function turnHistoryStorePath() {
|
|
13384
|
+
if (pathOverride5) return pathOverride5;
|
|
13385
|
+
const stateRoot = process.env.XDG_STATE_HOME || join16(homedir13(), ".local", "state");
|
|
13386
|
+
return join16(stateRoot, "opencode-claude-code-plugin", "turn-history.json");
|
|
13387
|
+
}
|
|
13388
|
+
function turnHistoryKey(agent, model) {
|
|
13389
|
+
return `${agent || "main"}/${model}`;
|
|
13390
|
+
}
|
|
13391
|
+
var INJECTED_BLOCKS = [
|
|
13392
|
+
/<system-reminder>[\s\S]*?<\/system-reminder>/g,
|
|
13393
|
+
/<dcp-system-reminder>[\s\S]*?<\/dcp-system-reminder>/g,
|
|
13394
|
+
/<dcp-message-id>[\s\S]*?<\/dcp-message-id>/g
|
|
13395
|
+
];
|
|
13396
|
+
function promptChars(texts) {
|
|
13397
|
+
if (texts.length === 0) return void 0;
|
|
13398
|
+
let total = 0;
|
|
13399
|
+
for (const text of texts) {
|
|
13400
|
+
let stripped = text;
|
|
13401
|
+
for (const block of INJECTED_BLOCKS) stripped = stripped.replace(block, "");
|
|
13402
|
+
total += stripped.trim().length;
|
|
13403
|
+
}
|
|
13404
|
+
return total;
|
|
13405
|
+
}
|
|
13406
|
+
function textsOf(content) {
|
|
13407
|
+
if (typeof content === "string") return [content];
|
|
13408
|
+
if (!Array.isArray(content)) return [];
|
|
13409
|
+
const texts = [];
|
|
13410
|
+
for (const part of content) {
|
|
13411
|
+
if (!part || typeof part !== "object" || part.type !== "text") continue;
|
|
13412
|
+
const text = part.text;
|
|
13413
|
+
if (typeof text === "string") texts.push(text);
|
|
13414
|
+
}
|
|
13415
|
+
return texts;
|
|
13416
|
+
}
|
|
13417
|
+
function newestPromptChars(prompt) {
|
|
13418
|
+
for (let index = prompt.length - 1; index >= 0; index -= 1) {
|
|
13419
|
+
if (prompt[index].role === "user") return promptChars(textsOf(prompt[index].content));
|
|
13420
|
+
}
|
|
13421
|
+
return void 0;
|
|
13422
|
+
}
|
|
13423
|
+
function startsTurn(prompt) {
|
|
13424
|
+
const last = prompt[prompt.length - 1];
|
|
13425
|
+
if (!last || last.role !== "user") return false;
|
|
13426
|
+
const before = prompt[prompt.length - 2];
|
|
13427
|
+
return before === void 0 || before.role !== "tool";
|
|
13428
|
+
}
|
|
13429
|
+
var MAX_TURN_STARTS = 256;
|
|
13430
|
+
var turnStarts = /* @__PURE__ */ new Map();
|
|
13431
|
+
function markTurnStart(key, at, chars) {
|
|
13432
|
+
turnStarts.delete(key);
|
|
13433
|
+
if (turnStarts.size >= MAX_TURN_STARTS) {
|
|
13434
|
+
const oldest = turnStarts.keys().next().value;
|
|
13435
|
+
if (oldest !== void 0) turnStarts.delete(oldest);
|
|
13436
|
+
}
|
|
13437
|
+
turnStarts.set(key, { at, ...chars !== void 0 ? { chars } : {} });
|
|
13438
|
+
}
|
|
13439
|
+
function takeTurnStart(key) {
|
|
13440
|
+
const start = turnStarts.get(key);
|
|
13441
|
+
turnStarts.delete(key);
|
|
13442
|
+
return start;
|
|
13443
|
+
}
|
|
13444
|
+
function isSample(value) {
|
|
13445
|
+
const sample = value;
|
|
13446
|
+
if (!sample || typeof sample !== "object" || Array.isArray(sample)) return false;
|
|
13447
|
+
if (typeof sample.ms !== "number" || !Number.isFinite(sample.ms) || sample.ms < 0) return false;
|
|
13448
|
+
if (typeof sample.at !== "number" || !Number.isFinite(sample.at)) return false;
|
|
13449
|
+
if (sample.chars !== void 0 && (typeof sample.chars !== "number" || !Number.isFinite(sample.chars) || sample.chars < 0)) {
|
|
13450
|
+
return false;
|
|
13451
|
+
}
|
|
13452
|
+
if (sample.effort !== void 0 && typeof sample.effort !== "string") return false;
|
|
13453
|
+
return true;
|
|
13454
|
+
}
|
|
13455
|
+
function cleanSample(sample) {
|
|
13456
|
+
return {
|
|
13457
|
+
ms: Math.round(sample.ms),
|
|
13458
|
+
...sample.chars !== void 0 ? { chars: Math.round(sample.chars) } : {},
|
|
13459
|
+
...sample.effort ? { effort: sample.effort } : {},
|
|
13460
|
+
at: sample.at
|
|
13461
|
+
};
|
|
13462
|
+
}
|
|
13463
|
+
function readEntries2(file, now) {
|
|
13464
|
+
const out = /* @__PURE__ */ new Map();
|
|
13465
|
+
try {
|
|
13466
|
+
const parsed = JSON.parse(readFileSync10(file, "utf8"));
|
|
13467
|
+
const entries = parsed && typeof parsed === "object" ? parsed.turns : null;
|
|
13468
|
+
if (!entries || typeof entries !== "object") return out;
|
|
13469
|
+
const cutoff = now - TURN_SAMPLE_MAX_AGE_MS;
|
|
13470
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
13471
|
+
if (!key || !Array.isArray(value)) continue;
|
|
13472
|
+
const samples = value.filter(isSample).filter((sample) => sample.at >= cutoff).sort((a, b) => a.at - b.at).slice(-MAX_TURN_SAMPLES).map(cleanSample);
|
|
13473
|
+
if (samples.length > 0) out.set(key, samples);
|
|
13474
|
+
}
|
|
13475
|
+
} catch {
|
|
13476
|
+
}
|
|
13477
|
+
return out;
|
|
13478
|
+
}
|
|
13479
|
+
function bounded2(history) {
|
|
13480
|
+
const newest = (samples) => samples[samples.length - 1]?.at ?? 0;
|
|
13481
|
+
return new Map([...history.entries()].sort((a, b) => newest(a[1]) - newest(b[1])).slice(-MAX_TURN_KEYS));
|
|
13482
|
+
}
|
|
13483
|
+
function recordTurnSample(key, sample) {
|
|
13484
|
+
if (!key || !isSample(sample)) return false;
|
|
13485
|
+
const file = turnHistoryStorePath();
|
|
13486
|
+
const merged = readEntries2(file, sample.at);
|
|
13487
|
+
const samples = [...merged.get(key) ?? [], cleanSample(sample)].sort((a, b) => a.at - b.at).slice(-MAX_TURN_SAMPLES);
|
|
13488
|
+
merged.set(key, samples);
|
|
13489
|
+
const kept = bounded2(merged);
|
|
13490
|
+
try {
|
|
13491
|
+
mkdirSync8(join16(file, ".."), { recursive: true, mode: 448 });
|
|
13492
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
13493
|
+
writeFileSync9(tmp, JSON.stringify({ version: 1, turns: Object.fromEntries(kept) }), { mode: 384 });
|
|
13494
|
+
renameSync6(tmp, file);
|
|
13495
|
+
} catch {
|
|
13496
|
+
return false;
|
|
13497
|
+
}
|
|
13498
|
+
return true;
|
|
13499
|
+
}
|
|
13500
|
+
|
|
13326
13501
|
// src/account-transcript.ts
|
|
13327
13502
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
13328
13503
|
import { constants as fsConstants } from "fs";
|
|
@@ -13384,13 +13559,13 @@ function dedupe2(dirs) {
|
|
|
13384
13559
|
}
|
|
13385
13560
|
|
|
13386
13561
|
// src/prompts.ts
|
|
13387
|
-
import { readFileSync as
|
|
13388
|
-
import { homedir as
|
|
13562
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync10 } from "fs";
|
|
13563
|
+
import { homedir as homedir14 } from "os";
|
|
13389
13564
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
13390
|
-
import { basename as basename2, dirname as dirname6, isAbsolute as isAbsolute3, join as
|
|
13565
|
+
import { basename as basename2, dirname as dirname6, isAbsolute as isAbsolute3, join as join17 } from "path";
|
|
13391
13566
|
function readPromptFileIfPresent(path15) {
|
|
13392
13567
|
try {
|
|
13393
|
-
const content =
|
|
13568
|
+
const content = readFileSync11(path15, "utf8").trim();
|
|
13394
13569
|
return content || void 0;
|
|
13395
13570
|
} catch {
|
|
13396
13571
|
return void 0;
|
|
@@ -13399,7 +13574,7 @@ function readPromptFileIfPresent(path15) {
|
|
|
13399
13574
|
function nearestWorkspaceAgentsPrompt(cwd) {
|
|
13400
13575
|
let dir = cwd;
|
|
13401
13576
|
while (true) {
|
|
13402
|
-
const content = readPromptFileIfPresent(
|
|
13577
|
+
const content = readPromptFileIfPresent(join17(dir, "AGENTS.md"));
|
|
13403
13578
|
if (content) return content;
|
|
13404
13579
|
const parent = dirname6(dir);
|
|
13405
13580
|
if (parent === dir) return void 0;
|
|
@@ -13510,7 +13685,7 @@ var CLAUDE_NATIVE_INSTRUCTION_FILES = /* @__PURE__ */ new Set(["CLAUDE.md", "CLA
|
|
|
13510
13685
|
function userAuthoredInstructions(forwarded, opts = {}) {
|
|
13511
13686
|
const readFile3 = opts.readFile ?? ((path15) => {
|
|
13512
13687
|
try {
|
|
13513
|
-
return
|
|
13688
|
+
return readFileSync11(path15, "utf8");
|
|
13514
13689
|
} catch {
|
|
13515
13690
|
return null;
|
|
13516
13691
|
}
|
|
@@ -13551,8 +13726,8 @@ ${options.compressionSummary.trim()}`
|
|
|
13551
13726
|
for (const s of extraSystemContent) {
|
|
13552
13727
|
if (s.trim()) parts.push(s.trim());
|
|
13553
13728
|
}
|
|
13554
|
-
const configRoot = process.env.XDG_CONFIG_HOME ??
|
|
13555
|
-
const globalAgents = readPromptFileIfPresent(
|
|
13729
|
+
const configRoot = process.env.XDG_CONFIG_HOME ?? join17(homedir14(), ".config");
|
|
13730
|
+
const globalAgents = readPromptFileIfPresent(join17(configRoot, "opencode", "AGENTS.md"));
|
|
13556
13731
|
const workspaceAgents = nearestWorkspaceAgentsPrompt(cwd);
|
|
13557
13732
|
const forwarded = extraSystemContent.join("\n\n");
|
|
13558
13733
|
const pushGlobal = !!globalAgents && !forwarded.includes(globalAgents);
|
|
@@ -13568,9 +13743,9 @@ ${options.compressionSummary.trim()}`
|
|
|
13568
13743
|
if (includeMultiStepHint) parts.push(MULTI_STEP_TASK_HINT);
|
|
13569
13744
|
const content = parts.join("\n\n");
|
|
13570
13745
|
if (!content) return void 0;
|
|
13571
|
-
const path15 =
|
|
13746
|
+
const path15 = join17(pluginTmpDir(), `opencode-cc-sys-${randomUUID7()}.md`);
|
|
13572
13747
|
try {
|
|
13573
|
-
|
|
13748
|
+
writeFileSync10(path15, content, { encoding: "utf8", mode: 384 });
|
|
13574
13749
|
return path15;
|
|
13575
13750
|
} catch (err) {
|
|
13576
13751
|
log.warn("failed to write system prompt file", { error: String(err) });
|
|
@@ -16712,6 +16887,7 @@ var ClaudeCodeLanguageModel = class {
|
|
|
16712
16887
|
const autoSwitch = accountRun?.switchTo;
|
|
16713
16888
|
if (accountRun) accountRun.switchTo = void 0;
|
|
16714
16889
|
const turnAbort = watchTurnAbort(options.abortSignal);
|
|
16890
|
+
const turnStartedAt = Date.now();
|
|
16715
16891
|
const abortedBeforeWork = (stage) => {
|
|
16716
16892
|
log.info("abort before the turn asked claude for work; nothing spawned", {
|
|
16717
16893
|
stage,
|
|
@@ -16971,8 +17147,12 @@ var ClaudeCodeLanguageModel = class {
|
|
|
16971
17147
|
recordSessionSpawn(affinity, {
|
|
16972
17148
|
model: stripAccountSuffix(failover.modelId),
|
|
16973
17149
|
effort: reasoningEffort,
|
|
16974
|
-
account: (this.config.failoverAccounts?.length ?? 0) > 1 ? failover.target ?? sourceAccount : void 0
|
|
17150
|
+
account: (this.config.failoverAccounts?.length ?? 0) > 1 ? failover.target ?? sourceAccount : void 0,
|
|
17151
|
+
agent: this.getOpencodeAgent(options)
|
|
16975
17152
|
});
|
|
17153
|
+
if (startsTurn(options.prompt)) {
|
|
17154
|
+
markTurnStart(sk, turnStartedAt, newestPromptChars(options.prompt));
|
|
17155
|
+
}
|
|
16976
17156
|
}
|
|
16977
17157
|
const hasPriorConversation = options.prompt.filter((m) => m.role === "user" || m.role === "assistant").length > 1;
|
|
16978
17158
|
if (!hasPriorConversation && !autoSwitch) {
|
|
@@ -17262,7 +17442,7 @@ var ClaudeCodeLanguageModel = class {
|
|
|
17262
17442
|
let replayReason = "no-session-for-key";
|
|
17263
17443
|
if (this.config.resumeAfterRestart !== false && includeHistoryContext && !compactionMode && !forkFromClaudeSessionId && failoverAnswer?.kind !== "switch") {
|
|
17264
17444
|
const configDir = resolveConfigDir(this.config.configDir);
|
|
17265
|
-
const transcriptPath2 = (id, dir) =>
|
|
17445
|
+
const transcriptPath2 = (id, dir) => join18(dir ?? configDir, "projects", encodeCwd(cwd), `${id}.jsonl`);
|
|
17266
17446
|
const resumePoint = findResumePoint({
|
|
17267
17447
|
sessionKey: sk,
|
|
17268
17448
|
prompt: options.prompt,
|
|
@@ -18325,6 +18505,18 @@ var ClaudeCodeLanguageModel = class {
|
|
|
18325
18505
|
state.resultFailure ??= "usage_limit";
|
|
18326
18506
|
}
|
|
18327
18507
|
if (runAutoContinue(state, msg)) return;
|
|
18508
|
+
if (!compactionMode && affinity !== "default" && msg.is_error !== true && state.resultFailure === void 0) {
|
|
18509
|
+
const start = takeTurnStart(sk);
|
|
18510
|
+
if (start) {
|
|
18511
|
+
const endedAt = Date.now();
|
|
18512
|
+
recordTurnSample(turnHistoryKey(self.getOpencodeAgent(options), stripAccountSuffix(failover.modelId)), {
|
|
18513
|
+
ms: endedAt - start.at,
|
|
18514
|
+
chars: start.chars,
|
|
18515
|
+
effort: reasoningEffort,
|
|
18516
|
+
at: endedAt
|
|
18517
|
+
});
|
|
18518
|
+
}
|
|
18519
|
+
}
|
|
18328
18520
|
for (const [idx, reasoningId] of state.reasoningIds) {
|
|
18329
18521
|
if (state.reasoningStarted.get(idx)) {
|
|
18330
18522
|
controller.enqueue({
|
|
@@ -18775,7 +18967,7 @@ var ClaudeCodeLanguageModel = class {
|
|
|
18775
18967
|
};
|
|
18776
18968
|
|
|
18777
18969
|
// src/account-tier.ts
|
|
18778
|
-
import { readFileSync as
|
|
18970
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
18779
18971
|
import path14 from "path";
|
|
18780
18972
|
var ORGANIZATION_TYPE_LABELS = {
|
|
18781
18973
|
claude_max: "Max",
|
|
@@ -18818,7 +19010,7 @@ function readTierFromConfigDir(configDir, allowLegacyFallback) {
|
|
|
18818
19010
|
function readOauthAccount(file) {
|
|
18819
19011
|
let raw;
|
|
18820
19012
|
try {
|
|
18821
|
-
raw =
|
|
19013
|
+
raw = readFileSync12(file, "utf8");
|
|
18822
19014
|
} catch {
|
|
18823
19015
|
return void 0;
|
|
18824
19016
|
}
|
|
@@ -18842,18 +19034,27 @@ function tierLabel(oauthAccount) {
|
|
|
18842
19034
|
const multiple = typeof rateLimitTier === "string" ? RATE_LIMIT_TIER_LABELS[rateLimitTier] : void 0;
|
|
18843
19035
|
return multiple ? `${base} ${multiple}` : base;
|
|
18844
19036
|
}
|
|
19037
|
+
function registerSidebarAccounts(accounts) {
|
|
19038
|
+
const list2 = accounts && accounts.length > 0 ? accounts : [DEFAULT_ACCOUNT];
|
|
19039
|
+
registerKnownAccounts(
|
|
19040
|
+
list2.map((account) => ({
|
|
19041
|
+
account: normalizeAccountName(account) || DEFAULT_ACCOUNT,
|
|
19042
|
+
tier: readAccountTier(account)
|
|
19043
|
+
}))
|
|
19044
|
+
);
|
|
19045
|
+
}
|
|
18845
19046
|
|
|
18846
19047
|
// src/cleanup-stale.ts
|
|
18847
19048
|
import {
|
|
18848
19049
|
existsSync as existsSync5,
|
|
18849
|
-
mkdirSync as
|
|
18850
|
-
readFileSync as
|
|
19050
|
+
mkdirSync as mkdirSync9,
|
|
19051
|
+
readFileSync as readFileSync13,
|
|
18851
19052
|
realpathSync as realpathSync4,
|
|
18852
19053
|
rmSync as rmSync3,
|
|
18853
|
-
writeFileSync as
|
|
19054
|
+
writeFileSync as writeFileSync11
|
|
18854
19055
|
} from "fs";
|
|
18855
|
-
import { homedir as
|
|
18856
|
-
import { dirname as dirname7, join as
|
|
19056
|
+
import { homedir as homedir15 } from "os";
|
|
19057
|
+
import { dirname as dirname7, join as join19, resolve as resolve6 } from "path";
|
|
18857
19058
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
18858
19059
|
var STALE_PACKAGE_NAME = "opencode-claude-code-plugin";
|
|
18859
19060
|
var SUSPECT_DESCRIPTION_TOKEN = "Claude Code";
|
|
@@ -18861,20 +19062,20 @@ var alreadyRan = false;
|
|
|
18861
19062
|
function candidateCacheRoots() {
|
|
18862
19063
|
const xdg = process.env.XDG_CACHE_HOME;
|
|
18863
19064
|
return [
|
|
18864
|
-
xdg ?
|
|
18865
|
-
|
|
18866
|
-
|
|
19065
|
+
xdg ? join19(xdg, "opencode") : null,
|
|
19066
|
+
join19(homedir15(), ".cache", "opencode"),
|
|
19067
|
+
join19(homedir15(), "Library", "Caches", "opencode")
|
|
18867
19068
|
].filter((p) => Boolean(p));
|
|
18868
19069
|
}
|
|
18869
19070
|
function userOpencodeJsonPath() {
|
|
18870
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME ??
|
|
18871
|
-
return
|
|
19071
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME ?? join19(homedir15(), ".config");
|
|
19072
|
+
return join19(xdgConfig, "opencode", "opencode.json");
|
|
18872
19073
|
}
|
|
18873
19074
|
function userIntendsToUseUnscoped() {
|
|
18874
19075
|
const cfg = userOpencodeJsonPath();
|
|
18875
19076
|
if (!existsSync5(cfg)) return false;
|
|
18876
19077
|
try {
|
|
18877
|
-
const json = JSON.parse(
|
|
19078
|
+
const json = JSON.parse(readFileSync13(cfg, "utf8"));
|
|
18878
19079
|
const plugins = json.plugin;
|
|
18879
19080
|
if (!Array.isArray(plugins)) return false;
|
|
18880
19081
|
return plugins.some(
|
|
@@ -18895,19 +19096,19 @@ function ourLoadedDir() {
|
|
|
18895
19096
|
function ourVersion(dir) {
|
|
18896
19097
|
if (!dir) return null;
|
|
18897
19098
|
try {
|
|
18898
|
-
const pkg = JSON.parse(
|
|
19099
|
+
const pkg = JSON.parse(readFileSync13(join19(dir, "package.json"), "utf8"));
|
|
18899
19100
|
return typeof pkg.version === "string" && pkg.version ? pkg.version : null;
|
|
18900
19101
|
} catch {
|
|
18901
19102
|
return null;
|
|
18902
19103
|
}
|
|
18903
19104
|
}
|
|
18904
19105
|
function markerPath() {
|
|
18905
|
-
const stateRoot = process.env.XDG_STATE_HOME ??
|
|
18906
|
-
return
|
|
19106
|
+
const stateRoot = process.env.XDG_STATE_HOME ?? join19(homedir15(), ".local", "state");
|
|
19107
|
+
return join19(stateRoot, "opencode-claude-code-plugin", "cleanup-stale.json");
|
|
18907
19108
|
}
|
|
18908
19109
|
function markerVersion() {
|
|
18909
19110
|
try {
|
|
18910
|
-
const marker = JSON.parse(
|
|
19111
|
+
const marker = JSON.parse(readFileSync13(markerPath(), "utf8"));
|
|
18911
19112
|
return typeof marker.version === "string" ? marker.version : null;
|
|
18912
19113
|
} catch {
|
|
18913
19114
|
return null;
|
|
@@ -18916,8 +19117,8 @@ function markerVersion() {
|
|
|
18916
19117
|
function writeMarker(version) {
|
|
18917
19118
|
const file = markerPath();
|
|
18918
19119
|
try {
|
|
18919
|
-
|
|
18920
|
-
|
|
19120
|
+
mkdirSync9(dirname7(file), { recursive: true, mode: 448 });
|
|
19121
|
+
writeFileSync11(
|
|
18921
19122
|
file,
|
|
18922
19123
|
JSON.stringify({ version, at: (/* @__PURE__ */ new Date()).toISOString() }, null, 2) + "\n",
|
|
18923
19124
|
"utf8"
|
|
@@ -18952,7 +19153,7 @@ function cleanupStaleUnscopedInstall() {
|
|
|
18952
19153
|
}
|
|
18953
19154
|
function cleanupOne(cacheRoot, ourDir) {
|
|
18954
19155
|
if (!existsSync5(cacheRoot)) return;
|
|
18955
|
-
const stalePath =
|
|
19156
|
+
const stalePath = join19(cacheRoot, "node_modules", STALE_PACKAGE_NAME);
|
|
18956
19157
|
if (!existsSync5(stalePath)) return;
|
|
18957
19158
|
let realStalePath = stalePath;
|
|
18958
19159
|
try {
|
|
@@ -18960,11 +19161,11 @@ function cleanupOne(cacheRoot, ourDir) {
|
|
|
18960
19161
|
} catch {
|
|
18961
19162
|
}
|
|
18962
19163
|
if (ourDir && realStalePath === ourDir) return;
|
|
18963
|
-
const pkgJsonPath =
|
|
19164
|
+
const pkgJsonPath = join19(stalePath, "package.json");
|
|
18964
19165
|
if (!existsSync5(pkgJsonPath)) return;
|
|
18965
19166
|
let pkg = {};
|
|
18966
19167
|
try {
|
|
18967
|
-
pkg = JSON.parse(
|
|
19168
|
+
pkg = JSON.parse(readFileSync13(pkgJsonPath, "utf8"));
|
|
18968
19169
|
} catch {
|
|
18969
19170
|
return;
|
|
18970
19171
|
}
|
|
@@ -18980,13 +19181,13 @@ function cleanupOne(cacheRoot, ourDir) {
|
|
|
18980
19181
|
});
|
|
18981
19182
|
return;
|
|
18982
19183
|
}
|
|
18983
|
-
const cachePkgJson =
|
|
19184
|
+
const cachePkgJson = join19(cacheRoot, "package.json");
|
|
18984
19185
|
if (!existsSync5(cachePkgJson)) return;
|
|
18985
19186
|
try {
|
|
18986
|
-
const cfg = JSON.parse(
|
|
19187
|
+
const cfg = JSON.parse(readFileSync13(cachePkgJson, "utf8"));
|
|
18987
19188
|
if (cfg?.dependencies?.[STALE_PACKAGE_NAME]) {
|
|
18988
19189
|
delete cfg.dependencies[STALE_PACKAGE_NAME];
|
|
18989
|
-
|
|
19190
|
+
writeFileSync11(cachePkgJson, JSON.stringify(cfg, null, 2) + "\n");
|
|
18990
19191
|
log.info("cleanup-stale: pruned dep from cache package.json");
|
|
18991
19192
|
}
|
|
18992
19193
|
} catch (err) {
|
|
@@ -19413,6 +19614,7 @@ function createV2Setup(deps) {
|
|
|
19413
19614
|
)
|
|
19414
19615
|
};
|
|
19415
19616
|
const plans = planV2Providers(seedSettings, deps.defaultProxyTools);
|
|
19617
|
+
registerSidebarAccounts(resolveAccounts(seedSettings.accounts));
|
|
19416
19618
|
planned.clear();
|
|
19417
19619
|
for (const plan of plans) {
|
|
19418
19620
|
planned.set(plan.info.id, plan.info.settings ?? {});
|
|
@@ -19954,6 +20156,7 @@ var server = async (input) => {
|
|
|
19954
20156
|
registerBundledSkillPath(config);
|
|
19955
20157
|
config.provider ??= {};
|
|
19956
20158
|
await buildAgentRegistry(config);
|
|
20159
|
+
registerSidebarAccounts(resolveAccounts(config.provider[PROVIDER_ID2]?.options?.accounts));
|
|
19957
20160
|
const expanded = await expandAccountProviders(config);
|
|
19958
20161
|
if (expanded) {
|
|
19959
20162
|
logStartupDiagnostics(
|