@lexwdex-org/opencode-dcp 4.0.0 → 5.0.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.en.md CHANGED
@@ -21,7 +21,7 @@ The host fires `experimental.chat.messages.transform` before every model request
21
21
 
22
22
  - **T tail zone**: the last `dtc.tailTurns` (default 4) conversation turns are **never folded**.
23
23
  - **C current-task zone**: turns since the latest topic boundary (lexical drift detection); only oversized tool outputs are head+tail truncated, task details survive.
24
- - **M middle zone**: long texts keep their first line; tool outputs get the host's native fold marker (rendered by the host as its own `[Old tool result content cleared]`); reasoning is emptied.
24
+ - **M middle zone**: long texts keep their first line; tool outputs get the host's native fold marker (rendered by the host as its own `[Old tool result content cleared]`); **tool arguments reduce to a target skeleton** (only filePath / command first line and friends — `oldString`/`newString`/`content` payloads are dropped); **failed attempts (error parts) fold to a short first line** — three edits on one file with two failures collapse to three recognizable call skeletons plus two single-line errors, with the final state owned by disk and the current-task zone; reasoning is emptied.
25
25
  - **D distant zone**: whole turns collapse into one mechanical digest line (intent / actions / files touched / outcome / error count) and tool inputs are cleared — hard facts live on in the digest.
26
26
 
27
27
  **Dynamic budget**: below `lowWatermarkRatio` of the context window (default 50%) **nothing is folded at all** — short sessions pay zero cost. Above it, folding escalates D→M→C from the far end until the estimate fits `targetRatio` (default 70%). The window size is learned per session from the `chat.params` hook; until it is known the engine fails open (no folding).
@@ -38,7 +38,7 @@ The host fires `experimental.chat.messages.transform` before every model request
38
38
  - **The `dcp_prune` model tool**: returns instantly. Marks a topic boundary (the current-task zone restarts at the next turn) and raises this session's minimum fold level to M — old-task content folds from the next request onward. Never interrupts the running turn.
39
39
  - **`/dcp fold`**: manual variant; raises the minimum fold level to the deepest tier.
40
40
  - **`/dcp status`**: shows turns, token estimate, context window, and the manual fold level for the session.
41
- - **The host's own compaction** (`/compact`, context-overflow fallback): unaffected by DTC and still fully functional. DCP continues to supply the high-quality semantic checkpoint prompt (rolling merge of the previous checkpoint, tiered compression depth, fixed four-section structure) and raises the host's tail protection defaults to 4 turns / 32000 tokens (`compaction.tail_turns` / `preserve_recent_tokens`; explicit user config always wins). When the compaction input passes through the transform hook, DTC skips it via a one-shot flag so the summarizer sees full-fidelity content.
41
+ - **The host's own compaction** (`/compact`, context-overflow fallback): **100% native behavior** the host's anchored-summary prompt and its own previous-checkpoint rolling merge stay fully in charge; DCP replaces nothing. DCP contributes exactly two things: it raises the host's tail-protection defaults to 4 turns / 32000 tokens (`compaction.tail_turns` / `preserve_recent_tokens`; explicit user config always wins), and DTC skips the compaction input via a one-shot flag so the summarizer sees full-fidelity content.
42
42
 
43
43
  ## Install
44
44
 
@@ -60,13 +60,9 @@ DCP reads these layers in order; later layers override earlier ones:
60
60
  "enabled": true,
61
61
  "autoUpdate": true,
62
62
  "debug": false,
63
- "language": "en",
64
63
  "commands": {
65
64
  "enabled": true,
66
65
  },
67
- "experimental": {
68
- "customPrompts": false,
69
- },
70
66
  "dtc": {
71
67
  "enabled": true,
72
68
  "tailTurns": 4,
@@ -83,7 +79,6 @@ DCP reads these layers in order; later layers override earlier ones:
83
79
 
84
80
  | Key | Description |
85
81
  | ------------------------- | ---------------------------------------------------------------------------------------------------------- |
86
- | `language` | Bundled compaction prompt language: `zh` (default) / `en`; custom overrides always win |
87
82
  | `dtc.enabled` | Master switch for dynamic tiered request-time compression |
88
83
  | `dtc.tailTurns` | Turns at the end that are never folded (default 4) |
89
84
  | `dtc.lowWatermarkRatio` | No folding below window × ratio (default 0.5) |
@@ -92,18 +87,11 @@ DCP reads these layers in order; later layers override earlier ones:
92
87
  | `dtc.toolOutputKeepChars` | Head+tail characters kept for oversized current-zone tool outputs (default 4000) |
93
88
  | `tool.enabled` | Register the model-invokable `dcp_prune` tool (instant boundary mark, never interrupts) |
94
89
 
95
- With `experimental.customPrompts` enabled, copy the generated
96
- `~/.config/opencode/dcp-prompts/defaults/compaction.md` to any override location:
97
-
98
- - Project: `.opencode/dcp-prompts/overrides/compaction.md`
99
- - Custom config dir: `$OPENCODE_CONFIG_DIR/dcp-prompts/overrides/compaction.md`
100
- - Global: `~/.config/opencode/dcp-prompts/overrides/compaction.md`
101
-
102
- ## Migrating from 3.x
90
+ ## Migrating from 3.x / 4.0
103
91
 
104
- The 3.x `summarize` and `autoPrune` config blocks are gone (DCP no longer calls native summarize and has no heuristic triggers); such keys produce a migration warning and are ignored. `autoPrune.driftThreshold` migrates automatically to `dtc.driftThreshold`. Older `compress`, `manualMode`, `strategies`, `turnProtection` keys remain removed.
92
+ The 3.x `summarize` and `autoPrune` config blocks are gone (DCP no longer calls native summarize and has no heuristic triggers); since 4.1 `language` and `experimental.customPrompts` are gone as well — DCP no longer replaces the host's compaction prompt, so the `dcp-prompts` override machinery retired with it. Such keys produce a migration warning and are ignored. `autoPrune.driftThreshold` migrates automatically to `dtc.driftThreshold`. Older `compress`, `manualMode`, `strategies`, `turnProtection` keys remain removed.
105
93
 
106
- Behavior change: compression no longer produces a visible "checkpoint turn" and needs no at-rest boundaries or continuation machinery — context folds automatically inside each request, invisible to the session and its state machine. Semantic checkpoints are still produced by the host's own compaction (manual `/compact` or the overflow fallback), for which DCP continues to provide the prompt and tail-protection defaults.
94
+ Behavior change: compression no longer produces a visible "checkpoint turn" and needs no at-rest boundaries or continuation machinery — context folds automatically inside each request, invisible to the session and its state machine. Semantic checkpoints are fully handed back to the host's native compaction (manual `/compact` or the overflow fallback): native prompt, native rolling merge — DCP only contributes the tail-protection defaults and full-fidelity protection of the summarizer input.
107
95
 
108
96
  ## Development
109
97
 
package/README.md CHANGED
@@ -21,7 +21,7 @@ DCP 以**动态分级请求期压缩(DTC)**管理 OpenCode 会话上下文
21
21
 
22
22
  - **T 尾部保护区**:最后 `dtc.tailTurns`(默认 4)轮对话**完全不折叠**。
23
23
  - **C 当前任务区**:自最近话题边界(词面漂移检测)以来的轮次,只把超长 tool 输出做首尾截断,任务细节不丢。
24
- - **M 中距离区**:长文本保留首行;tool 输出打宿主原生折叠标记(渲染为宿主自己的 `[Old tool result content cleared]`);推理内容清空。
24
+ - **M 中距离区**:长文本保留首行;tool 输出打宿主原生折叠标记(渲染为宿主自己的 `[Old tool result content cleared]`);**tool 参数规约为目标骨架**(仅留 filePath/command 首行等,`oldString`/`newString`/`content` 等载荷全部丢弃);**失败尝试(error part)折为短首行**——同一文件连改 3 次错 2 次,折叠后只剩 3 个可辨识调用骨架 + 2 条单行错误,最终状态以磁盘与当前任务区为准;推理内容清空。
25
25
  - **D 远距离区**:整轮塌缩为一行机械摘要(意图 / 动作 / 涉及文件 / 结果 / 错误数),tool 参数一并清空——硬事实保留在摘要里。
26
26
 
27
27
  **动态预算**:估算低于上下文窗口的 `lowWatermarkRatio`(默认 50%)时**完全不折叠**,短会话零开销;超出则按 D→M→C 从远到近逐级加深,直到估算落回 `targetRatio`(默认 70%)以内。窗口大小由 `chat.params` 钩子按会话自动学习,未知时 fail-open 不折叠。
@@ -38,7 +38,7 @@ DCP 以**动态分级请求期压缩(DTC)**管理 OpenCode 会话上下文
38
38
  - **模型调用 `dcp_prune` 工具**:瞬时返回。标记话题边界(当前任务区从下一轮重算)并把本会话折叠下限提到 M 级——旧任务内容从下一次请求起被折叠。绝不打断当前工作。
39
39
  - **`/dcp fold`**:手动版本,直接把折叠下限提到最深档。
40
40
  - **`/dcp status`**:查看当前会话的轮数、token 估算、窗口与降级档位。
41
- - **宿主自身的 compaction**(`/compact`、上下文溢出兜底):不受 DTC 影响照常工作;DCP 仍为其提供高质量语义检查点提示词(滚动合并上一份检查点、三层压缩深度、四段固定结构),并把宿主尾部保护默认提升到 4 轮 / 32000 tokens(`compaction.tail_turns` / `preserve_recent_tokens`,用户显式配置优先)。压缩输入经过 transform 钩子时 DTC 自动跳过,保证摘要器看到全保真内容。
41
+ - **宿主自身的 compaction**(`/compact`、上下文溢出兜底):**100% 原生行为**——原生 anchored-summary 提示词、原生上一份检查点滚动合并,DCP 不做任何替换。DCP 只做两件事:把宿主尾部保护默认提升到 4 轮 / 32000 tokens(`compaction.tail_turns` / `preserve_recent_tokens`,用户显式配置优先);压缩输入经过 transform 钩子时 DTC 一次性跳过,保证摘要器看到全保真内容。
42
42
 
43
43
  ## 安装
44
44
 
@@ -60,13 +60,9 @@ DCP 依次读取以下配置,后面的层覆盖前面的层:
60
60
  "enabled": true,
61
61
  "autoUpdate": true,
62
62
  "debug": false,
63
- "language": "zh",
64
63
  "commands": {
65
64
  "enabled": true,
66
65
  },
67
- "experimental": {
68
- "customPrompts": false,
69
- },
70
66
  "dtc": {
71
67
  "enabled": true,
72
68
  "tailTurns": 4,
@@ -83,7 +79,6 @@ DCP 依次读取以下配置,后面的层覆盖前面的层:
83
79
 
84
80
  | 键 | 说明 |
85
81
  | ------------------------- | ------------------------------------------------------------------------ |
86
- | `language` | 内置压缩提示词语言:`zh`(默认)/ `en`;自定义覆盖文件优先于该配置 |
87
82
  | `dtc.enabled` | 动态分级请求期压缩总开关 |
88
83
  | `dtc.tailTurns` | 尾部保护轮数:最后 N 轮完全不折叠(默认 4) |
89
84
  | `dtc.lowWatermarkRatio` | 估算低于窗口 × 该比例时完全不折叠(默认 0.5) |
@@ -92,18 +87,11 @@ DCP 依次读取以下配置,后面的层覆盖前面的层:
92
87
  | `dtc.toolOutputKeepChars` | 当前任务区超长 tool 输出的首尾截断保留字符数(默认 4000) |
93
88
  | `tool.enabled` | 注册模型可调用的 `dcp_prune` 工具(瞬时标记话题边界,绝不打断工作) |
94
89
 
95
- 启用 `experimental.customPrompts` 后,可将生成的
96
- `~/.config/opencode/dcp-prompts/defaults/compaction.md` 复制到以下任一覆盖位置:
97
-
98
- - 项目:`.opencode/dcp-prompts/overrides/compaction.md`
99
- - 自定义配置目录:`$OPENCODE_CONFIG_DIR/dcp-prompts/overrides/compaction.md`
100
- - 全局:`~/.config/opencode/dcp-prompts/overrides/compaction.md`
101
-
102
- ## 从 3.x 迁移
90
+ ## 从 3.x / 4.0 迁移
103
91
 
104
- 3.x 的 `summarize`、`autoPrune` 配置块已删除(DCP 不再调用原生 summarize,也不再有启发式触发器);这些键会显示迁移警告并被忽略。`autoPrune.driftThreshold` 自动迁移为 `dtc.driftThreshold`。更早的 `compress`、`manualMode`、`strategies`、`turnProtection` 等键维持删除状态。
92
+ 3.x 的 `summarize`、`autoPrune` 配置块已删除(DCP 不再调用原生 summarize,也不再有启发式触发器);4.1 起 `language` 与 `experimental.customPrompts` 也已删除——DCP 不再替换宿主压缩提示词,`dcp-prompts` 覆盖机制随之退役。这些键会显示迁移警告并被忽略。`autoPrune.driftThreshold` 自动迁移为 `dtc.driftThreshold`。更早的 `compress`、`manualMode`、`strategies`、`turnProtection` 等键维持删除状态。
105
93
 
106
- 行为变化:压缩不再产生可见的"检查点回合",也不再需要任何静息边界或续跑机制——上下文折叠在每次请求内自动完成,会话与状态机零感知。语义检查点仍由宿主自身的 compaction(手动 `/compact` 或溢出兜底)产生,DCP 继续为其提供提示词与尾部保护默认值。
94
+ 行为变化:压缩不再产生可见的"检查点回合",也不再需要任何静息边界或续跑机制——上下文折叠在每次请求内自动完成,会话与状态机零感知。语义检查点完全交还宿主原生 compaction(手动 `/compact` 或溢出兜底):原生提示词、原生滚动合并,DCP 仅贡献尾部保护默认值与摘要输入的全保真保护。
107
95
 
108
96
  ## 开发验证
109
97
 
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAgBjD,QAAA,MAAM,MAAM,EAAE,MA0DK,CAAA;AAEnB,eAAe,MAAM,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AAejD,QAAA,MAAM,MAAM,EAAE,MAiDK,CAAA;AAEnB,eAAe,MAAM,CAAA"}
package/dist/index.js CHANGED
@@ -1044,6 +1044,10 @@ var DTC_DEFAULTS = {
1044
1044
  var C_ZONE_MAX_TURNS = 8;
1045
1045
  var M_ZONE_MAX_TURNS = 12;
1046
1046
  var M_TEXT_KEEP_CHARS = 200;
1047
+ var M_ERROR_KEEP_CHARS = 200;
1048
+ var D_ERROR_KEEP_CHARS = 100;
1049
+ var INPUT_TARGET_KEYS = ["filePath", "path", "file", "filename", "pattern", "directory"];
1050
+ var COMMAND_KEEP_CHARS = 80;
1047
1051
  var FOLDED_TEXT = " ";
1048
1052
  var NO_STATS = {
1049
1053
  messages: 0,
@@ -1054,6 +1058,8 @@ var NO_STATS = {
1054
1058
  contextTokens: 0,
1055
1059
  foldedTools: 0,
1056
1060
  foldedTexts: 0,
1061
+ reducedInputs: 0,
1062
+ foldedErrors: 0,
1057
1063
  digestedTurns: 0,
1058
1064
  skipped: void 0
1059
1065
  };
@@ -1123,6 +1129,8 @@ function transformMessages(messages, deps) {
1123
1129
  estimatedAfter,
1124
1130
  contextTokens,
1125
1131
  foldedTools: stats.foldedTools,
1132
+ reducedInputs: stats.reducedInputs,
1133
+ foldedErrors: stats.foldedErrors,
1126
1134
  digestedTurns: stats.digestedTurns
1127
1135
  });
1128
1136
  return stats;
@@ -1177,7 +1185,11 @@ function foldDistant(messages, turn, ordinal, deps, stats, now) {
1177
1185
  const message = messages[i];
1178
1186
  for (const part of message?.parts ?? []) {
1179
1187
  if (!part || typeof part !== "object") continue;
1180
- if (foldToolPart(part, now, true)) {
1188
+ if (part.type === "tool" && part.state?.status === "error") {
1189
+ foldErrorPart(part, D_ERROR_KEEP_CHARS, true, stats);
1190
+ continue;
1191
+ }
1192
+ if (foldToolPart(part, now, "distant", stats)) {
1181
1193
  stats.foldedTools++;
1182
1194
  continue;
1183
1195
  }
@@ -1201,7 +1213,11 @@ function foldMiddle(messages, turn, stats, now) {
1201
1213
  for (let i = turn.start; i < turn.end; i++) {
1202
1214
  for (const part of messages[i]?.parts ?? []) {
1203
1215
  if (!part || typeof part !== "object") continue;
1204
- if (foldToolPart(part, now, false)) {
1216
+ if (part.type === "tool" && part.state?.status === "error") {
1217
+ foldErrorPart(part, M_ERROR_KEEP_CHARS, false, stats);
1218
+ continue;
1219
+ }
1220
+ if (foldToolPart(part, now, "middle", stats)) {
1205
1221
  stats.foldedTools++;
1206
1222
  continue;
1207
1223
  }
@@ -1233,7 +1249,20 @@ function foldCurrent(messages, turn, keepChars, stats) {
1233
1249
  }
1234
1250
  }
1235
1251
  }
1236
- function foldToolPart(part, now, clearInput) {
1252
+ function reduceInput(input) {
1253
+ if (!input || typeof input !== "object") return {};
1254
+ const reduced = {};
1255
+ for (const key of INPUT_TARGET_KEYS) {
1256
+ const value = input[key];
1257
+ if (typeof value === "string" && value) reduced[key] = value;
1258
+ }
1259
+ const command = input.command;
1260
+ if (typeof command === "string" && command) {
1261
+ reduced.command = firstLine(command, COMMAND_KEEP_CHARS);
1262
+ }
1263
+ return reduced;
1264
+ }
1265
+ function foldToolPart(part, now, zone, stats) {
1237
1266
  if (part.type !== "tool") return false;
1238
1267
  const state = part.state;
1239
1268
  if (!state || state.status !== "completed") return false;
@@ -1242,11 +1271,24 @@ function foldToolPart(part, now, clearInput) {
1242
1271
  } else {
1243
1272
  state.time = { compacted: now };
1244
1273
  }
1245
- if (clearInput && state.input && typeof state.input === "object") {
1246
- state.input = {};
1274
+ if (state.input && typeof state.input === "object") {
1275
+ state.input = zone === "distant" ? {} : reduceInput(state.input);
1276
+ stats.reducedInputs++;
1247
1277
  }
1248
1278
  return true;
1249
1279
  }
1280
+ function foldErrorPart(part, keepChars, clearInput, stats) {
1281
+ const state = part.state;
1282
+ if (!state) return;
1283
+ if (typeof state.error === "string" && state.error.length > keepChars) {
1284
+ state.error = firstLine(state.error, keepChars) || FOLDED_TEXT;
1285
+ stats.foldedErrors++;
1286
+ }
1287
+ if (state.input && typeof state.input === "object") {
1288
+ state.input = clearInput ? {} : reduceInput(state.input);
1289
+ stats.reducedInputs++;
1290
+ }
1291
+ }
1250
1292
  function findSessionID(messages) {
1251
1293
  for (const message of messages) {
1252
1294
  const id = message?.info?.sessionID;
@@ -1265,11 +1307,8 @@ var VALID_CONFIG_KEYS = /* @__PURE__ */ new Set([
1265
1307
  "enabled",
1266
1308
  "autoUpdate",
1267
1309
  "debug",
1268
- "language",
1269
1310
  "commands",
1270
1311
  "commands.enabled",
1271
- "experimental",
1272
- "experimental.customPrompts",
1273
1312
  "dtc",
1274
1313
  "dtc.enabled",
1275
1314
  "dtc.tailTurns",
@@ -1322,6 +1361,9 @@ var DEPRECATED_CONFIG_KEYS = /* @__PURE__ */ new Set([
1322
1361
  "protectedFilePatterns",
1323
1362
  "commands.protectedTools",
1324
1363
  "experimental.allowSubAgents",
1364
+ "language",
1365
+ "experimental",
1366
+ "experimental.customPrompts",
1325
1367
  "summarize",
1326
1368
  "summarize.failureCooldownMs",
1327
1369
  "autoPrune",
@@ -1367,13 +1409,6 @@ function validateConfigTypes(config) {
1367
1409
  if (config.debug !== void 0 && typeof config.debug !== "boolean") {
1368
1410
  errors.push({ key: "debug", expected: "boolean", actual: typeof config.debug });
1369
1411
  }
1370
- if (config.language !== void 0 && config.language !== "zh" && config.language !== "en") {
1371
- errors.push({
1372
- key: "language",
1373
- expected: '"zh" or "en"',
1374
- actual: JSON.stringify(config.language)
1375
- });
1376
- }
1377
1412
  const commands = config.commands;
1378
1413
  if (commands !== void 0) {
1379
1414
  if (typeof commands !== "object" || commands === null || Array.isArray(commands)) {
@@ -1386,18 +1421,6 @@ function validateConfigTypes(config) {
1386
1421
  });
1387
1422
  }
1388
1423
  }
1389
- const experimental = config.experimental;
1390
- if (experimental !== void 0) {
1391
- if (typeof experimental !== "object" || experimental === null || Array.isArray(experimental)) {
1392
- errors.push({ key: "experimental", expected: "object", actual: typeof experimental });
1393
- } else if (experimental.customPrompts !== void 0 && typeof experimental.customPrompts !== "boolean") {
1394
- errors.push({
1395
- key: "experimental.customPrompts",
1396
- expected: "boolean",
1397
- actual: typeof experimental.customPrompts
1398
- });
1399
- }
1400
- }
1401
1424
  const dtc = config.dtc;
1402
1425
  if (dtc !== void 0) {
1403
1426
  if (typeof dtc !== "object" || dtc === null || Array.isArray(dtc)) {
@@ -1491,13 +1514,9 @@ var defaultConfig = {
1491
1514
  enabled: true,
1492
1515
  autoUpdate: true,
1493
1516
  debug: false,
1494
- language: "zh",
1495
1517
  commands: {
1496
1518
  enabled: true
1497
1519
  },
1498
- experimental: {
1499
- customPrompts: false
1500
- },
1501
1520
  dtc: { ...DEFAULT_DTC },
1502
1521
  tool: {
1503
1522
  enabled: true
@@ -1576,14 +1595,6 @@ function mergeCommands(base, override) {
1576
1595
  enabled: typeof override.enabled === "boolean" ? override.enabled : base.enabled
1577
1596
  };
1578
1597
  }
1579
- function mergeExperimental(base, override) {
1580
- if (!override) {
1581
- return base;
1582
- }
1583
- return {
1584
- customPrompts: typeof override.customPrompts === "boolean" ? override.customPrompts : base.customPrompts
1585
- };
1586
- }
1587
1598
  function mergeDtc(base, override, legacyDrift) {
1588
1599
  const driftFallback = legacyDrift ?? base.driftThreshold;
1589
1600
  if (!override || typeof override !== "object" || Array.isArray(override)) {
@@ -1611,7 +1622,6 @@ function deepCloneConfig(config) {
1611
1622
  return {
1612
1623
  ...config,
1613
1624
  commands: { ...config.commands },
1614
- experimental: { ...config.experimental },
1615
1625
  dtc: { ...config.dtc },
1616
1626
  tool: { ...config.tool }
1617
1627
  };
@@ -1621,9 +1631,7 @@ function mergeLayer(config, data) {
1621
1631
  enabled: typeof data.enabled === "boolean" ? data.enabled : config.enabled,
1622
1632
  autoUpdate: typeof data.autoUpdate === "boolean" ? data.autoUpdate : config.autoUpdate,
1623
1633
  debug: typeof data.debug === "boolean" ? data.debug : config.debug,
1624
- language: data.language === "zh" || data.language === "en" ? data.language : config.language,
1625
1634
  commands: mergeCommands(config.commands, data.commands),
1626
- experimental: mergeExperimental(config.experimental, data.experimental),
1627
1635
  dtc: mergeDtc(config.dtc, data.dtc, legacyDriftThreshold(data)),
1628
1636
  tool: mergeTool(config.tool, data.tool)
1629
1637
  };
@@ -1759,56 +1767,18 @@ function eventSessionID(properties) {
1759
1767
  // lib/hooks.ts
1760
1768
  var DEFAULT_TAIL_TURNS = 4;
1761
1769
  var DEFAULT_PRESERVE_RECENT_TOKENS = 32e3;
1762
- function extractPreviousCheckpoint(messages) {
1763
- if (!Array.isArray(messages)) return void 0;
1764
- for (let index = messages.length - 1; index >= 0; index--) {
1765
- const message = messages[index];
1766
- const info = message?.info;
1767
- if (info?.role !== "assistant" || info.summary !== true) continue;
1768
- const parts = Array.isArray(message?.parts) ? message.parts : [];
1769
- const text = parts.filter((part) => part?.type === "text" && typeof part.text === "string").map((part) => part.text.trim()).filter(Boolean).join("\n\n").trim();
1770
- if (text) return text;
1771
- }
1772
- return void 0;
1773
- }
1774
- async function fetchPreviousCheckpoint(client, sessionID) {
1775
- if (!sessionID) return void 0;
1776
- try {
1777
- const response = await client.session.messages({ path: { id: sessionID } });
1778
- return extractPreviousCheckpoint(response.data ?? response);
1779
- } catch {
1780
- return void 0;
1781
- }
1782
- }
1783
1770
  function createSessionCompactingHandler(deps) {
1784
- return async (input, output) => {
1771
+ return async (input, _output) => {
1785
1772
  try {
1786
1773
  deps.state.armCompactionSkip(input.sessionID);
1787
- deps.prompts.reload();
1788
- const prompt = deps.prompts.getRuntimePrompts().compaction;
1789
- const previous = await fetchPreviousCheckpoint(deps.client, input.sessionID);
1790
- const withCheckpoint = previous ? `${prompt}
1791
-
1792
- <previous-checkpoint>
1793
- ${previous}
1794
- </previous-checkpoint>` : prompt;
1795
- if (!output.prompt) {
1796
- output.prompt = withCheckpoint;
1797
- } else if (!output.context.includes(prompt)) {
1798
- output.context.push(withCheckpoint);
1799
- }
1800
- deps.logger.debug("Applied semantic pruning prompt", {
1801
- sessionId: input.sessionID,
1802
- carriedCheckpoint: Boolean(previous)
1774
+ deps.logger.debug("Armed DTC skip for the native compaction input", {
1775
+ sessionId: input.sessionID
1803
1776
  });
1804
1777
  } catch (error) {
1805
- deps.logger.warn(
1806
- "Failed to apply semantic pruning prompt; native compaction continues",
1807
- {
1808
- sessionId: input.sessionID,
1809
- error: error instanceof Error ? error.message : String(error)
1810
- }
1811
- );
1778
+ deps.logger.warn("Failed to arm the compaction skip; native compaction continues", {
1779
+ sessionId: input.sessionID,
1780
+ error: error instanceof Error ? error.message : String(error)
1781
+ });
1812
1782
  }
1813
1783
  };
1814
1784
  }
@@ -2124,153 +2094,6 @@ var Logger = class {
2124
2094
  }
2125
2095
  };
2126
2096
 
2127
- // lib/prompts/store.ts
2128
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, statSync as statSync2, writeFileSync as writeFileSync2 } from "fs";
2129
- import { homedir as homedir3 } from "os";
2130
- import { dirname as dirname2, join as join3 } from "path";
2131
-
2132
- // lib/prompts/compaction.ts
2133
- var COMPACTION = `\u4F60\u6B63\u5728\u751F\u6210\u5F53\u524D\u4F1A\u8BDD\u552F\u4E00\u7684\u6EDA\u52A8\u68C0\u67E5\u70B9\u3002\u8F93\u51FA\u5C06\u66FF\u4EE3\u65E7\u5BF9\u8BDD\u524D\u7F00\uFF0C\u6210\u4E3A\u540E\u7EED\u6A21\u578B\u770B\u5230\u7684\u7B2C\u4E00\u6BB5\u4E0A\u4E0B\u6587\uFF1BOpenCode \u4F1A\u5728\u68C0\u67E5\u70B9\u4E4B\u540E\u76F4\u63A5\u4FDD\u7559\u6700\u8FD1\u82E5\u5E72\u8F6E\u5B8C\u6574\u5BF9\u8BDD\uFF08\u4E0D\u7ECF\u538B\u7F29\uFF0C\u8303\u56F4\u7531\u5BBF\u4E3B\u914D\u7F6E\u51B3\u5B9A\uFF09\uFF0C\u8FD9\u90E8\u5206\u5C3E\u90E8\u4E0D\u5C5E\u4E8E\u538B\u7F29\u5BF9\u8C61\uFF0C\u4E0D\u8981\u590D\u8FF0\u3001\u603B\u7ED3\u6216\u6539\u5199\u5B83\u4EEC\u3002\u7CFB\u7EDF\u7EA7\u5185\u5BB9\uFF08AGENTS.md\u3001\u9879\u76EE\u89C4\u5219\u7B49\uFF09\u7531 OpenCode \u5728\u6BCF\u6B21\u8BF7\u6C42\u65F6\u72EC\u7ACB\u6CE8\u5165\uFF0C\u4E0D\u5C5E\u4E8E\u538B\u7F29\u8303\u56F4\uFF0C\u4E0D\u8981\u590D\u8FF0\u5B83\u4EEC\u3002
2134
-
2135
- \u8FD9\u4E0D\u662F\u804A\u5929\u8BB0\u5F55\u6458\u8981\uFF0C\u800C\u662F\u53EF\u76F4\u63A5\u7EE7\u7EED\u5DE5\u4F5C\u7684\u8BED\u4E49\u526A\u679D\u7ED3\u679C\u3002\u6309\u4EE5\u4E0B\u5206\u5C42\u89C4\u5219\u538B\u7F29\uFF1A
2136
-
2137
- 1. \u6EDA\u52A8\u5408\u5E76\uFF1A\u5982\u679C\u8F93\u5165\u672B\u5C3E\u542B\u6709 <previous-checkpoint> \u6807\u7B7E\u5305\u88F9\u7684\u4E0A\u4E00\u4EFD\u68C0\u67E5\u70B9\uFF0C\u628A\u4ECD\u6709\u6548\u7684\u4FE1\u606F\u5408\u5E76\u8FDB\u65B0\u68C0\u67E5\u70B9\uFF1B\u4E0D\u8981\u5D4C\u5957\u3001\u5F15\u7528\u6216\u9010\u5B57\u91CD\u590D\u65E7\u68C0\u67E5\u70B9\uFF0C\u5931\u6548\u5185\u5BB9\u76F4\u63A5\u4E22\u5F03\u3002\u6CA1\u6709\u8BE5\u6807\u7B7E\u65F6\u5FFD\u7565\u672C\u6761\u3002
2138
- 2. \u8FDC\u8DDD\u79BB\u5185\u5BB9\uFF08\u65E9\u671F\u4E0E\u4E2D\u90E8\u5386\u53F2\uFF09\u91CD\u5EA6\u538B\u7F29\uFF1A\u6BCF\u4E2A\u4E3B\u9898\u53EA\u7559\u4E00\u53E5\u8BDD\u7ED3\u8BBA\uFF0C\u4E0D\u7559\u8FC7\u7A0B\u3001\u4E0D\u590D\u8FF0\u5BF9\u8BDD\u5F80\u6765\u3002
2139
- 3. \u5220\u9664\u65E0\u5173\u95F2\u804A\u3001\u5176\u4ED6\u9879\u76EE\u6216\u5176\u4ED6\u4ED3\u5E93\u7684\u5BF9\u8BDD\u3001\u91CD\u590D\u89E3\u91CA\u3001\u5DF2\u7ECF\u63A8\u7FFB\u4E14\u4E0D\u518D\u6709\u8BCA\u65AD\u4EF7\u503C\u7684\u65B9\u6848\u3002
2140
- 4. \u591A\u6B21\u5DE5\u5177\u8C03\u7528\u8BD5\u9519\u6216\u5931\u8D25\u540E\u6210\u529F\u65F6\uFF0C\u53EA\u4FDD\u7559\u6700\u7EC8\u6210\u529F\u7ED3\u679C\uFF1B\u4EC5\u5F53\u6839\u56E0\u4F1A\u5F71\u54CD\u540E\u7EED\u5DE5\u4F5C\u65F6\u4FDD\u7559\u4E00\u6B21\u7B80\u77ED\u5931\u8D25\u539F\u56E0\u3002
2141
- 5. \u540C\u4E00\u5185\u5BB9\u6216\u6587\u4EF6\u88AB\u91CD\u590D\u7F16\u8F91\u65F6\uFF0C\u53EA\u4FDD\u7559\u6700\u7EC8\u72B6\u6001\u3001\u4ECD\u6709\u6548\u7684\u5173\u952E\u51B3\u7B56\u548C\u5FC5\u8981\u7406\u7531\uFF0C\u4E0D\u590D\u8FF0\u6BCF\u8F6E\u4FEE\u6539\u3002
2142
- 6. \u8FD1\u8DDD\u79BB\u5185\u5BB9\uFF08\u81EA\u4E0A\u4E00\u4EFD\u68C0\u67E5\u70B9\u4EE5\u6765\u7684\u65B0\u5185\u5BB9\uFF0C\u4E14\u4E0D\u5C5E\u4E8E\u5BBF\u4E3B\u4FDD\u7559\u7684\u5C3E\u90E8\uFF09\u8F7B\u5EA6\u538B\u7F29\uFF1A\u5F53\u524D\u4EFB\u52A1\u3001\u76EE\u6807\u3001\u72B6\u6001\u4E0E\u8FDB\u884C\u4E2D\u7684\u60C5\u51B5\u505A\u6C47\u603B\u4F46\u4E0D\u4E22\u7EC6\u8282\u2014\u2014\u4FDD\u7559\u7EE7\u7EED\u5DE5\u4F5C\u6240\u9700\u7684\u6587\u4EF6\u8DEF\u5F84\u3001\u63A5\u53E3\u3001\u547D\u4EE4\u3001\u6D4B\u8BD5\u7ED3\u679C\u3001\u9519\u8BEF\u4E8B\u5B9E\u3001\u4ECD\u6709\u6548\u7684\u51B3\u7B56\u53CA\u7406\u7531\uFF0C\u53EA\u6298\u53E0\u91CD\u590D\u4E0E\u5DF2\u5931\u6548\u7684\u5185\u5BB9\u3002
2143
-
2144
- \u4F7F\u7528\u4EE5\u4E0B\u56FA\u5B9A\u7ED3\u6784\uFF0C\u7701\u7565\u786E\u5B9E\u4E3A\u7A7A\u7684\u6761\u76EE\uFF1A
2145
-
2146
- ## \u5386\u53F2\u6982\u8981
2147
- \u65E9\u671F\u4E0E\u4E2D\u90E8\u5386\u53F2\u7684\u4E3B\u9898\u548C\u80CC\u666F\uFF0C\u6BCF\u9879\u4E00\u53E5\u8BDD\u7ED3\u8BBA\uFF1B\u8FDC\u671F\u5DF2\u5B8C\u6210\u4EFB\u52A1\u5F52\u5165\u6B64\u5904\uFF0C\u4E0D\u542B\u6267\u884C\u8FC7\u7A0B\u3002
2148
-
2149
- ## \u5DF2\u5B8C\u6210\u4EFB\u52A1\u7684\u6982\u62EC
2150
- \u6700\u8FD1\u7684\u5DF2\u5B8C\u6210\u4EFB\u52A1\uFF0C\u6BCF\u4E2A\u4EFB\u52A1\u4E00\u53E5\u8BDD\u6982\u62EC\u5176\u7ED3\u679C\u4E0E\u5173\u952E\u4EA7\u51FA\u3002
2151
-
2152
- ## \u8FDB\u884C\u4E2D\u4EFB\u52A1\u8BE6\u60C5
2153
- \u5F53\u524D\u6B63\u5728\u8FDB\u884C\u7684\u4EFB\u52A1\u9010\u9879\u5199\u6E05\uFF1A\u76EE\u6807\u3001\u5DF2\u5B8C\u6210\u6B65\u9AA4\u3001\u6D89\u53CA\u6587\u4EF6\u8DEF\u5F84\u4E0E\u63A5\u53E3\u3001\u5173\u952E\u51B3\u7B56\u3001\u9047\u5230\u7684\u963B\u585E\u3001\u4E0B\u4E00\u6B65\u5177\u4F53\u52A8\u4F5C\u3002\u672C\u8282\u5C5E\u4E8E\u8F7B\u5EA6\u538B\u7F29\u533A\uFF0C\u5B81\u53EF\u591A\u4FDD\u7559\u7EC6\u8282\uFF0C\u4E0D\u505A\u4E8C\u6B21\u63A8\u65AD\u3002
2154
-
2155
- ## \u672A\u89E3\u51B3\u95EE\u9898
2156
- \u8DE8\u4EFB\u52A1\u7684\u9057\u7559\u98CE\u9669\u548C\u5F85\u786E\u8BA4\u4E8B\u9879\u3002\u53EA\u5199\u672A\u5728\u300C\u8FDB\u884C\u4E2D\u4EFB\u52A1\u8BE6\u60C5\u300D\u4E2D\u51FA\u73B0\u7684\u5185\u5BB9\uFF0C\u907F\u514D\u4E0E\u8BE5\u8282\u91CD\u590D\u3002
2157
-
2158
- \u4FDD\u6301\u5177\u4F53\u3001\u53EF\u9A8C\u8BC1\u548C\u9879\u76EE\u5185\u805A\u3002\u8FDB\u884C\u4E2D\u7684\u4EFB\u52A1\u5FC5\u987B\u80FD\u51ED\u68C0\u67E5\u70B9\u76F4\u63A5\u7EE7\u7EED\uFF0C\u4E0D\u8981\u4F9D\u8D56\u5DF2\u88AB\u538B\u7F29\u6389\u7684\u4E2D\u95F4\u8FC7\u7A0B\u3002\u4FDD\u7559\u6587\u4EF6\u8DEF\u5F84\u3001\u63A5\u53E3\u3001\u547D\u4EE4\u3001\u6D4B\u8BD5\u7ED3\u679C\u548C\u9519\u8BEF\u4E8B\u5B9E\u7B49\u786C\u4E8B\u5B9E\uFF0C\u4F46\u4E0D\u8981\u4FDD\u7559\u6D88\u606F ID\u3001\u5757 ID\u3001\u951A\u70B9\u3001\u5360\u4F4D\u7B26\u3001\u63A7\u5236\u6807\u7B7E\u6216\u8FC7\u7A0B\u6027\u804A\u5929\u3002`;
2159
- var COMPACTION_EN = `You are generating the single rolling checkpoint for this session. Your output will replace the old conversation prefix as the first context the model sees afterwards; OpenCode keeps the most recent conversation turns directly after the checkpoint, uncompacted (their range is a host setting). That tail is outside the compaction scope: do not restate, summarize, or rewrite it. System-level content (AGENTS.md, project rules, etc.) is injected independently by OpenCode on every request and is not part of compaction; do not restate it.
2160
-
2161
- This is not a chat-log summary but a semantic pruning result one can resume working from directly. Compress by these tiered rules:
2162
-
2163
- 1. Rolling merge: if the input ends with a <previous-checkpoint> block containing the previous checkpoint, merge its still-valid information into the new checkpoint; do not nest, quote, or repeat it verbatim, and drop stale content outright. Ignore this rule when the tag is absent.
2164
- 2. Distant content (early and middle history) is compressed heavily: one concluding sentence per topic, no process detail, no dialogue restatement.
2165
- 3. Remove irrelevant chitchat, conversations about other projects or repositories, repeated explanations, and approaches that were overturned and no longer carry diagnostic value.
2166
- 4. When repeated tool trial-and-error ends in success, keep only the final successful outcome; retain one brief failure reason only if the root cause affects future work.
2167
- 5. When the same content or file was edited repeatedly, keep only the final state, the still-valid key decisions, and the necessary rationale; do not restate each round of edits.
2168
- 6. Recent content (everything generated since the previous checkpoint, excluding the host-retained tail) is compressed lightly: summarize the current task, goals, status, and in-progress work without losing detail\u2014keep the file paths, interfaces, commands, test results, error facts, and still-valid decisions with rationale needed to continue, folding only duplicates and invalidated content.
2169
-
2170
- Use the following fixed structure, omitting sections that are truly empty:
2171
-
2172
- ## History Overview
2173
- Topics and background from early and middle history, one concluding sentence each; long-completed tasks belong here, without execution process.
2174
-
2175
- ## Completed Task Summaries
2176
- Recently completed tasks, one sentence per task covering its outcome and key outputs.
2177
-
2178
- ## In-Progress Task Details
2179
- For the current task, itemize: goal, completed steps, file paths and interfaces involved, key decisions, blockers encountered, concrete next actions. This is the lightly-compressed zone; prefer keeping more detail and avoid second-order inference.
2180
-
2181
- ## Unresolved Issues
2182
- Cross-task lingering risks and items awaiting confirmation. Only list items not already covered under In-Progress Task Details, to avoid duplication.
2183
-
2184
- Stay specific, verifiable, and project-cohesive. An in-progress task must be resumable straight from this checkpoint, without relying on intermediate process that was pruned away. Keep hard facts such as file paths, interfaces, commands, test results, and error facts, but never message IDs, block IDs, anchors, placeholders, control tags, or procedural chatter.`;
2185
- function getCompactionPrompt(language) {
2186
- return language === "en" ? COMPACTION_EN : COMPACTION;
2187
- }
2188
-
2189
- // lib/prompts/store.ts
2190
- function findOpencodeDir2(startDir) {
2191
- let current = startDir;
2192
- while (current !== "/") {
2193
- const candidate = join3(current, ".opencode");
2194
- if (existsSync3(candidate) && statSync2(candidate).isDirectory()) return candidate;
2195
- const parent = dirname2(current);
2196
- if (parent === current) break;
2197
- current = parent;
2198
- }
2199
- return null;
2200
- }
2201
- function resolvePaths(workingDirectory) {
2202
- const configHome = process.env.XDG_CONFIG_HOME || join3(homedir3(), ".config");
2203
- const globalRoot = join3(configHome, "opencode", "dcp-prompts");
2204
- const opencodeDir = findOpencodeDir2(workingDirectory);
2205
- return {
2206
- defaultsDir: join3(globalRoot, "defaults"),
2207
- overrides: [
2208
- opencodeDir ? join3(opencodeDir, "dcp-prompts", "overrides", "compaction.md") : "",
2209
- process.env.OPENCODE_CONFIG_DIR ? join3(process.env.OPENCODE_CONFIG_DIR, "dcp-prompts", "overrides", "compaction.md") : "",
2210
- join3(globalRoot, "overrides", "compaction.md")
2211
- ].filter(Boolean)
2212
- };
2213
- }
2214
- function normalize(content) {
2215
- return content.replace(/^\uFEFF/, "").replace(/\r\n?/g, "\n").replace(/<!--[\s\S]*?-->/g, "").trim();
2216
- }
2217
- var PromptStore = class {
2218
- constructor(logger, workingDirectory, customPromptsEnabled = false, language) {
2219
- this.logger = logger;
2220
- this.customPromptsEnabled = customPromptsEnabled;
2221
- this.paths = resolvePaths(workingDirectory);
2222
- this.defaultPrompt = getCompactionPrompt(language);
2223
- this.runtime = { compaction: this.defaultPrompt };
2224
- if (customPromptsEnabled) this.ensureDefaults();
2225
- this.reload();
2226
- }
2227
- paths;
2228
- defaultPrompt;
2229
- runtime;
2230
- lastReloadAt = 0;
2231
- getRuntimePrompts() {
2232
- return { ...this.runtime };
2233
- }
2234
- reload() {
2235
- const now = Date.now();
2236
- if (now - this.lastReloadAt < 1e3) return;
2237
- this.lastReloadAt = now;
2238
- this.runtime = { compaction: this.defaultPrompt };
2239
- if (!this.customPromptsEnabled) return;
2240
- for (const path of this.paths.overrides) {
2241
- if (!existsSync3(path)) continue;
2242
- try {
2243
- const prompt = normalize(readFileSync2(path, "utf-8"));
2244
- if (prompt) this.runtime = { compaction: prompt };
2245
- return;
2246
- } catch (error) {
2247
- this.logger.warn("Failed to load compaction prompt override", {
2248
- path,
2249
- error: error instanceof Error ? error.message : String(error)
2250
- });
2251
- }
2252
- }
2253
- }
2254
- ensureDefaults() {
2255
- try {
2256
- mkdirSync2(this.paths.defaultsDir, { recursive: true });
2257
- writeFileSync2(
2258
- join3(this.paths.defaultsDir, "compaction.md"),
2259
- `${this.defaultPrompt.trim()}
2260
- `
2261
- );
2262
- writeFileSync2(
2263
- join3(this.paths.defaultsDir, "README.md"),
2264
- "# DCP compaction prompt\n\nCopy `compaction.md` to an `overrides` directory and restart OpenCode.\n"
2265
- );
2266
- } catch (error) {
2267
- this.logger.warn("Failed to write bundled compaction prompt", {
2268
- error: error instanceof Error ? error.message : String(error)
2269
- });
2270
- }
2271
- }
2272
- };
2273
-
2274
2097
  // lib/prune-tool.ts
2275
2098
  import { tool } from "@opencode-ai/plugin";
2276
2099
  var PRUNE_TOOL_NAME = "dcp_prune";
@@ -2299,7 +2122,7 @@ function createPruneTool(deps) {
2299
2122
 
2300
2123
  // lib/update.ts
2301
2124
  import { readFile } from "fs/promises";
2302
- import { basename, dirname as dirname3, join as join4 } from "path";
2125
+ import { basename, dirname as dirname2, join as join3 } from "path";
2303
2126
  import { fileURLToPath } from "url";
2304
2127
  var PACKAGE_NAME = "@lexwdex-org/opencode-dcp";
2305
2128
  function startAutoUpdate(ctx, enabled) {
@@ -2325,7 +2148,7 @@ function startAutoUpdate(ctx, enabled) {
2325
2148
  async function checkAutoUpdate(signal) {
2326
2149
  const packageDir = await findPackageDir(PACKAGE_NAME);
2327
2150
  if (!packageDir) return { available: false };
2328
- const pkg = await readPackageJson(join4(packageDir, "package.json"));
2151
+ const pkg = await readPackageJson(join3(packageDir, "package.json"));
2329
2152
  if (!pkg?.name || !pkg.version) return { available: false };
2330
2153
  const latest = await fetchLatestVersion(pkg.name, signal);
2331
2154
  if (!latest || !isVersionNewer(latest, pkg.version)) return { available: false };
@@ -2334,21 +2157,21 @@ async function checkAutoUpdate(signal) {
2334
2157
  return { available: true, name: pkg.name, current: pkg.version, latest };
2335
2158
  }
2336
2159
  async function findPackageDir(name) {
2337
- let dir = dirname3(fileURLToPath(import.meta.url));
2160
+ let dir = dirname2(fileURLToPath(import.meta.url));
2338
2161
  for (; ; ) {
2339
- const pkg = await readPackageJson(join4(dir, "package.json"));
2162
+ const pkg = await readPackageJson(join3(dir, "package.json"));
2340
2163
  if (pkg?.name === name) return dir;
2341
- const parent = dirname3(dir);
2164
+ const parent = dirname2(dir);
2342
2165
  if (parent === dir) return void 0;
2343
2166
  dir = parent;
2344
2167
  }
2345
2168
  }
2346
2169
  async function findAutoUpdateWrapperDir(packageDir, name) {
2347
- const packageParent = dirname3(packageDir);
2348
- const nodeModulesDir = basename(packageParent).startsWith("@") ? dirname3(packageParent) : packageParent;
2170
+ const packageParent = dirname2(packageDir);
2171
+ const nodeModulesDir = basename(packageParent).startsWith("@") ? dirname2(packageParent) : packageParent;
2349
2172
  if (basename(nodeModulesDir) !== "node_modules") return void 0;
2350
- const wrapperDir = dirname3(nodeModulesDir);
2351
- const wrapperPkg = await readPackageJson(join4(wrapperDir, "package.json"));
2173
+ const wrapperDir = dirname2(nodeModulesDir);
2174
+ const wrapperPkg = await readPackageJson(join3(wrapperDir, "package.json"));
2352
2175
  const spec = wrapperSpec(wrapperDir, name) ?? wrapperPkg?.dependencies?.[name];
2353
2176
  if (!spec || !isAutoUpdatableSpec(spec)) return void 0;
2354
2177
  return wrapperDir;
@@ -2356,7 +2179,7 @@ async function findAutoUpdateWrapperDir(packageDir, name) {
2356
2179
  function wrapperSpec(wrapperDir, name) {
2357
2180
  if (name.startsWith("@")) {
2358
2181
  const [scope, pkg] = name.split("/");
2359
- if (!scope || !pkg || basename(dirname3(wrapperDir)) !== scope) return void 0;
2182
+ if (!scope || !pkg || basename(dirname2(wrapperDir)) !== scope) return void 0;
2360
2183
  const prefix2 = `${pkg}@`;
2361
2184
  const base2 = basename(wrapperDir);
2362
2185
  return base2.startsWith(prefix2) ? base2.slice(prefix2.length) : void 0;
@@ -2437,37 +2260,28 @@ var server = (async (ctx) => {
2437
2260
  const config = getConfig(ctx);
2438
2261
  if (!config.enabled) return {};
2439
2262
  const logger = new Logger(config.debug);
2440
- const prompts = new PromptStore(
2441
- logger,
2442
- ctx.directory,
2443
- config.experimental.customPrompts,
2444
- config.language
2445
- );
2446
2263
  const state = new DtcState();
2447
2264
  logger.info("DCP initialized", {
2448
2265
  commands: config.commands.enabled,
2449
2266
  dtc: config.dtc.enabled,
2450
- tool: config.tool.enabled,
2451
- customPrompts: config.experimental.customPrompts
2267
+ tool: config.tool.enabled
2452
2268
  });
2453
2269
  startAutoUpdate(ctx, config.autoUpdate);
2454
2270
  return {
2455
- "experimental.session.compacting": createSessionCompactingHandler({
2456
- prompts,
2457
- logger,
2458
- client: ctx.client,
2459
- state
2460
- }),
2461
2271
  // THE compression surface: dynamic tiered folding on every model
2462
2272
  // request, plus the chat.params feed that teaches the engine each
2463
- // session's context-window size.
2273
+ // session's context-window size. The compacting hook rides along
2274
+ // solely to keep the host's native compaction input unfolded — the
2275
+ // native prompt is never touched. With DTC off, DCP registers no
2276
+ // compaction-adjacent hook at all.
2464
2277
  ...config.dtc.enabled && {
2465
2278
  "experimental.chat.messages.transform": createTransformHandler({
2466
2279
  state,
2467
2280
  config: config.dtc,
2468
2281
  logger
2469
2282
  }),
2470
- "chat.params": createChatParamsHandler({ state, logger })
2283
+ "chat.params": createChatParamsHandler({ state, logger }),
2284
+ "experimental.session.compacting": createSessionCompactingHandler({ state, logger })
2471
2285
  },
2472
2286
  // Lifecycle cleanup for DTC session state (LRU-bounded regardless).
2473
2287
  event: createEventHandler({ state, logger }),