oh-my-opencode-cohub 1.17.1 → 1.18.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/README.md +2 -2
- package/dist/cli/config-io.d.ts +2 -2
- package/dist/cli/config-io.d.ts.map +1 -1
- package/dist/cli/index.js +209 -67
- package/dist/config/loader.d.ts +4 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/context/diag-log.d.ts +62 -0
- package/dist/context/diag-log.d.ts.map +1 -0
- package/dist/context/engine.d.ts +33 -0
- package/dist/context/engine.d.ts.map +1 -1
- package/dist/context/extractor.d.ts +1 -20
- package/dist/context/extractor.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +614 -395
- package/dist/index.test.d.ts +2 -0
- package/dist/index.test.d.ts.map +1 -0
- package/dist/instructions/chinese.d.ts +1 -1
- package/dist/instructions/chinese.d.ts.map +1 -1
- package/dist/prompts/council.d.ts +1 -1
- package/dist/prompts/council.d.ts.map +1 -1
- package/dist/prompts/oracle.d.ts +1 -1
- package/dist/prompts/oracle.d.ts.map +1 -1
- package/dist/prompts/orchestrator.d.ts +1 -1
- package/dist/prompts/orchestrator.d.ts.map +1 -1
- package/dist/prompts/rule-app.d.ts +1 -1
- package/dist/prompts/rule-app.d.ts.map +1 -1
- package/dist/prompts/rule-project.d.ts +1 -1
- package/dist/prompts/rule-project.d.ts.map +1 -1
- package/dist/prompts/rule-user.d.ts +1 -1
- package/dist/prompts/rule-user.d.ts.map +1 -1
- package/dist/shared/chinese.d.ts +2 -0
- package/dist/shared/chinese.d.ts.map +1 -0
- package/dist/shared/consensus.d.ts +132 -0
- package/dist/shared/consensus.d.ts.map +1 -0
- package/dist/shared/constants.d.ts +26 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/fs-atomic.d.ts +11 -0
- package/dist/shared/fs-atomic.d.ts.map +1 -0
- package/dist/shared/log.d.ts +38 -0
- package/dist/shared/log.d.ts.map +1 -0
- package/dist/shared/model.d.ts +7 -0
- package/dist/shared/model.d.ts.map +1 -0
- package/dist/shared/token-estimator.d.ts +25 -0
- package/dist/shared/token-estimator.d.ts.map +1 -0
- package/dist/task-manager/tracker.d.ts +22 -7
- package/dist/task-manager/tracker.d.ts.map +1 -1
- package/dist/task-manager/types.d.ts +2 -1
- package/dist/task-manager/types.d.ts.map +1 -1
- package/dist/tools/council.d.ts +2 -66
- package/dist/tools/council.d.ts.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +96 -48
- package/dist/utils/log.d.ts +8 -12
- package/dist/utils/log.d.ts.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
OpenCode 中文智能体编排插件 CoHub——纯调度模式、全中文提示词、编排引擎、上下文共享、规范分析代理、方案制定代理。
|
|
4
4
|
|
|
5
|
-
[](https://github.com/Mr-cjf/cohub)
|
|
6
6
|
|
|
7
7
|
## 特性
|
|
8
8
|
|
|
@@ -259,7 +259,7 @@ bunx oh-my-opencode-cohub uninstall && bun pm cache rm && bunx oh-my-opencode-co
|
|
|
259
259
|
|
|
260
260
|
```bash
|
|
261
261
|
# 1. 克隆项目
|
|
262
|
-
git clone https://github.com/Mr-cjf/
|
|
262
|
+
git clone https://github.com/Mr-cjf/cohub.git && cd cohub/packages/oh-my-opencode-cohub
|
|
263
263
|
|
|
264
264
|
# 2. 安装依赖
|
|
265
265
|
npm install
|
package/dist/cli/config-io.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
/** 添加 CoHub 到 opencode.json 的 plugin
|
|
1
|
+
/** 添加 CoHub 到 opencode.json 的 plugin 数组(宿主配置:解析失败中止 + 写入前备份) */
|
|
2
2
|
export declare function addPluginToOpenCodeConfig(version: string): {
|
|
3
3
|
success: boolean;
|
|
4
4
|
message: string;
|
|
5
5
|
};
|
|
6
|
-
/** 添加 CoHub 到 tui.json 的 plugin
|
|
6
|
+
/** 添加 CoHub 到 tui.json 的 plugin 数组(宿主配置:解析失败中止 + 写入前备份) */
|
|
7
7
|
export declare function addPluginToTuiConfig(): {
|
|
8
8
|
success: boolean;
|
|
9
9
|
message: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config-io.d.ts","sourceRoot":"","sources":["../../src/cli/config-io.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config-io.d.ts","sourceRoot":"","sources":["../../src/cli/config-io.ts"],"names":[],"mappings":"AAiJA,gEAAgE;AAChE,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CA0BhG;AAED,2DAA2D;AAC3D,wBAAgB,oBAAoB,IAAI;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAe5E;AAOD;;wDAEwD;AACxD,wBAAgB,mBAAmB,IAAI;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAwF3E;AA+ED,4DAA4D;AAC5D,wBAAgB,kBAAkB,IAAI;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAuG1E;AAED,8BAA8B;AAC9B,wBAAgB,cAAc,IAAI;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CA2IzE;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CA6BxF"}
|
package/dist/cli/index.js
CHANGED
|
@@ -1,13 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
|
-
import * as
|
|
4
|
+
import * as fs3 from "node:fs";
|
|
5
5
|
|
|
6
6
|
// src/task-manager/tracker.ts
|
|
7
7
|
import * as os from "node:os";
|
|
8
|
+
import * as path2 from "node:path";
|
|
9
|
+
|
|
10
|
+
// src/shared/fs-atomic.ts
|
|
11
|
+
import * as fs from "node:fs";
|
|
8
12
|
import * as path from "node:path";
|
|
13
|
+
function writeFileAtomic(filePath, data) {
|
|
14
|
+
const tmpPath = filePath + ".tmp";
|
|
15
|
+
const dir = path.dirname(filePath);
|
|
16
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
17
|
+
try {
|
|
18
|
+
fs.writeFileSync(tmpPath, data, "utf-8");
|
|
19
|
+
fs.renameSync(tmpPath, filePath);
|
|
20
|
+
} catch (err) {
|
|
21
|
+
try {
|
|
22
|
+
fs.unlinkSync(tmpPath);
|
|
23
|
+
} catch {}
|
|
24
|
+
throw err;
|
|
25
|
+
} finally {
|
|
26
|
+
try {
|
|
27
|
+
if (fs.existsSync(tmpPath))
|
|
28
|
+
fs.unlinkSync(tmpPath);
|
|
29
|
+
} catch {}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function writeJsonFileAtomic(filePath, data) {
|
|
33
|
+
writeFileAtomic(filePath, JSON.stringify(data, null, 2));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/task-manager/tracker.ts
|
|
9
37
|
var DEFAULT_STATS_WINDOW = 50;
|
|
10
|
-
var STATS_FILE =
|
|
38
|
+
var STATS_FILE = path2.join(os.homedir(), ".local", "share", "opencode", "storage", "oh-my-opencode-cohub", "stats.json");
|
|
11
39
|
function computeStats(records, window = DEFAULT_STATS_WINDOW) {
|
|
12
40
|
const recent = records.slice(-Math.max(1, window));
|
|
13
41
|
const buckets = new Map;
|
|
@@ -49,45 +77,154 @@ function computeStats(records, window = DEFAULT_STATS_WINDOW) {
|
|
|
49
77
|
return result;
|
|
50
78
|
}
|
|
51
79
|
// package.json
|
|
52
|
-
var version = "1.
|
|
80
|
+
var version = "1.18.1";
|
|
53
81
|
|
|
54
82
|
// src/cli/config-io.ts
|
|
55
|
-
import * as
|
|
56
|
-
import * as
|
|
83
|
+
import * as fs2 from "node:fs";
|
|
84
|
+
import * as path3 from "node:path";
|
|
57
85
|
import * as os2 from "node:os";
|
|
86
|
+
|
|
87
|
+
// src/shared/constants.ts
|
|
88
|
+
var COUNCIL_TIMEOUT_MS = 180000;
|
|
89
|
+
var STALE_TASK_MS = 30 * 60 * 1000;
|
|
90
|
+
|
|
91
|
+
// src/cli/config-io.ts
|
|
58
92
|
import { execSync } from "node:child_process";
|
|
59
93
|
var PACKAGE_NAME = "oh-my-opencode-cohub";
|
|
60
94
|
function getOpencodeConfigPath() {
|
|
61
|
-
return
|
|
95
|
+
return path3.join(os2.homedir(), ".config", "opencode", "opencode.json");
|
|
62
96
|
}
|
|
63
97
|
function getTuiConfigPath() {
|
|
64
|
-
return
|
|
98
|
+
return path3.join(os2.homedir(), ".config", "opencode", "tui.json");
|
|
99
|
+
}
|
|
100
|
+
function stripJsonc(raw) {
|
|
101
|
+
const out = [];
|
|
102
|
+
let inString = false;
|
|
103
|
+
let escaped = false;
|
|
104
|
+
let pendingComma = -1;
|
|
105
|
+
let i = 0;
|
|
106
|
+
while (i < raw.length) {
|
|
107
|
+
const ch = raw[i];
|
|
108
|
+
if (inString) {
|
|
109
|
+
out.push(ch);
|
|
110
|
+
if (escaped)
|
|
111
|
+
escaped = false;
|
|
112
|
+
else if (ch === "\\")
|
|
113
|
+
escaped = true;
|
|
114
|
+
else if (ch === '"')
|
|
115
|
+
inString = false;
|
|
116
|
+
i++;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (ch === '"') {
|
|
120
|
+
inString = true;
|
|
121
|
+
pendingComma = -1;
|
|
122
|
+
out.push(ch);
|
|
123
|
+
i++;
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (ch === "/" && raw[i + 1] === "/") {
|
|
127
|
+
i += 2;
|
|
128
|
+
while (i < raw.length && raw[i] !== `
|
|
129
|
+
`)
|
|
130
|
+
i++;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (ch === "/" && raw[i + 1] === "*") {
|
|
134
|
+
i += 2;
|
|
135
|
+
while (i < raw.length && !(raw[i] === "*" && raw[i + 1] === "/"))
|
|
136
|
+
i++;
|
|
137
|
+
i += 2;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (ch === ",") {
|
|
141
|
+
pendingComma = out.length;
|
|
142
|
+
out.push(ch);
|
|
143
|
+
i++;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (ch === " " || ch === "\t" || ch === "\r" || ch === `
|
|
147
|
+
`) {
|
|
148
|
+
out.push(ch);
|
|
149
|
+
i++;
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if ((ch === "}" || ch === "]") && pendingComma >= 0) {
|
|
153
|
+
out[pendingComma] = " ";
|
|
154
|
+
}
|
|
155
|
+
pendingComma = -1;
|
|
156
|
+
out.push(ch);
|
|
157
|
+
i++;
|
|
158
|
+
}
|
|
159
|
+
return out.join("");
|
|
65
160
|
}
|
|
66
|
-
function
|
|
161
|
+
function readJsonFile(filePath) {
|
|
162
|
+
let raw;
|
|
67
163
|
try {
|
|
68
|
-
if (!
|
|
69
|
-
return null;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
164
|
+
if (!fs2.existsSync(filePath))
|
|
165
|
+
return { ok: true, value: null };
|
|
166
|
+
raw = fs2.readFileSync(filePath, "utf-8");
|
|
167
|
+
} catch (err) {
|
|
168
|
+
return { ok: false, reason: `读取失败: ${err.message}` };
|
|
169
|
+
}
|
|
170
|
+
if (raw.trim() === "")
|
|
171
|
+
return { ok: true, value: null };
|
|
172
|
+
try {
|
|
173
|
+
const parsed = JSON.parse(raw);
|
|
174
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
175
|
+
return { ok: false, reason: "顶层不是 JSON 对象" };
|
|
75
176
|
}
|
|
76
|
-
|
|
77
|
-
|
|
177
|
+
return { ok: true, value: parsed };
|
|
178
|
+
} catch {}
|
|
179
|
+
try {
|
|
180
|
+
const parsed = JSON.parse(stripJsonc(raw));
|
|
181
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
182
|
+
return { ok: false, reason: "顶层不是 JSON 对象" };
|
|
183
|
+
}
|
|
184
|
+
return { ok: true, value: parsed };
|
|
185
|
+
} catch (err) {
|
|
186
|
+
return { ok: false, reason: err.message };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function readJSONLoose(filePath) {
|
|
190
|
+
const r = readJsonFile(filePath);
|
|
191
|
+
return r.ok ? r.value : null;
|
|
192
|
+
}
|
|
193
|
+
function loadConfigForWrite(filePath, label) {
|
|
194
|
+
const r = readJsonFile(filePath);
|
|
195
|
+
if (!r.ok) {
|
|
196
|
+
return {
|
|
197
|
+
ok: false,
|
|
198
|
+
message: `⚠ 拒绝覆盖 ${label}(JSON 解析失败): ${filePath}
|
|
199
|
+
${r.reason}
|
|
200
|
+
请先修复该文件语法后重新运行;原文件未被修改。`
|
|
201
|
+
};
|
|
78
202
|
}
|
|
203
|
+
return { ok: true, config: r.value ?? {} };
|
|
79
204
|
}
|
|
80
|
-
function
|
|
81
|
-
const
|
|
82
|
-
if (
|
|
83
|
-
|
|
205
|
+
function backupFile(filePath) {
|
|
206
|
+
const bak = filePath + ".bak";
|
|
207
|
+
if (fs2.existsSync(bak))
|
|
208
|
+
return;
|
|
209
|
+
if (fs2.existsSync(filePath))
|
|
210
|
+
fs2.copyFileSync(filePath, bak);
|
|
211
|
+
}
|
|
212
|
+
function writeJSON(filePath, data, opts = {}) {
|
|
213
|
+
const dir = path3.dirname(filePath);
|
|
214
|
+
if (!fs2.existsSync(dir))
|
|
215
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
216
|
+
if (opts.backup !== false)
|
|
217
|
+
backupFile(filePath);
|
|
84
218
|
const content = JSON.stringify(data, null, 2) + `
|
|
85
219
|
`;
|
|
86
|
-
|
|
220
|
+
fs2.writeFileSync(filePath, content, "utf-8");
|
|
87
221
|
}
|
|
88
222
|
function addPluginToOpenCodeConfig(version) {
|
|
89
223
|
const configPath = getOpencodeConfigPath();
|
|
90
|
-
|
|
224
|
+
const loaded = loadConfigForWrite(configPath, "opencode.json");
|
|
225
|
+
if (!loaded.ok)
|
|
226
|
+
return { success: false, message: loaded.message };
|
|
227
|
+
const config = loaded.config;
|
|
91
228
|
const plugins = Array.isArray(config.plugin) ? [...config.plugin] : [];
|
|
92
229
|
const pkgSpec = `${PACKAGE_NAME}@${version}`;
|
|
93
230
|
if (plugins.some((p) => p.includes(PACKAGE_NAME))) {
|
|
@@ -107,7 +244,10 @@ function addPluginToOpenCodeConfig(version) {
|
|
|
107
244
|
}
|
|
108
245
|
function addPluginToTuiConfig() {
|
|
109
246
|
const configPath = getTuiConfigPath();
|
|
110
|
-
|
|
247
|
+
const loaded = loadConfigForWrite(configPath, "tui.json");
|
|
248
|
+
if (!loaded.ok)
|
|
249
|
+
return { success: false, message: loaded.message };
|
|
250
|
+
const config = loaded.config;
|
|
111
251
|
const plugins = Array.isArray(config.plugin) ? [...config.plugin] : [];
|
|
112
252
|
if (plugins.some((p) => p.includes(PACKAGE_NAME))) {
|
|
113
253
|
return { success: true, message: "CoHub 已在 tui.json 的 plugin 数组中,跳过" };
|
|
@@ -118,14 +258,14 @@ function addPluginToTuiConfig() {
|
|
|
118
258
|
return { success: true, message: `✓ 已添加 "${PACKAGE_NAME}" 到 tui.json 的 plugin 数组` };
|
|
119
259
|
}
|
|
120
260
|
function getOhMyConfigPath() {
|
|
121
|
-
return
|
|
261
|
+
return path3.join(os2.homedir(), ".config", "opencode", "oh-my-opencode-slim.json");
|
|
122
262
|
}
|
|
123
263
|
function registerCoHubAgents() {
|
|
124
264
|
const configPath = getOpencodeConfigPath();
|
|
125
|
-
|
|
126
|
-
if (!
|
|
127
|
-
|
|
128
|
-
|
|
265
|
+
const loaded = loadConfigForWrite(configPath, "opencode.json");
|
|
266
|
+
if (!loaded.ok)
|
|
267
|
+
return { success: false, message: loaded.message };
|
|
268
|
+
const config = loaded.config;
|
|
129
269
|
let needUpdate = false;
|
|
130
270
|
const COHUB_BUILTIN_FIELDS = new Set(["description", "mode", "prompt", "permission"]);
|
|
131
271
|
let cleaned = 0;
|
|
@@ -198,8 +338,8 @@ function registerCoHubAgents() {
|
|
|
198
338
|
msgParts.push("Agent 定义已由插件运行时接管(参照 slim 架构)");
|
|
199
339
|
return { success: true, message: `✓ ${msgParts.join(",")}` };
|
|
200
340
|
}
|
|
201
|
-
var COHUB_CONFIG_PATH =
|
|
202
|
-
var PACKAGES_CACHE =
|
|
341
|
+
var COHUB_CONFIG_PATH = path3.join(os2.homedir(), ".config", "opencode", "oh-my-opencode-cohub.json");
|
|
342
|
+
var PACKAGES_CACHE = path3.join(os2.homedir(), ".cache", "opencode", "packages", PACKAGE_NAME);
|
|
203
343
|
var HEAVY_KEYWORDS = ["pro", "preview", "opus", "max", "sonnet", "gpt-5.6"];
|
|
204
344
|
var LIGHT_KEYWORDS = ["flash", "mini", "haiku", "gpt-5.4", "gpt-5.3"];
|
|
205
345
|
var DESIGN_KEYWORDS = ["minimax", "m3", "sonnet", "claude"];
|
|
@@ -231,7 +371,7 @@ function findBestModel(flatModels, keywords, agentType) {
|
|
|
231
371
|
return null;
|
|
232
372
|
}
|
|
233
373
|
function flattenModelsFromOpenCode() {
|
|
234
|
-
const opencodeConfig =
|
|
374
|
+
const opencodeConfig = readJSONLoose(getOpencodeConfigPath());
|
|
235
375
|
if (!opencodeConfig)
|
|
236
376
|
return [];
|
|
237
377
|
const providerRecord = opencodeConfig?.config;
|
|
@@ -253,7 +393,7 @@ function flattenModelsFromOpenCode() {
|
|
|
253
393
|
return result;
|
|
254
394
|
}
|
|
255
395
|
function writeDefaultConfig() {
|
|
256
|
-
if (
|
|
396
|
+
if (fs2.existsSync(COHUB_CONFIG_PATH)) {
|
|
257
397
|
return { success: true, message: "oh-my-opencode-cohub.json 已存在,跳过" };
|
|
258
398
|
}
|
|
259
399
|
const flatModels = flattenModelsFromOpenCode();
|
|
@@ -265,10 +405,7 @@ function writeDefaultConfig() {
|
|
|
265
405
|
_comment: "未找到可用供应商。请在 opencode.json 中配置 provider 后重新运行 install,或手动在此文件中配置 model 和 variant。"
|
|
266
406
|
};
|
|
267
407
|
try {
|
|
268
|
-
|
|
269
|
-
if (!fs.existsSync(dir))
|
|
270
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
271
|
-
fs.writeFileSync(COHUB_CONFIG_PATH, JSON.stringify(fallbackConfig, null, 2), "utf-8");
|
|
408
|
+
writeJsonFileAtomic(COHUB_CONFIG_PATH, fallbackConfig);
|
|
272
409
|
return { success: true, message: "✓ 已创建 oh-my-opencode-cohub.json(无可用 provider,请手动配置模型)" };
|
|
273
410
|
} catch {
|
|
274
411
|
return { success: false, message: "⚠ 无法创建配置文件" };
|
|
@@ -334,7 +471,7 @@ function writeDefaultConfig() {
|
|
|
334
471
|
agents,
|
|
335
472
|
council: councilCount > 0 ? {
|
|
336
473
|
default_preset: "default",
|
|
337
|
-
timeout:
|
|
474
|
+
timeout: COUNCIL_TIMEOUT_MS,
|
|
338
475
|
councillor_execution_mode: "parallel",
|
|
339
476
|
councillor_retries: 3,
|
|
340
477
|
presets: {
|
|
@@ -343,10 +480,7 @@ function writeDefaultConfig() {
|
|
|
343
480
|
} : { presets: {} }
|
|
344
481
|
};
|
|
345
482
|
try {
|
|
346
|
-
|
|
347
|
-
if (!fs.existsSync(dir))
|
|
348
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
349
|
-
fs.writeFileSync(COHUB_CONFIG_PATH, JSON.stringify(defaultConfig, null, 2), "utf-8");
|
|
483
|
+
writeJsonFileAtomic(COHUB_CONFIG_PATH, defaultConfig);
|
|
350
484
|
return { success: true, message: `✓ 已智能匹配 ${matched}/12 个代理的模型,生成 oh-my-opencode-cohub.json` };
|
|
351
485
|
} catch {
|
|
352
486
|
return { success: false, message: "⚠ 无法创建配置文件" };
|
|
@@ -355,8 +489,9 @@ function writeDefaultConfig() {
|
|
|
355
489
|
function uninstallCoHub() {
|
|
356
490
|
const messages = [];
|
|
357
491
|
const configPath = getOpencodeConfigPath();
|
|
358
|
-
let config =
|
|
359
|
-
|
|
492
|
+
let config = readJSONLoose(configPath);
|
|
493
|
+
const configReadable = readJsonFile(configPath).ok;
|
|
494
|
+
if (config && configReadable) {
|
|
360
495
|
const plugins = Array.isArray(config.plugin) ? [...config.plugin] : [];
|
|
361
496
|
const before = plugins.length;
|
|
362
497
|
const filtered = plugins.filter((p) => {
|
|
@@ -386,13 +521,16 @@ function uninstallCoHub() {
|
|
|
386
521
|
}
|
|
387
522
|
}
|
|
388
523
|
writeJSON(configPath, config);
|
|
524
|
+
} else if (!configReadable) {
|
|
525
|
+
messages.push(`⚠ opencode.json 解析失败,已跳过(原文件未被覆盖): ${configPath}`);
|
|
389
526
|
} else {
|
|
390
527
|
messages.push("⚠ opencode.json 不存在,跳过");
|
|
391
528
|
}
|
|
392
529
|
const tuiPath = getTuiConfigPath();
|
|
393
|
-
if (
|
|
394
|
-
const
|
|
395
|
-
|
|
530
|
+
if (fs2.existsSync(tuiPath)) {
|
|
531
|
+
const tuiReadable = readJsonFile(tuiPath).ok;
|
|
532
|
+
const tuiConfig = readJSONLoose(tuiPath);
|
|
533
|
+
if (tuiConfig && tuiReadable) {
|
|
396
534
|
const tuiPlugins = Array.isArray(tuiConfig.plugin) ? [...tuiConfig.plugin] : [];
|
|
397
535
|
const before = tuiPlugins.length;
|
|
398
536
|
const filtered = tuiPlugins.filter((p) => {
|
|
@@ -406,12 +544,15 @@ function uninstallCoHub() {
|
|
|
406
544
|
writeJSON(tuiPath, tuiConfig);
|
|
407
545
|
messages.push("✓ 已从 tui.json 的 plugin 数组移除 CoHub");
|
|
408
546
|
}
|
|
547
|
+
} else if (!tuiReadable) {
|
|
548
|
+
messages.push(`⚠ tui.json 解析失败,已跳过(原文件未被覆盖): ${tuiPath}`);
|
|
409
549
|
}
|
|
410
550
|
}
|
|
411
|
-
const tuiStatePath =
|
|
412
|
-
if (
|
|
413
|
-
|
|
414
|
-
|
|
551
|
+
const tuiStatePath = path3.join(os2.homedir(), ".local", "share", "opencode", "storage", "oh-my-opencode-slim", "tui-state.json");
|
|
552
|
+
if (fs2.existsSync(tuiStatePath)) {
|
|
553
|
+
const tuiStateReadable = readJsonFile(tuiStatePath).ok;
|
|
554
|
+
let tuiState = readJSONLoose(tuiStatePath);
|
|
555
|
+
if (tuiState && tuiStateReadable) {
|
|
415
556
|
let cleaned = false;
|
|
416
557
|
if (tuiState.agentModels && typeof tuiState.agentModels === "object") {
|
|
417
558
|
const models = tuiState.agentModels;
|
|
@@ -438,9 +579,10 @@ function uninstallCoHub() {
|
|
|
438
579
|
}
|
|
439
580
|
}
|
|
440
581
|
const ohMyPath = getOhMyConfigPath();
|
|
441
|
-
if (
|
|
442
|
-
|
|
443
|
-
|
|
582
|
+
if (fs2.existsSync(ohMyPath)) {
|
|
583
|
+
const ohMyReadable = readJsonFile(ohMyPath).ok;
|
|
584
|
+
let ohMyConfig = readJSONLoose(ohMyPath);
|
|
585
|
+
if (ohMyConfig && ohMyReadable && ohMyConfig.agents && typeof ohMyConfig.agents === "object") {
|
|
444
586
|
let cleanedOhMy = false;
|
|
445
587
|
const agents = ohMyConfig.agents;
|
|
446
588
|
for (const key of Object.keys(agents)) {
|
|
@@ -455,18 +597,18 @@ function uninstallCoHub() {
|
|
|
455
597
|
}
|
|
456
598
|
}
|
|
457
599
|
}
|
|
458
|
-
if (
|
|
600
|
+
if (fs2.existsSync(PACKAGES_CACHE)) {
|
|
459
601
|
try {
|
|
460
|
-
|
|
602
|
+
fs2.rmSync(PACKAGES_CACHE, { recursive: true, force: true });
|
|
461
603
|
messages.push("✓ 已清理缓存目录");
|
|
462
604
|
} catch {
|
|
463
605
|
messages.push("⚠ 清理缓存目录失败,请手动删除: " + PACKAGES_CACHE);
|
|
464
606
|
}
|
|
465
607
|
}
|
|
466
|
-
const legacyPluginsDir =
|
|
467
|
-
if (
|
|
608
|
+
const legacyPluginsDir = path3.join(os2.homedir(), ".config", "opencode", "plugins", PACKAGE_NAME);
|
|
609
|
+
if (fs2.existsSync(legacyPluginsDir)) {
|
|
468
610
|
try {
|
|
469
|
-
|
|
611
|
+
fs2.rmSync(legacyPluginsDir, { recursive: true, force: true });
|
|
470
612
|
messages.push("✓ 已清理旧 plugins 目录");
|
|
471
613
|
} catch {}
|
|
472
614
|
}
|
|
@@ -476,17 +618,17 @@ function uninstallCoHub() {
|
|
|
476
618
|
function installToCacheDir(version) {
|
|
477
619
|
try {
|
|
478
620
|
const targetDir = PACKAGES_CACHE;
|
|
479
|
-
if (
|
|
480
|
-
|
|
621
|
+
if (fs2.existsSync(targetDir)) {
|
|
622
|
+
fs2.rmSync(targetDir, { recursive: true, force: true });
|
|
481
623
|
}
|
|
482
|
-
|
|
624
|
+
fs2.mkdirSync(targetDir, { recursive: true });
|
|
483
625
|
const pkgJson = { private: true };
|
|
484
|
-
|
|
626
|
+
writeJsonFileAtomic(path3.join(targetDir, "package.json"), pkgJson);
|
|
485
627
|
const pkgSpec = `${PACKAGE_NAME}@${version}`;
|
|
486
628
|
const cmd = `npm install "${pkgSpec}" --save --legacy-peer-deps`;
|
|
487
629
|
execSync(cmd, { cwd: targetDir, stdio: "pipe", timeout: 120000 });
|
|
488
|
-
const entryPath =
|
|
489
|
-
if (!
|
|
630
|
+
const entryPath = path3.join(targetDir, "node_modules", PACKAGE_NAME, "dist", "index.js");
|
|
631
|
+
if (!fs2.existsSync(entryPath)) {
|
|
490
632
|
return { success: false, message: `⚠ npm install 成功但入口文件缺失: ${entryPath}` };
|
|
491
633
|
}
|
|
492
634
|
return { success: true, message: `✓ 已安装 ${pkgSpec} 到 ${targetDir}` };
|
|
@@ -669,8 +811,8 @@ function printStats(window) {
|
|
|
669
811
|
`);
|
|
670
812
|
let records = [];
|
|
671
813
|
try {
|
|
672
|
-
if (
|
|
673
|
-
const raw = JSON.parse(
|
|
814
|
+
if (fs3.existsSync(STATS_FILE)) {
|
|
815
|
+
const raw = JSON.parse(fs3.readFileSync(STATS_FILE, "utf8"));
|
|
674
816
|
records = computeStats(raw, window);
|
|
675
817
|
}
|
|
676
818
|
} catch {
|
package/dist/config/loader.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import type { QualityConfig } from '../task-manager/quality';
|
|
|
3
3
|
import { DEFAULT_CONTEXT_CONFIG } from '../context/types';
|
|
4
4
|
import type { CouncilConfig, CouncilPreset, CouncillorConfig } from '../tools/council';
|
|
5
5
|
export type { CouncilConfig, CouncilPreset, CouncillorConfig };
|
|
6
|
+
import type { CtxDiagConfig } from '../context/diag-log';
|
|
7
|
+
export type { CtxDiagConfig };
|
|
6
8
|
/** 用户配置中单个代理的覆盖项 */
|
|
7
9
|
export interface AgentOverride {
|
|
8
10
|
model?: string;
|
|
@@ -15,6 +17,8 @@ export interface CoHubConfig {
|
|
|
15
17
|
context?: Partial<ContextConfig>;
|
|
16
18
|
/** 质量回送配置(P0-1 负反馈闭环,默认开启) */
|
|
17
19
|
quality?: Partial<QualityConfig>;
|
|
20
|
+
/** 诊断日志配置(默认全部关闭:ctx-diag opt-in;新增字段,旧配置缺省即安全) */
|
|
21
|
+
diag?: CtxDiagConfig;
|
|
18
22
|
}
|
|
19
23
|
/** 加载用户配置(项目级优先覆盖用户级) */
|
|
20
24
|
export declare function loadCoHubConfig(projectDir?: string): CoHubConfig;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAI1D,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACvF,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAI1D,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACvF,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B,oBAAoB;AACpB,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACvC,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACjC,8BAA8B;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACjC,mDAAmD;IACnD,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB;AAKD,yBAAyB;AACzB,wBAAgB,eAAe,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,CA0BhE;AAYD,OAAO,EAAE,sBAAsB,EAAE,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 上下文注入诊断日志(opt-in,**默认关闭**)。
|
|
3
|
+
*
|
|
4
|
+
* 用途:排查「CoHub 注入的上下文是否真的到达了子代理」。
|
|
5
|
+
* 历史(见 CHANGELOG 1.4.0 / 1.5.1):曾连续出现「上下文未注入 / 详情未追加 /
|
|
6
|
+
* 写入 description 而非 prompt」等 bug,该日志就是当时的排查手段,因此**保留字段与
|
|
7
|
+
* 默认路径不变**,只把「每次委派无条件同步写盘」改成「显式开启后才写」。
|
|
8
|
+
*
|
|
9
|
+
* 开启方式(任一即可):
|
|
10
|
+
* 1. 环境变量 `COHUB_CTX_DIAG=1`(`=0` 可强制关闭,优先级最高)
|
|
11
|
+
* 2. 用户配置 `~/.config/opencode/oh-my-opencode-cohub.json` → `{ "diag": { "enabled": true } }`
|
|
12
|
+
* 或项目配置 `.opencode/oh-my-opencode-cohub.json` → 同上
|
|
13
|
+
*
|
|
14
|
+
* 设计要点(对比旧实现):
|
|
15
|
+
* - 旧:每次委派 = statSync + appendFileSync(同步阻塞事件循环),
|
|
16
|
+
* 且「超 50KB → 读全文 → 重写末 30 行 → 立刻又 append」形成**反复全量读+全量写**的循环。
|
|
17
|
+
* - 新:关闭时不产生任何 I/O;开启时用**异步串行队列** appendFile(不阻塞事件循环),
|
|
18
|
+
* 仅在「自上次压缩以来累计写入 > MAX_BYTES」时触发一次压缩,且压缩**只读文件尾部窗口**
|
|
19
|
+
* (不读全文),压缩后计数器归零 → 需要再累积 MAX_BYTES 才会再次压缩,循环被消除。
|
|
20
|
+
* - 文件创建时使用 mode 0o600(POSIX 收紧权限;Windows 上为 no-op)。
|
|
21
|
+
*/
|
|
22
|
+
/** 诊断日志配置(全部可选,缺省即安全) */
|
|
23
|
+
export interface CtxDiagConfig {
|
|
24
|
+
/** 是否开启上下文注入诊断日志(默认 false) */
|
|
25
|
+
enabled?: boolean;
|
|
26
|
+
/** 自定义日志文件路径(默认 os.tmpdir()/opencode/ctx-diag.log,保持历史路径不变) */
|
|
27
|
+
path?: string;
|
|
28
|
+
}
|
|
29
|
+
/** 缺省配置:关闭。热路径零开销是缺省行为。 */
|
|
30
|
+
export declare const DEFAULT_CTX_DIAG_CONFIG: Required<Omit<CtxDiagConfig, 'path'>>;
|
|
31
|
+
/** 解析后的诊断设置(在插件初始化时求值一次,热路径只读常量) */
|
|
32
|
+
export interface CtxDiagSettings {
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
filePath: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 是否开启诊断日志。
|
|
38
|
+
* 优先级:环境变量(1/true 开,0/false 关)> 配置 > 缺省(关)。
|
|
39
|
+
*/
|
|
40
|
+
export declare function isCtxDiagEnabled(config?: Partial<CtxDiagConfig> | null, env?: string): boolean;
|
|
41
|
+
/** 诊断日志文件路径(默认保持历史 tmpdir 路径,可被配置覆盖) */
|
|
42
|
+
export declare function resolveCtxDiagPath(config?: Partial<CtxDiagConfig> | null): string;
|
|
43
|
+
/** 一次性解析设置(插件初始化时调用,避免热路径重复读 process.env) */
|
|
44
|
+
export declare function resolveCtxDiagSettings(config?: Partial<CtxDiagConfig> | null, env?: NodeJS.ProcessEnv): CtxDiagSettings;
|
|
45
|
+
/**
|
|
46
|
+
* 追加一条诊断记录(异步,失败静默)。
|
|
47
|
+
* 调用方应先判断 `settings.enabled`;本函数自身不做开关判断,便于复用。
|
|
48
|
+
*/
|
|
49
|
+
export declare function appendCtxDiag(record: unknown, filePath: string): void;
|
|
50
|
+
/** 测试/诊断辅助:等待队列落盘 */
|
|
51
|
+
export declare function flushCtxDiag(): Promise<void>;
|
|
52
|
+
/** 测试辅助:重置进程内计数器 */
|
|
53
|
+
export declare function __resetCtxDiagState(): void;
|
|
54
|
+
/** 供测试断言用的常量导出 */
|
|
55
|
+
export declare const CTX_DIAG_LIMITS: {
|
|
56
|
+
readonly MAX_BYTES: number;
|
|
57
|
+
readonly KEEP_LINES: 30;
|
|
58
|
+
readonly TAIL_WINDOW: number;
|
|
59
|
+
};
|
|
60
|
+
/** 诊断日志目录(供排查指引使用) */
|
|
61
|
+
export declare function ctxDiagDir(filePath?: string): string;
|
|
62
|
+
//# sourceMappingURL=diag-log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diag-log.d.ts","sourceRoot":"","sources":["../../src/context/diag-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAeH,yBAAyB;AACzB,MAAM,WAAW,aAAa;IAC5B,8BAA8B;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,2BAA2B;AAC3B,eAAO,MAAM,uBAAuB,EAAE,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,CAEzE,CAAC;AAEF,oCAAoC;AACpC,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAQ9F;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,GAAG,MAAM,CAIjF;AAED,6CAA6C;AAC7C,wBAAgB,sBAAsB,CACpC,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,IAAI,EACtC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,GACtB,eAAe,CAKjB;AA8CD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAgBrE;AAED,qBAAqB;AACrB,wBAAgB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAE5C;AAED,oBAAoB;AACpB,wBAAgB,mBAAmB,IAAI,IAAI,CAG1C;AAED,kBAAkB;AAClB,eAAO,MAAM,eAAe;;;;CAAkD,CAAC;AAE/E,sBAAsB;AACtB,wBAAgB,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpD"}
|
package/dist/context/engine.d.ts
CHANGED
|
@@ -4,6 +4,14 @@ type SdkClient = ReturnType<typeof createOpencodeClient>;
|
|
|
4
4
|
export declare class ContextEngine {
|
|
5
5
|
/** contextId → TaskContext */
|
|
6
6
|
private registry;
|
|
7
|
+
/**
|
|
8
|
+
* contextId → 最后一次被读写的时间戳(ms)。
|
|
9
|
+
* registry 的唯二读取者是 `formatContextDetails()`(index.ts 注入详情)与
|
|
10
|
+
* `consumeMarkedContext()`(消息标记替换);两者都会刷新本时间戳。
|
|
11
|
+
* 定时清理据此判断条目是否已「过期未被合法消费」——
|
|
12
|
+
* 时间戳只在读写时更新,因此不会误删仍在被后续读取的条目。
|
|
13
|
+
*/
|
|
14
|
+
private registryTouchedAt;
|
|
7
15
|
/** alias → 前置子代理结果 */
|
|
8
16
|
private dependencyCache;
|
|
9
17
|
/**
|
|
@@ -70,6 +78,31 @@ export declare class ContextEngine {
|
|
|
70
78
|
* 清理过期的依赖缓存(超过 10 分钟的条目)。
|
|
71
79
|
*/
|
|
72
80
|
cleanupStaleDependencies(maxAgeMs?: number): void;
|
|
81
|
+
/** 刷新 registry 条目的「最后读写时间」(内部使用) */
|
|
82
|
+
private touch;
|
|
83
|
+
/**
|
|
84
|
+
* 显式释放一个已消费完的上下文(供调用方在注入完成后主动回收)。
|
|
85
|
+
* 未注册的 contextId 为无害 no-op。
|
|
86
|
+
*/
|
|
87
|
+
releaseContext(contextId: string): void;
|
|
88
|
+
/**
|
|
89
|
+
* 清理长期未被读写的 registry 条目(默认 20 分钟)。
|
|
90
|
+
*
|
|
91
|
+
* 背景:`registry` 的唯一删除点原本在 `consumeMarkedContext()` 内,而该方法全仓库零调用
|
|
92
|
+
* (真实注入路径是 `formatContextDetails()`),于是每次委派都新增一条 TaskContext 且永不回收。
|
|
93
|
+
*
|
|
94
|
+
* 为何用「最后读写时间」而非 `createdAt`:TaskContext 类型上没有任何时间字段
|
|
95
|
+
* (见 `context/types.ts`),故另开 `registryTouchedAt` 侧表记录;且清理**不能早于消费**——
|
|
96
|
+
* 时间戳在 `fillContextAsync` 结束时刷新、并在每次 `formatContextDetails()` / `consumeMarkedContext()`
|
|
97
|
+
* 读取时刷新,因此仍会被读取的条目不会因登记时间久远而被误删。
|
|
98
|
+
* 阈值取 20 分钟(两倍于依赖缓存 TTL):一次委派从登记到注入详情是秒级,
|
|
99
|
+
* 20 分钟已远超任何合法读写窗口,仅回收真正的泄漏。
|
|
100
|
+
*
|
|
101
|
+
* @returns 被回收的条目数
|
|
102
|
+
*/
|
|
103
|
+
cleanupStaleContexts(maxAgeMs?: number): number;
|
|
104
|
+
/** 当前 registry 条目数(诊断/测试用,只读) */
|
|
105
|
+
get registrySize(): number;
|
|
73
106
|
}
|
|
74
107
|
export {};
|
|
75
108
|
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/context/engine.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAe,aAAa,EAAkC,MAAM,SAAS,CAAC;AAK3G,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE7D,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAEzD,qBAAa,aAAa;IACxB,8BAA8B;IAC9B,OAAO,CAAC,QAAQ,CAAkC;IAClD,sBAAsB;IACtB,OAAO,CAAC,eAAe,CAAuC;IAC9D;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAgG;IAChH,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC;IAU9D;;;OAGG;IACH,eAAe,CAAC,IAAI,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/context/engine.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAe,aAAa,EAAkC,MAAM,SAAS,CAAC;AAK3G,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAE7D,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAEzD,qBAAa,aAAa;IACxB,8BAA8B;IAC9B,OAAO,CAAC,QAAQ,CAAkC;IAClD;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB,CAA6B;IACtD,sBAAsB;IACtB,OAAO,CAAC,eAAe,CAAuC;IAC9D;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAgG;IAChH,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,MAAM,CAAgB;gBAElB,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC;IAU9D;;;OAGG;IACH,eAAe,CAAC,IAAI,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;IAatD;;OAEG;IACG,gBAAgB,CACpB,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,EACvB,IAAI,EAAE;QAAE,QAAQ,EAAE,eAAe,CAAA;KAAE,GAClC,OAAO,CAAC,IAAI,CAAC;IA8DhB;;;OAGG;IACH,OAAO,CAAC,qBAAqB;IAa7B;;;;OAIG;IACH,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAmBxD;;;OAGG;IACH,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAmE/C;;;;;OAKG;IACG,aAAa,CACjB,cAAc,EAAE,MAAM,EACtB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,GAAG,IAAI,CAAC;IAqDpG;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAIvC;;OAEG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,eAAe;IAI/C;;OAEG;IACH,wBAAwB,CAAC,QAAQ,GAAE,MAAuB,GAAG,IAAI;IASjE,oCAAoC;IACpC,OAAO,CAAC,KAAK;IAIb;;;OAGG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKvC;;;;;;;;;;;;;;OAcG;IACH,oBAAoB,CAAC,QAAQ,GAAE,MAAuB,GAAG,MAAM;IAmB/D,iCAAiC;IACjC,IAAI,YAAY,IAAI,MAAM,CAEzB;CACF"}
|
|
@@ -32,24 +32,5 @@ export declare function extractDecisions(messages: SdkMessage[], maxDecisions: n
|
|
|
32
32
|
* 从 bash 输出中提取编译/测试错误。
|
|
33
33
|
*/
|
|
34
34
|
export declare function extractErrors(messages: SdkMessage[], maxErrors: number, windowSize: number): string[];
|
|
35
|
-
|
|
36
|
-
* 估算文本的 token 数。
|
|
37
|
-
* 中文字符(CJK 及东亚表意区)按 1 token/字符,其余字符按 0.25 token/字符。
|
|
38
|
-
*/
|
|
39
|
-
export declare function estimateTokens(text: string): number;
|
|
40
|
-
/**
|
|
41
|
-
* 强制 prompt 预算约束。
|
|
42
|
-
* 若 full 的估算 token 数 ≤ maxTokens → 返回 full(完整保留);
|
|
43
|
-
* 否则 → 返回 base(丢弃全部 CoHub 注入后缀,只保留用户原始 prompt)。
|
|
44
|
-
*/
|
|
45
|
-
export declare function enforcePromptBudget(base: string, full: string, maxTokens: number): string;
|
|
46
|
-
/**
|
|
47
|
-
* 按 token 预算截断文本。
|
|
48
|
-
* P2-5: 估算规则区分中西文——中文字符(CJK 及东亚表意区)按 1 token/字符,
|
|
49
|
-
* 其余字符按 4 字符 ≈ 1 token(原统一 4 字符/token 对中文低估 2-4 倍)。
|
|
50
|
-
* 仅用于 summary 策略下文件正文裁剪;空文本或 maxTokens<=0 返回空串;
|
|
51
|
-
* 未超预算时原样返回,超预算时保留头部并在末尾追加省略标记。
|
|
52
|
-
*/
|
|
53
|
-
export declare function truncateByTokens(text: string, maxTokens: number): string;
|
|
54
|
-
export {};
|
|
35
|
+
export { estimateTokens, enforcePromptBudget, truncateByTokens } from '../shared/token-estimator';
|
|
55
36
|
//# sourceMappingURL=extractor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/context/extractor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAuB5C,yBAAyB;AACzB,UAAU,OAAO;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE;QACN,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,sBAAsB;AACtB,UAAU,UAAU;IAClB,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzB,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,UAAU,EAAE,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,YAAY,EAAE,CAmGhB;AAUD;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,UAAU,EAAE,EACtB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CAqBV;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,UAAU,EAAE,EACtB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CAwBV;
|
|
1
|
+
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/context/extractor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAuB5C,yBAAyB;AACzB,UAAU,OAAO;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE;QACN,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAED,sBAAsB;AACtB,UAAU,UAAU;IAClB,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzB,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,UAAU,EAAE,EACtB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,YAAY,EAAE,CAmGhB;AAUD;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,UAAU,EAAE,EACtB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CAqBV;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,UAAU,EAAE,EACtB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CAwBV;AAID,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC"}
|