opencode-gbk-tools 0.1.31 → 1.1.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/README.md +1 -0
- package/dist/opencode-tools/gbk_edit.js +23 -1
- package/dist/opencode-tools/gbk_read.js +14 -0
- package/dist/opencode-tools/text_edit.js +9 -1
- package/dist/plugin/index.js +118 -186
- package/dist/plugins/opencode-gbk-tools.js +118 -186
- package/dist/release-manifest.json +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -210,6 +210,7 @@ A:不要。现在优先用 `mode="insertAfter"` 或 `mode="insertBefore"`,
|
|
|
210
210
|
|
|
211
211
|
| 版本 | 说明 |
|
|
212
212
|
|------|------|
|
|
213
|
+
| 1.1.0 | 首个 `1.x` 稳定版本:保留 GBK/GB18030 路由、记忆与新建 `.txt` 走 `gbk_write` 的规则,同时修复插件层同步自动 summarize 可能导致的会话卡住问题;改为只依赖 OpenCode 原生自动压缩,并为会话状态与 `gbk-file` 行索引缓存增加边界控制,降低长会话和多文件场景下的阻塞与内存累积风险 |
|
|
213
214
|
| 0.1.31 | 在 `0.1.30` 基础上继续收紧新建文件路由:新建 `.txt` 文件必须优先直接使用 `gbk_write`,不再先走 `text_write` 或内置 `write/edit`;并新增“当前会话一旦成功使用过 `gbk_*`,后续新建文件继续优先走 `gbk_*`”的插件级约束与测试覆盖 |
|
|
214
215
|
| 0.1.30 | 补强 `text_*` 针对真实 GBK 样本与大体积重复样本的高强度测试:新增 `QFunction-0.txt` 真实样本读取、编辑、追加与端到端工作流覆盖,并补充大文件重复样本下的 `text_read` / `text_edit` 行为验证;同时继续收紧路由规则:新建 `.txt` 文件直接要求改用 `gbk_write`,且当前会话一旦使用过 `gbk_*`,后续新建文件也继续要求走 `gbk_*` |
|
|
215
216
|
| 0.1.29 | 在方案 B 基础上新增 GBK 文件持久记忆:普通 agent 继续按编码分流,UTF-8 优先使用 OpenCode 内置工具;对现有文件,已确认或首次检测到是 GBK/GB18030 的路径会按完整路径 + mtime/size 持久记忆;后续再次操作同一路径时,`text_*` 与内置 `read` / `write` / `edit` 都会被直接拦截并提示改用 `gbk_*`,避免先误走 `text_edit` / `edit` 再失败;`gbk-engine` 继续保持为强制 GBK 专属模式 |
|
|
@@ -16243,10 +16243,18 @@ var FALLBACK_MAX_OUTPUT_CHARS = 8e3;
|
|
|
16243
16243
|
var MIN_BASE_MAX_OUTPUT_CHARS = 4e3;
|
|
16244
16244
|
var MAX_BASE_OUTPUT_CHARS = 32e3;
|
|
16245
16245
|
var MIN_PRESSURED_OUTPUT_CHARS = 1500;
|
|
16246
|
+
var SESSION_STATE_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
16246
16247
|
var sessionStates = /* @__PURE__ */ new Map();
|
|
16248
|
+
function touchSessionState(state, touchedAt = Date.now()) {
|
|
16249
|
+
state.lastTouchedAt = touchedAt;
|
|
16250
|
+
}
|
|
16247
16251
|
function getSessionState(sessionID) {
|
|
16248
16252
|
if (!sessionID) return null;
|
|
16249
|
-
|
|
16253
|
+
const state = sessionStates.get(sessionID) ?? null;
|
|
16254
|
+
if (state) {
|
|
16255
|
+
touchSessionState(state);
|
|
16256
|
+
}
|
|
16257
|
+
return state;
|
|
16250
16258
|
}
|
|
16251
16259
|
function getCompactionPressureFactor(compactionCount) {
|
|
16252
16260
|
if (compactionCount >= 3) return 0.35;
|
|
@@ -16348,6 +16356,7 @@ async function assertPathAllowed(filePath, context, allowExternal = false) {
|
|
|
16348
16356
|
// src/lib/gbk-file.ts
|
|
16349
16357
|
var STREAMING_FILE_SIZE_THRESHOLD_BYTES = 1024 * 1024;
|
|
16350
16358
|
var STREAM_READ_CHUNK_SIZE_BYTES = 1024 * 1024;
|
|
16359
|
+
var MAX_GBK_LINE_INDEX_CACHE_ENTRIES = 32;
|
|
16351
16360
|
var gbkLineIndexCache = /* @__PURE__ */ new Map();
|
|
16352
16361
|
var ANSI_RED = "\x1B[31m";
|
|
16353
16362
|
var ANSI_GREEN = "\x1B[32m";
|
|
@@ -16390,6 +16399,16 @@ function toSafeNumber(value) {
|
|
|
16390
16399
|
function invalidateGbkLineIndex(filePath) {
|
|
16391
16400
|
gbkLineIndexCache.delete(filePath);
|
|
16392
16401
|
}
|
|
16402
|
+
function pruneGbkLineIndexCache() {
|
|
16403
|
+
if (gbkLineIndexCache.size <= MAX_GBK_LINE_INDEX_CACHE_ENTRIES) {
|
|
16404
|
+
return;
|
|
16405
|
+
}
|
|
16406
|
+
const overflow = gbkLineIndexCache.size - MAX_GBK_LINE_INDEX_CACHE_ENTRIES;
|
|
16407
|
+
const oldestKeys = [...gbkLineIndexCache.keys()].slice(0, overflow);
|
|
16408
|
+
for (const key of oldestKeys) {
|
|
16409
|
+
gbkLineIndexCache.delete(key);
|
|
16410
|
+
}
|
|
16411
|
+
}
|
|
16393
16412
|
function assertStringArgument(value, name) {
|
|
16394
16413
|
if (typeof value !== "string") {
|
|
16395
16414
|
throw createGbkError("GBK_INVALID_ARGUMENT", `${name} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);
|
|
@@ -16863,6 +16882,8 @@ async function visitDecodedTextChunks(input, visitor) {
|
|
|
16863
16882
|
async function getGbkLineIndex(input) {
|
|
16864
16883
|
const cached2 = gbkLineIndexCache.get(input.filePath);
|
|
16865
16884
|
if (cached2 && cached2.fileSize === toSafeNumber(input.stat.size) && cached2.mtimeMs === toSafeNumber(input.stat.mtimeMs)) {
|
|
16885
|
+
gbkLineIndexCache.delete(input.filePath);
|
|
16886
|
+
gbkLineIndexCache.set(input.filePath, cached2);
|
|
16866
16887
|
return cached2;
|
|
16867
16888
|
}
|
|
16868
16889
|
const lineStartOffsets = [0];
|
|
@@ -16908,6 +16929,7 @@ async function getGbkLineIndex(input) {
|
|
|
16908
16929
|
newlineStyle: finalizeNewlineStyle(crlfCount, lfCount)
|
|
16909
16930
|
};
|
|
16910
16931
|
gbkLineIndexCache.set(input.filePath, result);
|
|
16932
|
+
pruneGbkLineIndexCache();
|
|
16911
16933
|
return result;
|
|
16912
16934
|
}
|
|
16913
16935
|
async function readDecodedGbkByteRange(input, start, endExclusive) {
|
|
@@ -16306,10 +16306,21 @@ async function assertPathAllowed(filePath, context, allowExternal = false) {
|
|
|
16306
16306
|
// src/lib/gbk-file.ts
|
|
16307
16307
|
var STREAMING_FILE_SIZE_THRESHOLD_BYTES = 1024 * 1024;
|
|
16308
16308
|
var STREAM_READ_CHUNK_SIZE_BYTES = 1024 * 1024;
|
|
16309
|
+
var MAX_GBK_LINE_INDEX_CACHE_ENTRIES = 32;
|
|
16309
16310
|
var gbkLineIndexCache = /* @__PURE__ */ new Map();
|
|
16310
16311
|
function toSafeNumber(value) {
|
|
16311
16312
|
return typeof value === "bigint" ? Number(value) : value;
|
|
16312
16313
|
}
|
|
16314
|
+
function pruneGbkLineIndexCache() {
|
|
16315
|
+
if (gbkLineIndexCache.size <= MAX_GBK_LINE_INDEX_CACHE_ENTRIES) {
|
|
16316
|
+
return;
|
|
16317
|
+
}
|
|
16318
|
+
const overflow = gbkLineIndexCache.size - MAX_GBK_LINE_INDEX_CACHE_ENTRIES;
|
|
16319
|
+
const oldestKeys = [...gbkLineIndexCache.keys()].slice(0, overflow);
|
|
16320
|
+
for (const key of oldestKeys) {
|
|
16321
|
+
gbkLineIndexCache.delete(key);
|
|
16322
|
+
}
|
|
16323
|
+
}
|
|
16313
16324
|
function assertEncodingSupported(encoding) {
|
|
16314
16325
|
if (encoding !== "gbk" && encoding !== "gb18030") {
|
|
16315
16326
|
throw createGbkError("GBK_INVALID_ENCODING", `\u4E0D\u652F\u6301\u7684\u7F16\u7801: ${encoding}`);
|
|
@@ -16451,6 +16462,8 @@ async function readWholeGbkTextFile(input) {
|
|
|
16451
16462
|
async function getGbkLineIndex(input) {
|
|
16452
16463
|
const cached2 = gbkLineIndexCache.get(input.filePath);
|
|
16453
16464
|
if (cached2 && cached2.fileSize === toSafeNumber(input.stat.size) && cached2.mtimeMs === toSafeNumber(input.stat.mtimeMs)) {
|
|
16465
|
+
gbkLineIndexCache.delete(input.filePath);
|
|
16466
|
+
gbkLineIndexCache.set(input.filePath, cached2);
|
|
16454
16467
|
return cached2;
|
|
16455
16468
|
}
|
|
16456
16469
|
const lineStartOffsets = [0];
|
|
@@ -16496,6 +16509,7 @@ async function getGbkLineIndex(input) {
|
|
|
16496
16509
|
newlineStyle: finalizeNewlineStyle(crlfCount, lfCount)
|
|
16497
16510
|
};
|
|
16498
16511
|
gbkLineIndexCache.set(input.filePath, result);
|
|
16512
|
+
pruneGbkLineIndexCache();
|
|
16499
16513
|
return result;
|
|
16500
16514
|
}
|
|
16501
16515
|
async function readDecodedGbkByteRange(input, start, endExclusive) {
|
|
@@ -16243,10 +16243,18 @@ var FALLBACK_MAX_OUTPUT_CHARS = 8e3;
|
|
|
16243
16243
|
var MIN_BASE_MAX_OUTPUT_CHARS = 4e3;
|
|
16244
16244
|
var MAX_BASE_OUTPUT_CHARS = 32e3;
|
|
16245
16245
|
var MIN_PRESSURED_OUTPUT_CHARS = 1500;
|
|
16246
|
+
var SESSION_STATE_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
16246
16247
|
var sessionStates = /* @__PURE__ */ new Map();
|
|
16248
|
+
function touchSessionState(state, touchedAt = Date.now()) {
|
|
16249
|
+
state.lastTouchedAt = touchedAt;
|
|
16250
|
+
}
|
|
16247
16251
|
function getSessionState(sessionID) {
|
|
16248
16252
|
if (!sessionID) return null;
|
|
16249
|
-
|
|
16253
|
+
const state = sessionStates.get(sessionID) ?? null;
|
|
16254
|
+
if (state) {
|
|
16255
|
+
touchSessionState(state);
|
|
16256
|
+
}
|
|
16257
|
+
return state;
|
|
16250
16258
|
}
|
|
16251
16259
|
function getCompactionPressureFactor(compactionCount) {
|
|
16252
16260
|
if (compactionCount >= 3) return 0.35;
|
package/dist/plugin/index.js
CHANGED
|
@@ -3817,102 +3817,9 @@ var require_lib = __commonJS({
|
|
|
3817
3817
|
});
|
|
3818
3818
|
|
|
3819
3819
|
// src/plugin/index.ts
|
|
3820
|
+
import fs5 from "fs/promises";
|
|
3820
3821
|
import path5 from "path";
|
|
3821
3822
|
|
|
3822
|
-
// src/lib/session-pressure.ts
|
|
3823
|
-
var AUTO_SUMMARIZE_PRESSURE_RATIO = 0.85;
|
|
3824
|
-
var AUTO_SUMMARIZE_COOLDOWN_MS = 6e4;
|
|
3825
|
-
var PRESSURE_CHECK_INTERVAL_MS = 15e3;
|
|
3826
|
-
var SESSION_PRESSURE_MESSAGE_LIMIT = 200;
|
|
3827
|
-
function estimateUnknownChars(value) {
|
|
3828
|
-
if (typeof value === "string") return value.length;
|
|
3829
|
-
if (typeof value === "number" || typeof value === "boolean") return String(value).length;
|
|
3830
|
-
if (Array.isArray(value)) {
|
|
3831
|
-
return value.reduce((total, item) => total + estimateUnknownChars(item), 0);
|
|
3832
|
-
}
|
|
3833
|
-
if (!value || typeof value !== "object") return 0;
|
|
3834
|
-
try {
|
|
3835
|
-
return JSON.stringify(value).length;
|
|
3836
|
-
} catch {
|
|
3837
|
-
return 0;
|
|
3838
|
-
}
|
|
3839
|
-
}
|
|
3840
|
-
function estimateDiffChars(summary) {
|
|
3841
|
-
let chars = (summary.title?.length ?? 0) + (summary.body?.length ?? 0);
|
|
3842
|
-
for (const diff of summary.diffs ?? []) {
|
|
3843
|
-
chars += diff.file.length + diff.before.length + diff.after.length;
|
|
3844
|
-
}
|
|
3845
|
-
return chars;
|
|
3846
|
-
}
|
|
3847
|
-
function estimateToolPartChars(part) {
|
|
3848
|
-
let chars = part.tool.length + estimateUnknownChars(part.metadata);
|
|
3849
|
-
switch (part.state.status) {
|
|
3850
|
-
case "pending":
|
|
3851
|
-
chars += estimateUnknownChars(part.state.input) + part.state.raw.length;
|
|
3852
|
-
break;
|
|
3853
|
-
case "running":
|
|
3854
|
-
chars += estimateUnknownChars(part.state.input);
|
|
3855
|
-
chars += part.state.title?.length ?? 0;
|
|
3856
|
-
chars += estimateUnknownChars(part.state.metadata);
|
|
3857
|
-
break;
|
|
3858
|
-
case "completed":
|
|
3859
|
-
chars += estimateUnknownChars(part.state.input);
|
|
3860
|
-
chars += part.state.output.length + part.state.title.length;
|
|
3861
|
-
chars += estimateUnknownChars(part.state.metadata);
|
|
3862
|
-
break;
|
|
3863
|
-
case "error":
|
|
3864
|
-
chars += estimateUnknownChars(part.state.input);
|
|
3865
|
-
chars += part.state.error.length + estimateUnknownChars(part.state.metadata);
|
|
3866
|
-
break;
|
|
3867
|
-
}
|
|
3868
|
-
return chars;
|
|
3869
|
-
}
|
|
3870
|
-
function estimatePartChars(part) {
|
|
3871
|
-
switch (part.type) {
|
|
3872
|
-
case "text":
|
|
3873
|
-
return part.text.length;
|
|
3874
|
-
case "reasoning":
|
|
3875
|
-
return Math.round(part.text.length * 0.25);
|
|
3876
|
-
case "file":
|
|
3877
|
-
return (part.filename?.length ?? 0) + (part.source?.text.value.length ?? 0);
|
|
3878
|
-
case "tool":
|
|
3879
|
-
return estimateToolPartChars(part);
|
|
3880
|
-
case "step-start":
|
|
3881
|
-
return part.snapshot?.length ?? 0;
|
|
3882
|
-
case "step-finish":
|
|
3883
|
-
return part.reason.length + (part.snapshot?.length ?? 0);
|
|
3884
|
-
case "snapshot":
|
|
3885
|
-
return part.snapshot.length;
|
|
3886
|
-
case "patch":
|
|
3887
|
-
return part.hash.length + part.files.join("\n").length;
|
|
3888
|
-
case "agent":
|
|
3889
|
-
return part.name.length + (part.source?.value.length ?? 0);
|
|
3890
|
-
case "retry":
|
|
3891
|
-
return estimateUnknownChars(part.error);
|
|
3892
|
-
case "compaction":
|
|
3893
|
-
return 32;
|
|
3894
|
-
case "subtask":
|
|
3895
|
-
return part.prompt.length + part.description.length + part.agent.length;
|
|
3896
|
-
}
|
|
3897
|
-
}
|
|
3898
|
-
function estimateMessageChars(message, parts) {
|
|
3899
|
-
let chars = 0;
|
|
3900
|
-
if (message.role === "user") {
|
|
3901
|
-
chars += message.system?.length ?? 0;
|
|
3902
|
-
if (message.summary) {
|
|
3903
|
-
chars += estimateDiffChars(message.summary);
|
|
3904
|
-
}
|
|
3905
|
-
}
|
|
3906
|
-
for (const part of parts) {
|
|
3907
|
-
chars += estimatePartChars(part);
|
|
3908
|
-
}
|
|
3909
|
-
return chars;
|
|
3910
|
-
}
|
|
3911
|
-
function estimateSessionTokens(messages) {
|
|
3912
|
-
const totalChars = messages.reduce((total, message) => total + estimateMessageChars(message.info, message.parts), 0);
|
|
3913
|
-
return Math.ceil(totalChars / 4);
|
|
3914
|
-
}
|
|
3915
|
-
|
|
3916
3823
|
// src/lib/encoding-memory.ts
|
|
3917
3824
|
import fs from "fs/promises";
|
|
3918
3825
|
import os from "os";
|
|
@@ -16534,8 +16441,32 @@ var FALLBACK_MAX_OUTPUT_CHARS = 8e3;
|
|
|
16534
16441
|
var MIN_BASE_MAX_OUTPUT_CHARS = 4e3;
|
|
16535
16442
|
var MAX_BASE_OUTPUT_CHARS = 32e3;
|
|
16536
16443
|
var MIN_PRESSURED_OUTPUT_CHARS = 1500;
|
|
16444
|
+
var SESSION_STATE_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
16445
|
+
var MAX_SESSION_STATES = 200;
|
|
16537
16446
|
var sessionStates = /* @__PURE__ */ new Map();
|
|
16447
|
+
function pruneSessionStates(now = Date.now()) {
|
|
16448
|
+
for (const [sessionID, state] of sessionStates) {
|
|
16449
|
+
if (now - state.lastTouchedAt > SESSION_STATE_TTL_MS) {
|
|
16450
|
+
sessionStates.delete(sessionID);
|
|
16451
|
+
}
|
|
16452
|
+
}
|
|
16453
|
+
if (sessionStates.size <= MAX_SESSION_STATES) {
|
|
16454
|
+
return;
|
|
16455
|
+
}
|
|
16456
|
+
const oldestEntries = [...sessionStates.entries()].sort((left, right) => left[1].lastTouchedAt - right[1].lastTouchedAt);
|
|
16457
|
+
for (const [sessionID] of oldestEntries) {
|
|
16458
|
+
if (sessionStates.size <= MAX_SESSION_STATES) {
|
|
16459
|
+
break;
|
|
16460
|
+
}
|
|
16461
|
+
sessionStates.delete(sessionID);
|
|
16462
|
+
}
|
|
16463
|
+
}
|
|
16464
|
+
function touchSessionState(state, touchedAt = Date.now()) {
|
|
16465
|
+
state.lastTouchedAt = touchedAt;
|
|
16466
|
+
}
|
|
16538
16467
|
function getOrCreateSessionState(sessionID) {
|
|
16468
|
+
const now = Date.now();
|
|
16469
|
+
pruneSessionStates(now);
|
|
16539
16470
|
let state = sessionStates.get(sessionID);
|
|
16540
16471
|
if (!state) {
|
|
16541
16472
|
state = {
|
|
@@ -16546,15 +16477,22 @@ function getOrCreateSessionState(sessionID) {
|
|
|
16546
16477
|
lastPressureCheckedAt: null,
|
|
16547
16478
|
autoSummarizeInFlight: false,
|
|
16548
16479
|
lastAutoSummarizeAt: null,
|
|
16549
|
-
autoSummarizeCount: 0
|
|
16480
|
+
autoSummarizeCount: 0,
|
|
16481
|
+
lastTouchedAt: now
|
|
16550
16482
|
};
|
|
16551
16483
|
sessionStates.set(sessionID, state);
|
|
16484
|
+
return state;
|
|
16552
16485
|
}
|
|
16486
|
+
touchSessionState(state, now);
|
|
16553
16487
|
return state;
|
|
16554
16488
|
}
|
|
16555
16489
|
function getSessionState(sessionID) {
|
|
16556
16490
|
if (!sessionID) return null;
|
|
16557
|
-
|
|
16491
|
+
const state = sessionStates.get(sessionID) ?? null;
|
|
16492
|
+
if (state) {
|
|
16493
|
+
touchSessionState(state);
|
|
16494
|
+
}
|
|
16495
|
+
return state;
|
|
16558
16496
|
}
|
|
16559
16497
|
function getCompactionPressureFactor(compactionCount) {
|
|
16560
16498
|
if (compactionCount >= 3) return 0.35;
|
|
@@ -16590,20 +16528,6 @@ function markSessionCompacted(sessionID) {
|
|
|
16590
16528
|
function getSessionCompactionCount(sessionID) {
|
|
16591
16529
|
return getSessionState(sessionID)?.compactionCount ?? 0;
|
|
16592
16530
|
}
|
|
16593
|
-
function updateSessionPressure(sessionID, estimatedTokens, pressureRatio, checkedAt = Date.now()) {
|
|
16594
|
-
if (!sessionID) return;
|
|
16595
|
-
const state = getOrCreateSessionState(sessionID);
|
|
16596
|
-
state.estimatedTokens = estimatedTokens;
|
|
16597
|
-
state.pressureRatio = pressureRatio;
|
|
16598
|
-
state.lastPressureCheckedAt = checkedAt;
|
|
16599
|
-
}
|
|
16600
|
-
function clearSessionPressure(sessionID) {
|
|
16601
|
-
if (!sessionID) return;
|
|
16602
|
-
const state = getOrCreateSessionState(sessionID);
|
|
16603
|
-
state.estimatedTokens = null;
|
|
16604
|
-
state.pressureRatio = null;
|
|
16605
|
-
state.lastPressureCheckedAt = null;
|
|
16606
|
-
}
|
|
16607
16531
|
function getSessionPressure(sessionID) {
|
|
16608
16532
|
const state = getSessionState(sessionID);
|
|
16609
16533
|
if (!state || state.estimatedTokens === null || state.pressureRatio === null || state.lastPressureCheckedAt === null) {
|
|
@@ -16615,32 +16539,6 @@ function getSessionPressure(sessionID) {
|
|
|
16615
16539
|
checkedAt: state.lastPressureCheckedAt
|
|
16616
16540
|
};
|
|
16617
16541
|
}
|
|
16618
|
-
function isAutoSummarizeInFlight(sessionID) {
|
|
16619
|
-
return getSessionState(sessionID)?.autoSummarizeInFlight ?? false;
|
|
16620
|
-
}
|
|
16621
|
-
function markAutoSummarizeStarted(sessionID) {
|
|
16622
|
-
if (!sessionID) return;
|
|
16623
|
-
const state = getOrCreateSessionState(sessionID);
|
|
16624
|
-
state.autoSummarizeInFlight = true;
|
|
16625
|
-
}
|
|
16626
|
-
function markAutoSummarizeFinished(sessionID, summarized, finishedAt = Date.now()) {
|
|
16627
|
-
if (!sessionID) return;
|
|
16628
|
-
const state = getOrCreateSessionState(sessionID);
|
|
16629
|
-
state.autoSummarizeInFlight = false;
|
|
16630
|
-
if (summarized) {
|
|
16631
|
-
state.lastAutoSummarizeAt = finishedAt;
|
|
16632
|
-
state.autoSummarizeCount += 1;
|
|
16633
|
-
state.estimatedTokens = null;
|
|
16634
|
-
state.pressureRatio = null;
|
|
16635
|
-
state.lastPressureCheckedAt = null;
|
|
16636
|
-
}
|
|
16637
|
-
}
|
|
16638
|
-
function getLastAutoSummarizeAt(sessionID) {
|
|
16639
|
-
return getSessionState(sessionID)?.lastAutoSummarizeAt ?? null;
|
|
16640
|
-
}
|
|
16641
|
-
function getAutoSummarizeCount(sessionID) {
|
|
16642
|
-
return getSessionState(sessionID)?.autoSummarizeCount ?? 0;
|
|
16643
|
-
}
|
|
16644
16542
|
function getMaxOutputChars(sessionID, fallback = FALLBACK_MAX_OUTPUT_CHARS) {
|
|
16645
16543
|
const state = getSessionState(sessionID);
|
|
16646
16544
|
const base = getBaseMaxOutputChars(state?.contextTokens ?? null, fallback);
|
|
@@ -16663,6 +16561,7 @@ import fs3 from "fs/promises";
|
|
|
16663
16561
|
import path3 from "path";
|
|
16664
16562
|
var STREAMING_FILE_SIZE_THRESHOLD_BYTES = 1024 * 1024;
|
|
16665
16563
|
var STREAM_READ_CHUNK_SIZE_BYTES = 1024 * 1024;
|
|
16564
|
+
var MAX_GBK_LINE_INDEX_CACHE_ENTRIES = 32;
|
|
16666
16565
|
var gbkLineIndexCache = /* @__PURE__ */ new Map();
|
|
16667
16566
|
var ANSI_RED = "\x1B[31m";
|
|
16668
16567
|
var ANSI_GREEN = "\x1B[32m";
|
|
@@ -16705,6 +16604,16 @@ function toSafeNumber(value) {
|
|
|
16705
16604
|
function invalidateGbkLineIndex(filePath) {
|
|
16706
16605
|
gbkLineIndexCache.delete(filePath);
|
|
16707
16606
|
}
|
|
16607
|
+
function pruneGbkLineIndexCache() {
|
|
16608
|
+
if (gbkLineIndexCache.size <= MAX_GBK_LINE_INDEX_CACHE_ENTRIES) {
|
|
16609
|
+
return;
|
|
16610
|
+
}
|
|
16611
|
+
const overflow = gbkLineIndexCache.size - MAX_GBK_LINE_INDEX_CACHE_ENTRIES;
|
|
16612
|
+
const oldestKeys = [...gbkLineIndexCache.keys()].slice(0, overflow);
|
|
16613
|
+
for (const key of oldestKeys) {
|
|
16614
|
+
gbkLineIndexCache.delete(key);
|
|
16615
|
+
}
|
|
16616
|
+
}
|
|
16708
16617
|
function assertStringArgument(value, name) {
|
|
16709
16618
|
if (typeof value !== "string") {
|
|
16710
16619
|
throw createGbkError("GBK_INVALID_ARGUMENT", `${name} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);
|
|
@@ -17227,6 +17136,8 @@ async function visitDecodedTextChunks(input, visitor) {
|
|
|
17227
17136
|
async function getGbkLineIndex(input) {
|
|
17228
17137
|
const cached2 = gbkLineIndexCache.get(input.filePath);
|
|
17229
17138
|
if (cached2 && cached2.fileSize === toSafeNumber(input.stat.size) && cached2.mtimeMs === toSafeNumber(input.stat.mtimeMs)) {
|
|
17139
|
+
gbkLineIndexCache.delete(input.filePath);
|
|
17140
|
+
gbkLineIndexCache.set(input.filePath, cached2);
|
|
17230
17141
|
return cached2;
|
|
17231
17142
|
}
|
|
17232
17143
|
const lineStartOffsets = [0];
|
|
@@ -17272,6 +17183,7 @@ async function getGbkLineIndex(input) {
|
|
|
17272
17183
|
newlineStyle: finalizeNewlineStyle(crlfCount, lfCount)
|
|
17273
17184
|
};
|
|
17274
17185
|
gbkLineIndexCache.set(input.filePath, result);
|
|
17186
|
+
pruneGbkLineIndexCache();
|
|
17275
17187
|
return result;
|
|
17276
17188
|
}
|
|
17277
17189
|
async function readDecodedGbkByteRange(input, start, endExclusive) {
|
|
@@ -19492,7 +19404,8 @@ var TEXT_TOOL_SYSTEM_PROMPT = [
|
|
|
19492
19404
|
"\u6587\u672C\u6587\u4EF6\u5904\u7406\u89C4\u5219\uFF1A",
|
|
19493
19405
|
"- \u666E\u901A UTF-8 / UTF-8 BOM / UTF-16 \u6587\u672C\uFF0C\u4F18\u5148\u4F7F\u7528 OpenCode \u5185\u7F6E read\u3001write\u3001edit\u3002",
|
|
19494
19406
|
"- \u9047\u5230 GBK / GB18030 \u6587\u4EF6\u3001\u4E2D\u6587\u4E71\u7801\u3001\u975E UTF-8 \u65E7\u6587\u672C\uFF0C\u4F18\u5148\u4F7F\u7528 gbk_read\u3001gbk_write\u3001gbk_edit\u3001gbk_search\uFF0C\u4E0D\u8981\u5148\u5C1D\u8BD5 text_* \u6216\u5185\u7F6E read/write/edit\u3002",
|
|
19495
|
-
"- \u65B0\u5EFA .txt \u6587\u4EF6\u5728 encoding=auto \u4E0B\u9ED8\u8BA4\
|
|
19407
|
+
"- \u65B0\u5EFA .txt \u6587\u4EF6\u5FC5\u987B\u4F18\u5148\u76F4\u63A5\u4F7F\u7528 gbk_write \u521B\u5EFA\uFF0C\u4E0D\u8981\u5148\u7528 text_write \u6216\u5185\u7F6E write/edit\uFF1B\u5E95\u5C42 text_write \u5728 encoding=auto \u4E0B\u867D\u7136\u4E5F\u4F1A\u9ED8\u8BA4\u5199\u6210 GBK\uFF0C\u4F46\u63D2\u4EF6\u4F1A\u628A\u8FD9\u7C7B\u521B\u5EFA\u8BF7\u6C42\u76F4\u63A5\u8DEF\u7531\u5230 gbk_*\u3002",
|
|
19408
|
+
"- \u5F53\u524D\u4F1A\u8BDD\u53EA\u8981\u5DF2\u7ECF\u6210\u529F\u4F7F\u7528\u8FC7 gbk_*\uFF0C\u540E\u7EED\u65B0\u5EFA\u6587\u4EF6\u4E5F\u7EE7\u7EED\u4F18\u5148\u4F7F\u7528 gbk_write / gbk_*\uFF0C\u4E0D\u8981\u518D\u5207\u56DE text_* \u6216\u5185\u7F6E write/edit\u3002",
|
|
19496
19409
|
"- \u5BF9\u73B0\u6709 .txt / .cfg / .ini / .log \u7B49\u65E7\u6587\u672C\u6587\u4EF6\uFF0C\u53EA\u8981\u6000\u7591\u662F\u4E2D\u6587\u672C\u5730\u7F16\u7801\uFF0C\u4F18\u5148\u5148\u7528 gbk_read \u5224\u65AD\uFF0C\u4E0D\u8981\u5148 edit \u518D\u56E0\u4E3A\u5339\u914D\u5931\u8D25\u6216\u6587\u4EF6\u65F6\u95F4\u6233\u53D8\u5316\u800C\u56DE\u9000\u3002",
|
|
19497
19410
|
"- \u5DF2\u786E\u8BA4\u6216\u9996\u6B21\u68C0\u6D4B\u5230\u662F GBK/GB18030 \u7684\u6587\u4EF6\u4F1A\u88AB\u63D2\u4EF6\u6301\u4E45\u8BB0\u5FC6\uFF1B\u518D\u6B21\u64CD\u4F5C\u540C\u4E00\u8DEF\u5F84\u65F6\uFF0C\u4F1A\u76F4\u63A5\u62E6\u622A\u5185\u7F6E read/write/edit \u548C text_*\uFF0C\u5E76\u8981\u6C42\u6539\u7528 gbk_*\u3002",
|
|
19498
19411
|
"- \u5982\u679C\u610F\u56FE\u662F\u2018\u5728\u67D0\u6807\u7B7E\u524D\u540E\u63D2\u5165\u5185\u5BB9\u2019\uFF0C\u4F18\u5148\u4F7F\u7528 mode=insertAfter \u6216 mode=insertBefore\uFF0C\u5E76\u4F20 anchor/content\u3002",
|
|
@@ -19660,6 +19573,8 @@ var MANAGED_TOOL_IDS = /* @__PURE__ */ new Set([
|
|
|
19660
19573
|
var BUILTIN_TEXT_TOOL_IDS = /* @__PURE__ */ new Set(["read", "write", "edit"]);
|
|
19661
19574
|
var TEXT_TOOL_IDS = /* @__PURE__ */ new Set(["text_read", "text_write", "text_edit"]);
|
|
19662
19575
|
var ROUTED_TEXT_TOOL_IDS = /* @__PURE__ */ new Set([...BUILTIN_TEXT_TOOL_IDS, ...TEXT_TOOL_IDS]);
|
|
19576
|
+
var CREATE_ROUTED_TEXT_TOOL_IDS = /* @__PURE__ */ new Set(["write", "edit", "text_write", "text_edit"]);
|
|
19577
|
+
var GBK_TOOL_IDS = /* @__PURE__ */ new Set(["gbk_read", "gbk_write", "gbk_edit", "gbk_search"]);
|
|
19663
19578
|
function getToolFilePath(args) {
|
|
19664
19579
|
if (!args || typeof args !== "object") {
|
|
19665
19580
|
return null;
|
|
@@ -19683,6 +19598,26 @@ function buildGbkRoutingMessage(filePath, encoding) {
|
|
|
19683
19598
|
function buildTextEditSessionRoutingMessage(filePath) {
|
|
19684
19599
|
return `\u5F53\u524D\u4F1A\u8BDD\u5DF2\u5BF9\u8BE5\u6587\u4EF6\u4F7F\u7528 text_edit\uFF0C\u8BF7\u7EE7\u7EED\u4F7F\u7528 text_read\u3001text_write\u3001text_edit \u6216\u76F4\u63A5\u6539\u7528 gbk_*\uFF1B\u4E0D\u8981\u518D\u5207\u56DE\u5185\u7F6E read/write/edit\uFF0C\u4EE5\u514D\u89E6\u53D1\u6587\u4EF6\u65B0\u9C9C\u5EA6\u68C0\u67E5\u51B2\u7A81\uFF1A${filePath}`;
|
|
19685
19600
|
}
|
|
19601
|
+
function buildNewTxtRoutingMessage(filePath) {
|
|
19602
|
+
return `\u65B0\u5EFA .txt \u6587\u4EF6\u8BF7\u76F4\u63A5\u4F7F\u7528 gbk_write \u521B\u5EFA\u4E3A GBK/GB18030\uFF1B\u4E0D\u8981\u5148\u4F7F\u7528\u5185\u7F6E write/edit \u6216 text_*\uFF1A${filePath}`;
|
|
19603
|
+
}
|
|
19604
|
+
function buildSessionGbkNewFileRoutingMessage(filePath) {
|
|
19605
|
+
return `\u5F53\u524D\u4F1A\u8BDD\u5DF2\u4F7F\u7528 gbk_* \u5DE5\u5177\uFF1B\u65B0\u5EFA\u6587\u4EF6\u8BF7\u7EE7\u7EED\u76F4\u63A5\u4F7F\u7528 gbk_write \u521B\u5EFA\u4E3A GBK/GB18030\uFF0C\u5FC5\u8981\u65F6\u518D\u7528 gbk_edit\uFF1B\u4E0D\u8981\u5207\u56DE\u5185\u7F6E write/edit \u6216 text_*\uFF1A${filePath}`;
|
|
19606
|
+
}
|
|
19607
|
+
function isNewTxtFilePath(filePath) {
|
|
19608
|
+
return path5.extname(filePath).toLowerCase() === ".txt";
|
|
19609
|
+
}
|
|
19610
|
+
async function doesPathExist(filePath) {
|
|
19611
|
+
try {
|
|
19612
|
+
await fs5.stat(filePath);
|
|
19613
|
+
return true;
|
|
19614
|
+
} catch (error45) {
|
|
19615
|
+
if (error45?.code === "ENOENT") {
|
|
19616
|
+
return false;
|
|
19617
|
+
}
|
|
19618
|
+
throw error45;
|
|
19619
|
+
}
|
|
19620
|
+
}
|
|
19686
19621
|
async function detectExistingGbkEncoding(filePath, allowExternal, directory, worktree) {
|
|
19687
19622
|
try {
|
|
19688
19623
|
const detected = await detectTextFileEncoding({
|
|
@@ -19716,51 +19651,26 @@ function truncateMetadataPreview(value, sessionID) {
|
|
|
19716
19651
|
return `${truncated}
|
|
19717
19652
|
\x1B[2m... (metadata diffPreview \u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${previewMaxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
19718
19653
|
}
|
|
19719
|
-
|
|
19720
|
-
if (!client?.session?.messages || !client.session.summarize) return;
|
|
19721
|
-
if (isAutoSummarizeInFlight(input.sessionID)) return;
|
|
19722
|
-
const contextTokens = input.model.limit?.context;
|
|
19723
|
-
if (typeof contextTokens !== "number" || contextTokens <= 0) return;
|
|
19724
|
-
const now = Date.now();
|
|
19725
|
-
const lastAutoSummarizeAt = getLastAutoSummarizeAt(input.sessionID);
|
|
19726
|
-
if (lastAutoSummarizeAt !== null && now - lastAutoSummarizeAt < AUTO_SUMMARIZE_COOLDOWN_MS) {
|
|
19727
|
-
return;
|
|
19728
|
-
}
|
|
19729
|
-
let pressure = getSessionPressure(input.sessionID);
|
|
19730
|
-
if (!pressure || now - pressure.checkedAt >= PRESSURE_CHECK_INTERVAL_MS) {
|
|
19731
|
-
const response = await client.session.messages({
|
|
19732
|
-
path: { id: input.sessionID },
|
|
19733
|
-
query: {
|
|
19734
|
-
directory,
|
|
19735
|
-
limit: SESSION_PRESSURE_MESSAGE_LIMIT
|
|
19736
|
-
},
|
|
19737
|
-
throwOnError: true
|
|
19738
|
-
});
|
|
19739
|
-
const estimatedTokens = estimateSessionTokens(Array.isArray(response.data) ? response.data : []);
|
|
19740
|
-
const pressureRatio = estimatedTokens / contextTokens;
|
|
19741
|
-
updateSessionPressure(input.sessionID, estimatedTokens, pressureRatio, now);
|
|
19742
|
-
pressure = getSessionPressure(input.sessionID);
|
|
19743
|
-
}
|
|
19744
|
-
if (!pressure || pressure.pressureRatio < AUTO_SUMMARIZE_PRESSURE_RATIO) return;
|
|
19745
|
-
markAutoSummarizeStarted(input.sessionID);
|
|
19746
|
-
try {
|
|
19747
|
-
await client.session.summarize({
|
|
19748
|
-
path: { id: input.sessionID },
|
|
19749
|
-
body: {
|
|
19750
|
-
providerID: input.model.providerID,
|
|
19751
|
-
modelID: input.model.id
|
|
19752
|
-
},
|
|
19753
|
-
query: { directory },
|
|
19754
|
-
throwOnError: true
|
|
19755
|
-
});
|
|
19756
|
-
clearSessionPressure(input.sessionID);
|
|
19757
|
-
markAutoSummarizeFinished(input.sessionID, true);
|
|
19758
|
-
} catch {
|
|
19759
|
-
markAutoSummarizeFinished(input.sessionID, false);
|
|
19760
|
-
}
|
|
19761
|
-
}
|
|
19762
|
-
function createOpencodeGbkHooks(client, directory, worktree) {
|
|
19654
|
+
function createOpencodeGbkHooks(_client, directory, worktree) {
|
|
19763
19655
|
const sessionTextEditedFiles = /* @__PURE__ */ new Map();
|
|
19656
|
+
const sessionGbkToolUsage = /* @__PURE__ */ new Set();
|
|
19657
|
+
const SESSION_TRACKING_LIMIT = 200;
|
|
19658
|
+
function pruneSessionTracking() {
|
|
19659
|
+
if (sessionTextEditedFiles.size > SESSION_TRACKING_LIMIT) {
|
|
19660
|
+
const overflow = sessionTextEditedFiles.size - SESSION_TRACKING_LIMIT;
|
|
19661
|
+
const sessionIDs = [...sessionTextEditedFiles.keys()].slice(0, overflow);
|
|
19662
|
+
for (const sessionID of sessionIDs) {
|
|
19663
|
+
sessionTextEditedFiles.delete(sessionID);
|
|
19664
|
+
}
|
|
19665
|
+
}
|
|
19666
|
+
if (sessionGbkToolUsage.size > SESSION_TRACKING_LIMIT) {
|
|
19667
|
+
const overflow = sessionGbkToolUsage.size - SESSION_TRACKING_LIMIT;
|
|
19668
|
+
const sessionIDs = [...sessionGbkToolUsage].slice(0, overflow);
|
|
19669
|
+
for (const sessionID of sessionIDs) {
|
|
19670
|
+
sessionGbkToolUsage.delete(sessionID);
|
|
19671
|
+
}
|
|
19672
|
+
}
|
|
19673
|
+
}
|
|
19764
19674
|
function rememberSessionTextEditFile(sessionID, normalizedFilePath) {
|
|
19765
19675
|
if (!sessionID) {
|
|
19766
19676
|
return;
|
|
@@ -19769,6 +19679,7 @@ function createOpencodeGbkHooks(client, directory, worktree) {
|
|
|
19769
19679
|
if (!files) {
|
|
19770
19680
|
files = /* @__PURE__ */ new Set();
|
|
19771
19681
|
sessionTextEditedFiles.set(sessionID, files);
|
|
19682
|
+
pruneSessionTracking();
|
|
19772
19683
|
}
|
|
19773
19684
|
files.add(normalizedFilePath);
|
|
19774
19685
|
}
|
|
@@ -19778,6 +19689,20 @@ function createOpencodeGbkHooks(client, directory, worktree) {
|
|
|
19778
19689
|
}
|
|
19779
19690
|
return sessionTextEditedFiles.get(sessionID)?.has(normalizedFilePath) ?? false;
|
|
19780
19691
|
}
|
|
19692
|
+
function rememberSessionGbkToolUsage(sessionID) {
|
|
19693
|
+
if (!sessionID) {
|
|
19694
|
+
return;
|
|
19695
|
+
}
|
|
19696
|
+
sessionGbkToolUsage.delete(sessionID);
|
|
19697
|
+
sessionGbkToolUsage.add(sessionID);
|
|
19698
|
+
pruneSessionTracking();
|
|
19699
|
+
}
|
|
19700
|
+
function hasSessionGbkToolUsage(sessionID) {
|
|
19701
|
+
if (!sessionID) {
|
|
19702
|
+
return false;
|
|
19703
|
+
}
|
|
19704
|
+
return sessionGbkToolUsage.has(sessionID);
|
|
19705
|
+
}
|
|
19781
19706
|
return {
|
|
19782
19707
|
tool: {
|
|
19783
19708
|
gbk_read: gbk_read_default,
|
|
@@ -19794,13 +19719,13 @@ function createOpencodeGbkHooks(client, directory, worktree) {
|
|
|
19794
19719
|
if (sessionID) {
|
|
19795
19720
|
markSessionCompacted(sessionID);
|
|
19796
19721
|
}
|
|
19722
|
+
return;
|
|
19797
19723
|
}
|
|
19798
19724
|
},
|
|
19799
19725
|
async "chat.params"(input) {
|
|
19800
19726
|
const contextTokens = input.model?.limit?.context;
|
|
19801
19727
|
if (typeof contextTokens === "number" && contextTokens > 0) {
|
|
19802
19728
|
setCurrentContextTokens(input.sessionID, contextTokens);
|
|
19803
|
-
await maybeAutoSummarizeSession(client, directory, input);
|
|
19804
19729
|
}
|
|
19805
19730
|
},
|
|
19806
19731
|
async "tool.execute.before"(input, output) {
|
|
@@ -19816,6 +19741,14 @@ function createOpencodeGbkHooks(client, directory, worktree) {
|
|
|
19816
19741
|
throw new Error(buildTextEditSessionRoutingMessage(filePath));
|
|
19817
19742
|
}
|
|
19818
19743
|
const resolvedFilePath = resolveCandidatePath(filePath, { directory, worktree });
|
|
19744
|
+
if (CREATE_ROUTED_TEXT_TOOL_IDS.has(input.tool) && !await doesPathExist(resolvedFilePath)) {
|
|
19745
|
+
if (hasSessionGbkToolUsage(input.sessionID)) {
|
|
19746
|
+
throw new Error(buildSessionGbkNewFileRoutingMessage(filePath));
|
|
19747
|
+
}
|
|
19748
|
+
if (isNewTxtFilePath(resolvedFilePath)) {
|
|
19749
|
+
throw new Error(buildNewTxtRoutingMessage(filePath));
|
|
19750
|
+
}
|
|
19751
|
+
}
|
|
19819
19752
|
const remembered = await getRememberedGbkEncoding(resolvedFilePath);
|
|
19820
19753
|
if (remembered) {
|
|
19821
19754
|
throw new Error(buildGbkRoutingMessage(filePath, remembered.encoding));
|
|
@@ -19840,7 +19773,6 @@ function createOpencodeGbkHooks(client, directory, worktree) {
|
|
|
19840
19773
|
const maxOutputChars = getMaxOutputChars(input.sessionID);
|
|
19841
19774
|
const compactionCount = getSessionCompactionCount(input.sessionID);
|
|
19842
19775
|
const sessionPressure = getSessionPressure(input.sessionID);
|
|
19843
|
-
const autoSummarizeCount = getAutoSummarizeCount(input.sessionID);
|
|
19844
19776
|
const metadata = output.metadata && typeof output.metadata === "object" ? { ...output.metadata } : {};
|
|
19845
19777
|
const nextOutput = truncateToolOutput(output.output, input.sessionID);
|
|
19846
19778
|
if (nextOutput !== output.output) {
|
|
@@ -19850,6 +19782,9 @@ function createOpencodeGbkHooks(client, directory, worktree) {
|
|
|
19850
19782
|
if (typeof metadata.diffPreview === "string") {
|
|
19851
19783
|
metadata.diffPreview = truncateMetadataPreview(metadata.diffPreview, input.sessionID);
|
|
19852
19784
|
}
|
|
19785
|
+
if (GBK_TOOL_IDS.has(input.tool)) {
|
|
19786
|
+
rememberSessionGbkToolUsage(input.sessionID);
|
|
19787
|
+
}
|
|
19853
19788
|
if (input.tool === "text_edit" && typeof metadata.filePath === "string") {
|
|
19854
19789
|
rememberSessionTextEditFile(
|
|
19855
19790
|
input.sessionID,
|
|
@@ -19869,9 +19804,6 @@ function createOpencodeGbkHooks(client, directory, worktree) {
|
|
|
19869
19804
|
metadata.estimatedSessionTokens = sessionPressure.estimatedTokens;
|
|
19870
19805
|
metadata.sessionPressureRatio = Number(sessionPressure.pressureRatio.toFixed(3));
|
|
19871
19806
|
}
|
|
19872
|
-
if (autoSummarizeCount > 0) {
|
|
19873
|
-
metadata.autoSummarizeCount = autoSummarizeCount;
|
|
19874
|
-
}
|
|
19875
19807
|
output.metadata = metadata;
|
|
19876
19808
|
},
|
|
19877
19809
|
async "experimental.chat.system.transform"(_input, output) {
|
|
@@ -3817,102 +3817,9 @@ var require_lib = __commonJS({
|
|
|
3817
3817
|
});
|
|
3818
3818
|
|
|
3819
3819
|
// src/plugin/index.ts
|
|
3820
|
+
import fs5 from "fs/promises";
|
|
3820
3821
|
import path5 from "path";
|
|
3821
3822
|
|
|
3822
|
-
// src/lib/session-pressure.ts
|
|
3823
|
-
var AUTO_SUMMARIZE_PRESSURE_RATIO = 0.85;
|
|
3824
|
-
var AUTO_SUMMARIZE_COOLDOWN_MS = 6e4;
|
|
3825
|
-
var PRESSURE_CHECK_INTERVAL_MS = 15e3;
|
|
3826
|
-
var SESSION_PRESSURE_MESSAGE_LIMIT = 200;
|
|
3827
|
-
function estimateUnknownChars(value) {
|
|
3828
|
-
if (typeof value === "string") return value.length;
|
|
3829
|
-
if (typeof value === "number" || typeof value === "boolean") return String(value).length;
|
|
3830
|
-
if (Array.isArray(value)) {
|
|
3831
|
-
return value.reduce((total, item) => total + estimateUnknownChars(item), 0);
|
|
3832
|
-
}
|
|
3833
|
-
if (!value || typeof value !== "object") return 0;
|
|
3834
|
-
try {
|
|
3835
|
-
return JSON.stringify(value).length;
|
|
3836
|
-
} catch {
|
|
3837
|
-
return 0;
|
|
3838
|
-
}
|
|
3839
|
-
}
|
|
3840
|
-
function estimateDiffChars(summary) {
|
|
3841
|
-
let chars = (summary.title?.length ?? 0) + (summary.body?.length ?? 0);
|
|
3842
|
-
for (const diff of summary.diffs ?? []) {
|
|
3843
|
-
chars += diff.file.length + diff.before.length + diff.after.length;
|
|
3844
|
-
}
|
|
3845
|
-
return chars;
|
|
3846
|
-
}
|
|
3847
|
-
function estimateToolPartChars(part) {
|
|
3848
|
-
let chars = part.tool.length + estimateUnknownChars(part.metadata);
|
|
3849
|
-
switch (part.state.status) {
|
|
3850
|
-
case "pending":
|
|
3851
|
-
chars += estimateUnknownChars(part.state.input) + part.state.raw.length;
|
|
3852
|
-
break;
|
|
3853
|
-
case "running":
|
|
3854
|
-
chars += estimateUnknownChars(part.state.input);
|
|
3855
|
-
chars += part.state.title?.length ?? 0;
|
|
3856
|
-
chars += estimateUnknownChars(part.state.metadata);
|
|
3857
|
-
break;
|
|
3858
|
-
case "completed":
|
|
3859
|
-
chars += estimateUnknownChars(part.state.input);
|
|
3860
|
-
chars += part.state.output.length + part.state.title.length;
|
|
3861
|
-
chars += estimateUnknownChars(part.state.metadata);
|
|
3862
|
-
break;
|
|
3863
|
-
case "error":
|
|
3864
|
-
chars += estimateUnknownChars(part.state.input);
|
|
3865
|
-
chars += part.state.error.length + estimateUnknownChars(part.state.metadata);
|
|
3866
|
-
break;
|
|
3867
|
-
}
|
|
3868
|
-
return chars;
|
|
3869
|
-
}
|
|
3870
|
-
function estimatePartChars(part) {
|
|
3871
|
-
switch (part.type) {
|
|
3872
|
-
case "text":
|
|
3873
|
-
return part.text.length;
|
|
3874
|
-
case "reasoning":
|
|
3875
|
-
return Math.round(part.text.length * 0.25);
|
|
3876
|
-
case "file":
|
|
3877
|
-
return (part.filename?.length ?? 0) + (part.source?.text.value.length ?? 0);
|
|
3878
|
-
case "tool":
|
|
3879
|
-
return estimateToolPartChars(part);
|
|
3880
|
-
case "step-start":
|
|
3881
|
-
return part.snapshot?.length ?? 0;
|
|
3882
|
-
case "step-finish":
|
|
3883
|
-
return part.reason.length + (part.snapshot?.length ?? 0);
|
|
3884
|
-
case "snapshot":
|
|
3885
|
-
return part.snapshot.length;
|
|
3886
|
-
case "patch":
|
|
3887
|
-
return part.hash.length + part.files.join("\n").length;
|
|
3888
|
-
case "agent":
|
|
3889
|
-
return part.name.length + (part.source?.value.length ?? 0);
|
|
3890
|
-
case "retry":
|
|
3891
|
-
return estimateUnknownChars(part.error);
|
|
3892
|
-
case "compaction":
|
|
3893
|
-
return 32;
|
|
3894
|
-
case "subtask":
|
|
3895
|
-
return part.prompt.length + part.description.length + part.agent.length;
|
|
3896
|
-
}
|
|
3897
|
-
}
|
|
3898
|
-
function estimateMessageChars(message, parts) {
|
|
3899
|
-
let chars = 0;
|
|
3900
|
-
if (message.role === "user") {
|
|
3901
|
-
chars += message.system?.length ?? 0;
|
|
3902
|
-
if (message.summary) {
|
|
3903
|
-
chars += estimateDiffChars(message.summary);
|
|
3904
|
-
}
|
|
3905
|
-
}
|
|
3906
|
-
for (const part of parts) {
|
|
3907
|
-
chars += estimatePartChars(part);
|
|
3908
|
-
}
|
|
3909
|
-
return chars;
|
|
3910
|
-
}
|
|
3911
|
-
function estimateSessionTokens(messages) {
|
|
3912
|
-
const totalChars = messages.reduce((total, message) => total + estimateMessageChars(message.info, message.parts), 0);
|
|
3913
|
-
return Math.ceil(totalChars / 4);
|
|
3914
|
-
}
|
|
3915
|
-
|
|
3916
3823
|
// src/lib/encoding-memory.ts
|
|
3917
3824
|
import fs from "fs/promises";
|
|
3918
3825
|
import os from "os";
|
|
@@ -16534,8 +16441,32 @@ var FALLBACK_MAX_OUTPUT_CHARS = 8e3;
|
|
|
16534
16441
|
var MIN_BASE_MAX_OUTPUT_CHARS = 4e3;
|
|
16535
16442
|
var MAX_BASE_OUTPUT_CHARS = 32e3;
|
|
16536
16443
|
var MIN_PRESSURED_OUTPUT_CHARS = 1500;
|
|
16444
|
+
var SESSION_STATE_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
16445
|
+
var MAX_SESSION_STATES = 200;
|
|
16537
16446
|
var sessionStates = /* @__PURE__ */ new Map();
|
|
16447
|
+
function pruneSessionStates(now = Date.now()) {
|
|
16448
|
+
for (const [sessionID, state] of sessionStates) {
|
|
16449
|
+
if (now - state.lastTouchedAt > SESSION_STATE_TTL_MS) {
|
|
16450
|
+
sessionStates.delete(sessionID);
|
|
16451
|
+
}
|
|
16452
|
+
}
|
|
16453
|
+
if (sessionStates.size <= MAX_SESSION_STATES) {
|
|
16454
|
+
return;
|
|
16455
|
+
}
|
|
16456
|
+
const oldestEntries = [...sessionStates.entries()].sort((left, right) => left[1].lastTouchedAt - right[1].lastTouchedAt);
|
|
16457
|
+
for (const [sessionID] of oldestEntries) {
|
|
16458
|
+
if (sessionStates.size <= MAX_SESSION_STATES) {
|
|
16459
|
+
break;
|
|
16460
|
+
}
|
|
16461
|
+
sessionStates.delete(sessionID);
|
|
16462
|
+
}
|
|
16463
|
+
}
|
|
16464
|
+
function touchSessionState(state, touchedAt = Date.now()) {
|
|
16465
|
+
state.lastTouchedAt = touchedAt;
|
|
16466
|
+
}
|
|
16538
16467
|
function getOrCreateSessionState(sessionID) {
|
|
16468
|
+
const now = Date.now();
|
|
16469
|
+
pruneSessionStates(now);
|
|
16539
16470
|
let state = sessionStates.get(sessionID);
|
|
16540
16471
|
if (!state) {
|
|
16541
16472
|
state = {
|
|
@@ -16546,15 +16477,22 @@ function getOrCreateSessionState(sessionID) {
|
|
|
16546
16477
|
lastPressureCheckedAt: null,
|
|
16547
16478
|
autoSummarizeInFlight: false,
|
|
16548
16479
|
lastAutoSummarizeAt: null,
|
|
16549
|
-
autoSummarizeCount: 0
|
|
16480
|
+
autoSummarizeCount: 0,
|
|
16481
|
+
lastTouchedAt: now
|
|
16550
16482
|
};
|
|
16551
16483
|
sessionStates.set(sessionID, state);
|
|
16484
|
+
return state;
|
|
16552
16485
|
}
|
|
16486
|
+
touchSessionState(state, now);
|
|
16553
16487
|
return state;
|
|
16554
16488
|
}
|
|
16555
16489
|
function getSessionState(sessionID) {
|
|
16556
16490
|
if (!sessionID) return null;
|
|
16557
|
-
|
|
16491
|
+
const state = sessionStates.get(sessionID) ?? null;
|
|
16492
|
+
if (state) {
|
|
16493
|
+
touchSessionState(state);
|
|
16494
|
+
}
|
|
16495
|
+
return state;
|
|
16558
16496
|
}
|
|
16559
16497
|
function getCompactionPressureFactor(compactionCount) {
|
|
16560
16498
|
if (compactionCount >= 3) return 0.35;
|
|
@@ -16590,20 +16528,6 @@ function markSessionCompacted(sessionID) {
|
|
|
16590
16528
|
function getSessionCompactionCount(sessionID) {
|
|
16591
16529
|
return getSessionState(sessionID)?.compactionCount ?? 0;
|
|
16592
16530
|
}
|
|
16593
|
-
function updateSessionPressure(sessionID, estimatedTokens, pressureRatio, checkedAt = Date.now()) {
|
|
16594
|
-
if (!sessionID) return;
|
|
16595
|
-
const state = getOrCreateSessionState(sessionID);
|
|
16596
|
-
state.estimatedTokens = estimatedTokens;
|
|
16597
|
-
state.pressureRatio = pressureRatio;
|
|
16598
|
-
state.lastPressureCheckedAt = checkedAt;
|
|
16599
|
-
}
|
|
16600
|
-
function clearSessionPressure(sessionID) {
|
|
16601
|
-
if (!sessionID) return;
|
|
16602
|
-
const state = getOrCreateSessionState(sessionID);
|
|
16603
|
-
state.estimatedTokens = null;
|
|
16604
|
-
state.pressureRatio = null;
|
|
16605
|
-
state.lastPressureCheckedAt = null;
|
|
16606
|
-
}
|
|
16607
16531
|
function getSessionPressure(sessionID) {
|
|
16608
16532
|
const state = getSessionState(sessionID);
|
|
16609
16533
|
if (!state || state.estimatedTokens === null || state.pressureRatio === null || state.lastPressureCheckedAt === null) {
|
|
@@ -16615,32 +16539,6 @@ function getSessionPressure(sessionID) {
|
|
|
16615
16539
|
checkedAt: state.lastPressureCheckedAt
|
|
16616
16540
|
};
|
|
16617
16541
|
}
|
|
16618
|
-
function isAutoSummarizeInFlight(sessionID) {
|
|
16619
|
-
return getSessionState(sessionID)?.autoSummarizeInFlight ?? false;
|
|
16620
|
-
}
|
|
16621
|
-
function markAutoSummarizeStarted(sessionID) {
|
|
16622
|
-
if (!sessionID) return;
|
|
16623
|
-
const state = getOrCreateSessionState(sessionID);
|
|
16624
|
-
state.autoSummarizeInFlight = true;
|
|
16625
|
-
}
|
|
16626
|
-
function markAutoSummarizeFinished(sessionID, summarized, finishedAt = Date.now()) {
|
|
16627
|
-
if (!sessionID) return;
|
|
16628
|
-
const state = getOrCreateSessionState(sessionID);
|
|
16629
|
-
state.autoSummarizeInFlight = false;
|
|
16630
|
-
if (summarized) {
|
|
16631
|
-
state.lastAutoSummarizeAt = finishedAt;
|
|
16632
|
-
state.autoSummarizeCount += 1;
|
|
16633
|
-
state.estimatedTokens = null;
|
|
16634
|
-
state.pressureRatio = null;
|
|
16635
|
-
state.lastPressureCheckedAt = null;
|
|
16636
|
-
}
|
|
16637
|
-
}
|
|
16638
|
-
function getLastAutoSummarizeAt(sessionID) {
|
|
16639
|
-
return getSessionState(sessionID)?.lastAutoSummarizeAt ?? null;
|
|
16640
|
-
}
|
|
16641
|
-
function getAutoSummarizeCount(sessionID) {
|
|
16642
|
-
return getSessionState(sessionID)?.autoSummarizeCount ?? 0;
|
|
16643
|
-
}
|
|
16644
16542
|
function getMaxOutputChars(sessionID, fallback = FALLBACK_MAX_OUTPUT_CHARS) {
|
|
16645
16543
|
const state = getSessionState(sessionID);
|
|
16646
16544
|
const base = getBaseMaxOutputChars(state?.contextTokens ?? null, fallback);
|
|
@@ -16663,6 +16561,7 @@ import fs3 from "fs/promises";
|
|
|
16663
16561
|
import path3 from "path";
|
|
16664
16562
|
var STREAMING_FILE_SIZE_THRESHOLD_BYTES = 1024 * 1024;
|
|
16665
16563
|
var STREAM_READ_CHUNK_SIZE_BYTES = 1024 * 1024;
|
|
16564
|
+
var MAX_GBK_LINE_INDEX_CACHE_ENTRIES = 32;
|
|
16666
16565
|
var gbkLineIndexCache = /* @__PURE__ */ new Map();
|
|
16667
16566
|
var ANSI_RED = "\x1B[31m";
|
|
16668
16567
|
var ANSI_GREEN = "\x1B[32m";
|
|
@@ -16705,6 +16604,16 @@ function toSafeNumber(value) {
|
|
|
16705
16604
|
function invalidateGbkLineIndex(filePath) {
|
|
16706
16605
|
gbkLineIndexCache.delete(filePath);
|
|
16707
16606
|
}
|
|
16607
|
+
function pruneGbkLineIndexCache() {
|
|
16608
|
+
if (gbkLineIndexCache.size <= MAX_GBK_LINE_INDEX_CACHE_ENTRIES) {
|
|
16609
|
+
return;
|
|
16610
|
+
}
|
|
16611
|
+
const overflow = gbkLineIndexCache.size - MAX_GBK_LINE_INDEX_CACHE_ENTRIES;
|
|
16612
|
+
const oldestKeys = [...gbkLineIndexCache.keys()].slice(0, overflow);
|
|
16613
|
+
for (const key of oldestKeys) {
|
|
16614
|
+
gbkLineIndexCache.delete(key);
|
|
16615
|
+
}
|
|
16616
|
+
}
|
|
16708
16617
|
function assertStringArgument(value, name) {
|
|
16709
16618
|
if (typeof value !== "string") {
|
|
16710
16619
|
throw createGbkError("GBK_INVALID_ARGUMENT", `${name} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);
|
|
@@ -17227,6 +17136,8 @@ async function visitDecodedTextChunks(input, visitor) {
|
|
|
17227
17136
|
async function getGbkLineIndex(input) {
|
|
17228
17137
|
const cached2 = gbkLineIndexCache.get(input.filePath);
|
|
17229
17138
|
if (cached2 && cached2.fileSize === toSafeNumber(input.stat.size) && cached2.mtimeMs === toSafeNumber(input.stat.mtimeMs)) {
|
|
17139
|
+
gbkLineIndexCache.delete(input.filePath);
|
|
17140
|
+
gbkLineIndexCache.set(input.filePath, cached2);
|
|
17230
17141
|
return cached2;
|
|
17231
17142
|
}
|
|
17232
17143
|
const lineStartOffsets = [0];
|
|
@@ -17272,6 +17183,7 @@ async function getGbkLineIndex(input) {
|
|
|
17272
17183
|
newlineStyle: finalizeNewlineStyle(crlfCount, lfCount)
|
|
17273
17184
|
};
|
|
17274
17185
|
gbkLineIndexCache.set(input.filePath, result);
|
|
17186
|
+
pruneGbkLineIndexCache();
|
|
17275
17187
|
return result;
|
|
17276
17188
|
}
|
|
17277
17189
|
async function readDecodedGbkByteRange(input, start, endExclusive) {
|
|
@@ -19492,7 +19404,8 @@ var TEXT_TOOL_SYSTEM_PROMPT = [
|
|
|
19492
19404
|
"\u6587\u672C\u6587\u4EF6\u5904\u7406\u89C4\u5219\uFF1A",
|
|
19493
19405
|
"- \u666E\u901A UTF-8 / UTF-8 BOM / UTF-16 \u6587\u672C\uFF0C\u4F18\u5148\u4F7F\u7528 OpenCode \u5185\u7F6E read\u3001write\u3001edit\u3002",
|
|
19494
19406
|
"- \u9047\u5230 GBK / GB18030 \u6587\u4EF6\u3001\u4E2D\u6587\u4E71\u7801\u3001\u975E UTF-8 \u65E7\u6587\u672C\uFF0C\u4F18\u5148\u4F7F\u7528 gbk_read\u3001gbk_write\u3001gbk_edit\u3001gbk_search\uFF0C\u4E0D\u8981\u5148\u5C1D\u8BD5 text_* \u6216\u5185\u7F6E read/write/edit\u3002",
|
|
19495
|
-
"- \u65B0\u5EFA .txt \u6587\u4EF6\u5728 encoding=auto \u4E0B\u9ED8\u8BA4\
|
|
19407
|
+
"- \u65B0\u5EFA .txt \u6587\u4EF6\u5FC5\u987B\u4F18\u5148\u76F4\u63A5\u4F7F\u7528 gbk_write \u521B\u5EFA\uFF0C\u4E0D\u8981\u5148\u7528 text_write \u6216\u5185\u7F6E write/edit\uFF1B\u5E95\u5C42 text_write \u5728 encoding=auto \u4E0B\u867D\u7136\u4E5F\u4F1A\u9ED8\u8BA4\u5199\u6210 GBK\uFF0C\u4F46\u63D2\u4EF6\u4F1A\u628A\u8FD9\u7C7B\u521B\u5EFA\u8BF7\u6C42\u76F4\u63A5\u8DEF\u7531\u5230 gbk_*\u3002",
|
|
19408
|
+
"- \u5F53\u524D\u4F1A\u8BDD\u53EA\u8981\u5DF2\u7ECF\u6210\u529F\u4F7F\u7528\u8FC7 gbk_*\uFF0C\u540E\u7EED\u65B0\u5EFA\u6587\u4EF6\u4E5F\u7EE7\u7EED\u4F18\u5148\u4F7F\u7528 gbk_write / gbk_*\uFF0C\u4E0D\u8981\u518D\u5207\u56DE text_* \u6216\u5185\u7F6E write/edit\u3002",
|
|
19496
19409
|
"- \u5BF9\u73B0\u6709 .txt / .cfg / .ini / .log \u7B49\u65E7\u6587\u672C\u6587\u4EF6\uFF0C\u53EA\u8981\u6000\u7591\u662F\u4E2D\u6587\u672C\u5730\u7F16\u7801\uFF0C\u4F18\u5148\u5148\u7528 gbk_read \u5224\u65AD\uFF0C\u4E0D\u8981\u5148 edit \u518D\u56E0\u4E3A\u5339\u914D\u5931\u8D25\u6216\u6587\u4EF6\u65F6\u95F4\u6233\u53D8\u5316\u800C\u56DE\u9000\u3002",
|
|
19497
19410
|
"- \u5DF2\u786E\u8BA4\u6216\u9996\u6B21\u68C0\u6D4B\u5230\u662F GBK/GB18030 \u7684\u6587\u4EF6\u4F1A\u88AB\u63D2\u4EF6\u6301\u4E45\u8BB0\u5FC6\uFF1B\u518D\u6B21\u64CD\u4F5C\u540C\u4E00\u8DEF\u5F84\u65F6\uFF0C\u4F1A\u76F4\u63A5\u62E6\u622A\u5185\u7F6E read/write/edit \u548C text_*\uFF0C\u5E76\u8981\u6C42\u6539\u7528 gbk_*\u3002",
|
|
19498
19411
|
"- \u5982\u679C\u610F\u56FE\u662F\u2018\u5728\u67D0\u6807\u7B7E\u524D\u540E\u63D2\u5165\u5185\u5BB9\u2019\uFF0C\u4F18\u5148\u4F7F\u7528 mode=insertAfter \u6216 mode=insertBefore\uFF0C\u5E76\u4F20 anchor/content\u3002",
|
|
@@ -19660,6 +19573,8 @@ var MANAGED_TOOL_IDS = /* @__PURE__ */ new Set([
|
|
|
19660
19573
|
var BUILTIN_TEXT_TOOL_IDS = /* @__PURE__ */ new Set(["read", "write", "edit"]);
|
|
19661
19574
|
var TEXT_TOOL_IDS = /* @__PURE__ */ new Set(["text_read", "text_write", "text_edit"]);
|
|
19662
19575
|
var ROUTED_TEXT_TOOL_IDS = /* @__PURE__ */ new Set([...BUILTIN_TEXT_TOOL_IDS, ...TEXT_TOOL_IDS]);
|
|
19576
|
+
var CREATE_ROUTED_TEXT_TOOL_IDS = /* @__PURE__ */ new Set(["write", "edit", "text_write", "text_edit"]);
|
|
19577
|
+
var GBK_TOOL_IDS = /* @__PURE__ */ new Set(["gbk_read", "gbk_write", "gbk_edit", "gbk_search"]);
|
|
19663
19578
|
function getToolFilePath(args) {
|
|
19664
19579
|
if (!args || typeof args !== "object") {
|
|
19665
19580
|
return null;
|
|
@@ -19683,6 +19598,26 @@ function buildGbkRoutingMessage(filePath, encoding) {
|
|
|
19683
19598
|
function buildTextEditSessionRoutingMessage(filePath) {
|
|
19684
19599
|
return `\u5F53\u524D\u4F1A\u8BDD\u5DF2\u5BF9\u8BE5\u6587\u4EF6\u4F7F\u7528 text_edit\uFF0C\u8BF7\u7EE7\u7EED\u4F7F\u7528 text_read\u3001text_write\u3001text_edit \u6216\u76F4\u63A5\u6539\u7528 gbk_*\uFF1B\u4E0D\u8981\u518D\u5207\u56DE\u5185\u7F6E read/write/edit\uFF0C\u4EE5\u514D\u89E6\u53D1\u6587\u4EF6\u65B0\u9C9C\u5EA6\u68C0\u67E5\u51B2\u7A81\uFF1A${filePath}`;
|
|
19685
19600
|
}
|
|
19601
|
+
function buildNewTxtRoutingMessage(filePath) {
|
|
19602
|
+
return `\u65B0\u5EFA .txt \u6587\u4EF6\u8BF7\u76F4\u63A5\u4F7F\u7528 gbk_write \u521B\u5EFA\u4E3A GBK/GB18030\uFF1B\u4E0D\u8981\u5148\u4F7F\u7528\u5185\u7F6E write/edit \u6216 text_*\uFF1A${filePath}`;
|
|
19603
|
+
}
|
|
19604
|
+
function buildSessionGbkNewFileRoutingMessage(filePath) {
|
|
19605
|
+
return `\u5F53\u524D\u4F1A\u8BDD\u5DF2\u4F7F\u7528 gbk_* \u5DE5\u5177\uFF1B\u65B0\u5EFA\u6587\u4EF6\u8BF7\u7EE7\u7EED\u76F4\u63A5\u4F7F\u7528 gbk_write \u521B\u5EFA\u4E3A GBK/GB18030\uFF0C\u5FC5\u8981\u65F6\u518D\u7528 gbk_edit\uFF1B\u4E0D\u8981\u5207\u56DE\u5185\u7F6E write/edit \u6216 text_*\uFF1A${filePath}`;
|
|
19606
|
+
}
|
|
19607
|
+
function isNewTxtFilePath(filePath) {
|
|
19608
|
+
return path5.extname(filePath).toLowerCase() === ".txt";
|
|
19609
|
+
}
|
|
19610
|
+
async function doesPathExist(filePath) {
|
|
19611
|
+
try {
|
|
19612
|
+
await fs5.stat(filePath);
|
|
19613
|
+
return true;
|
|
19614
|
+
} catch (error45) {
|
|
19615
|
+
if (error45?.code === "ENOENT") {
|
|
19616
|
+
return false;
|
|
19617
|
+
}
|
|
19618
|
+
throw error45;
|
|
19619
|
+
}
|
|
19620
|
+
}
|
|
19686
19621
|
async function detectExistingGbkEncoding(filePath, allowExternal, directory, worktree) {
|
|
19687
19622
|
try {
|
|
19688
19623
|
const detected = await detectTextFileEncoding({
|
|
@@ -19716,51 +19651,26 @@ function truncateMetadataPreview(value, sessionID) {
|
|
|
19716
19651
|
return `${truncated}
|
|
19717
19652
|
\x1B[2m... (metadata diffPreview \u5DF2\u622A\u65AD\uFF0C\u8D85\u51FA ${previewMaxChars} \u5B57\u7B26\u4E0A\u9650)\x1B[0m`;
|
|
19718
19653
|
}
|
|
19719
|
-
|
|
19720
|
-
if (!client?.session?.messages || !client.session.summarize) return;
|
|
19721
|
-
if (isAutoSummarizeInFlight(input.sessionID)) return;
|
|
19722
|
-
const contextTokens = input.model.limit?.context;
|
|
19723
|
-
if (typeof contextTokens !== "number" || contextTokens <= 0) return;
|
|
19724
|
-
const now = Date.now();
|
|
19725
|
-
const lastAutoSummarizeAt = getLastAutoSummarizeAt(input.sessionID);
|
|
19726
|
-
if (lastAutoSummarizeAt !== null && now - lastAutoSummarizeAt < AUTO_SUMMARIZE_COOLDOWN_MS) {
|
|
19727
|
-
return;
|
|
19728
|
-
}
|
|
19729
|
-
let pressure = getSessionPressure(input.sessionID);
|
|
19730
|
-
if (!pressure || now - pressure.checkedAt >= PRESSURE_CHECK_INTERVAL_MS) {
|
|
19731
|
-
const response = await client.session.messages({
|
|
19732
|
-
path: { id: input.sessionID },
|
|
19733
|
-
query: {
|
|
19734
|
-
directory,
|
|
19735
|
-
limit: SESSION_PRESSURE_MESSAGE_LIMIT
|
|
19736
|
-
},
|
|
19737
|
-
throwOnError: true
|
|
19738
|
-
});
|
|
19739
|
-
const estimatedTokens = estimateSessionTokens(Array.isArray(response.data) ? response.data : []);
|
|
19740
|
-
const pressureRatio = estimatedTokens / contextTokens;
|
|
19741
|
-
updateSessionPressure(input.sessionID, estimatedTokens, pressureRatio, now);
|
|
19742
|
-
pressure = getSessionPressure(input.sessionID);
|
|
19743
|
-
}
|
|
19744
|
-
if (!pressure || pressure.pressureRatio < AUTO_SUMMARIZE_PRESSURE_RATIO) return;
|
|
19745
|
-
markAutoSummarizeStarted(input.sessionID);
|
|
19746
|
-
try {
|
|
19747
|
-
await client.session.summarize({
|
|
19748
|
-
path: { id: input.sessionID },
|
|
19749
|
-
body: {
|
|
19750
|
-
providerID: input.model.providerID,
|
|
19751
|
-
modelID: input.model.id
|
|
19752
|
-
},
|
|
19753
|
-
query: { directory },
|
|
19754
|
-
throwOnError: true
|
|
19755
|
-
});
|
|
19756
|
-
clearSessionPressure(input.sessionID);
|
|
19757
|
-
markAutoSummarizeFinished(input.sessionID, true);
|
|
19758
|
-
} catch {
|
|
19759
|
-
markAutoSummarizeFinished(input.sessionID, false);
|
|
19760
|
-
}
|
|
19761
|
-
}
|
|
19762
|
-
function createOpencodeGbkHooks(client, directory, worktree) {
|
|
19654
|
+
function createOpencodeGbkHooks(_client, directory, worktree) {
|
|
19763
19655
|
const sessionTextEditedFiles = /* @__PURE__ */ new Map();
|
|
19656
|
+
const sessionGbkToolUsage = /* @__PURE__ */ new Set();
|
|
19657
|
+
const SESSION_TRACKING_LIMIT = 200;
|
|
19658
|
+
function pruneSessionTracking() {
|
|
19659
|
+
if (sessionTextEditedFiles.size > SESSION_TRACKING_LIMIT) {
|
|
19660
|
+
const overflow = sessionTextEditedFiles.size - SESSION_TRACKING_LIMIT;
|
|
19661
|
+
const sessionIDs = [...sessionTextEditedFiles.keys()].slice(0, overflow);
|
|
19662
|
+
for (const sessionID of sessionIDs) {
|
|
19663
|
+
sessionTextEditedFiles.delete(sessionID);
|
|
19664
|
+
}
|
|
19665
|
+
}
|
|
19666
|
+
if (sessionGbkToolUsage.size > SESSION_TRACKING_LIMIT) {
|
|
19667
|
+
const overflow = sessionGbkToolUsage.size - SESSION_TRACKING_LIMIT;
|
|
19668
|
+
const sessionIDs = [...sessionGbkToolUsage].slice(0, overflow);
|
|
19669
|
+
for (const sessionID of sessionIDs) {
|
|
19670
|
+
sessionGbkToolUsage.delete(sessionID);
|
|
19671
|
+
}
|
|
19672
|
+
}
|
|
19673
|
+
}
|
|
19764
19674
|
function rememberSessionTextEditFile(sessionID, normalizedFilePath) {
|
|
19765
19675
|
if (!sessionID) {
|
|
19766
19676
|
return;
|
|
@@ -19769,6 +19679,7 @@ function createOpencodeGbkHooks(client, directory, worktree) {
|
|
|
19769
19679
|
if (!files) {
|
|
19770
19680
|
files = /* @__PURE__ */ new Set();
|
|
19771
19681
|
sessionTextEditedFiles.set(sessionID, files);
|
|
19682
|
+
pruneSessionTracking();
|
|
19772
19683
|
}
|
|
19773
19684
|
files.add(normalizedFilePath);
|
|
19774
19685
|
}
|
|
@@ -19778,6 +19689,20 @@ function createOpencodeGbkHooks(client, directory, worktree) {
|
|
|
19778
19689
|
}
|
|
19779
19690
|
return sessionTextEditedFiles.get(sessionID)?.has(normalizedFilePath) ?? false;
|
|
19780
19691
|
}
|
|
19692
|
+
function rememberSessionGbkToolUsage(sessionID) {
|
|
19693
|
+
if (!sessionID) {
|
|
19694
|
+
return;
|
|
19695
|
+
}
|
|
19696
|
+
sessionGbkToolUsage.delete(sessionID);
|
|
19697
|
+
sessionGbkToolUsage.add(sessionID);
|
|
19698
|
+
pruneSessionTracking();
|
|
19699
|
+
}
|
|
19700
|
+
function hasSessionGbkToolUsage(sessionID) {
|
|
19701
|
+
if (!sessionID) {
|
|
19702
|
+
return false;
|
|
19703
|
+
}
|
|
19704
|
+
return sessionGbkToolUsage.has(sessionID);
|
|
19705
|
+
}
|
|
19781
19706
|
return {
|
|
19782
19707
|
tool: {
|
|
19783
19708
|
gbk_read: gbk_read_default,
|
|
@@ -19794,13 +19719,13 @@ function createOpencodeGbkHooks(client, directory, worktree) {
|
|
|
19794
19719
|
if (sessionID) {
|
|
19795
19720
|
markSessionCompacted(sessionID);
|
|
19796
19721
|
}
|
|
19722
|
+
return;
|
|
19797
19723
|
}
|
|
19798
19724
|
},
|
|
19799
19725
|
async "chat.params"(input) {
|
|
19800
19726
|
const contextTokens = input.model?.limit?.context;
|
|
19801
19727
|
if (typeof contextTokens === "number" && contextTokens > 0) {
|
|
19802
19728
|
setCurrentContextTokens(input.sessionID, contextTokens);
|
|
19803
|
-
await maybeAutoSummarizeSession(client, directory, input);
|
|
19804
19729
|
}
|
|
19805
19730
|
},
|
|
19806
19731
|
async "tool.execute.before"(input, output) {
|
|
@@ -19816,6 +19741,14 @@ function createOpencodeGbkHooks(client, directory, worktree) {
|
|
|
19816
19741
|
throw new Error(buildTextEditSessionRoutingMessage(filePath));
|
|
19817
19742
|
}
|
|
19818
19743
|
const resolvedFilePath = resolveCandidatePath(filePath, { directory, worktree });
|
|
19744
|
+
if (CREATE_ROUTED_TEXT_TOOL_IDS.has(input.tool) && !await doesPathExist(resolvedFilePath)) {
|
|
19745
|
+
if (hasSessionGbkToolUsage(input.sessionID)) {
|
|
19746
|
+
throw new Error(buildSessionGbkNewFileRoutingMessage(filePath));
|
|
19747
|
+
}
|
|
19748
|
+
if (isNewTxtFilePath(resolvedFilePath)) {
|
|
19749
|
+
throw new Error(buildNewTxtRoutingMessage(filePath));
|
|
19750
|
+
}
|
|
19751
|
+
}
|
|
19819
19752
|
const remembered = await getRememberedGbkEncoding(resolvedFilePath);
|
|
19820
19753
|
if (remembered) {
|
|
19821
19754
|
throw new Error(buildGbkRoutingMessage(filePath, remembered.encoding));
|
|
@@ -19840,7 +19773,6 @@ function createOpencodeGbkHooks(client, directory, worktree) {
|
|
|
19840
19773
|
const maxOutputChars = getMaxOutputChars(input.sessionID);
|
|
19841
19774
|
const compactionCount = getSessionCompactionCount(input.sessionID);
|
|
19842
19775
|
const sessionPressure = getSessionPressure(input.sessionID);
|
|
19843
|
-
const autoSummarizeCount = getAutoSummarizeCount(input.sessionID);
|
|
19844
19776
|
const metadata = output.metadata && typeof output.metadata === "object" ? { ...output.metadata } : {};
|
|
19845
19777
|
const nextOutput = truncateToolOutput(output.output, input.sessionID);
|
|
19846
19778
|
if (nextOutput !== output.output) {
|
|
@@ -19850,6 +19782,9 @@ function createOpencodeGbkHooks(client, directory, worktree) {
|
|
|
19850
19782
|
if (typeof metadata.diffPreview === "string") {
|
|
19851
19783
|
metadata.diffPreview = truncateMetadataPreview(metadata.diffPreview, input.sessionID);
|
|
19852
19784
|
}
|
|
19785
|
+
if (GBK_TOOL_IDS.has(input.tool)) {
|
|
19786
|
+
rememberSessionGbkToolUsage(input.sessionID);
|
|
19787
|
+
}
|
|
19853
19788
|
if (input.tool === "text_edit" && typeof metadata.filePath === "string") {
|
|
19854
19789
|
rememberSessionTextEditFile(
|
|
19855
19790
|
input.sessionID,
|
|
@@ -19869,9 +19804,6 @@ function createOpencodeGbkHooks(client, directory, worktree) {
|
|
|
19869
19804
|
metadata.estimatedSessionTokens = sessionPressure.estimatedTokens;
|
|
19870
19805
|
metadata.sessionPressureRatio = Number(sessionPressure.pressureRatio.toFixed(3));
|
|
19871
19806
|
}
|
|
19872
|
-
if (autoSummarizeCount > 0) {
|
|
19873
|
-
metadata.autoSummarizeCount = autoSummarizeCount;
|
|
19874
|
-
}
|
|
19875
19807
|
output.metadata = metadata;
|
|
19876
19808
|
},
|
|
19877
19809
|
async "experimental.chat.system.transform"(_input, output) {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifestVersion": 1,
|
|
3
3
|
"packageName": "opencode-gbk-tools",
|
|
4
|
-
"packageVersion": "
|
|
4
|
+
"packageVersion": "1.1.0",
|
|
5
5
|
"artifacts": [
|
|
6
6
|
{
|
|
7
7
|
"relativePath": "plugins/opencode-gbk-tools.js",
|
|
8
8
|
"kind": "plugin",
|
|
9
|
-
"expectedHash": "
|
|
9
|
+
"expectedHash": "1303ca430818ce08f4ef9a6c90b0c96f94f7de000cc50a1b344dbf7d47041ebd",
|
|
10
10
|
"hashAlgorithm": "sha256"
|
|
11
11
|
},
|
|
12
12
|
{
|