dsh-manual-compact-plugin 0.1.1 → 0.2.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 +5 -2
- package/lib/client.js +56 -30
- package/lib/index.js +134 -34
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -2,14 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
手动上下文压缩插件(DeepSeek Harness / DSH)。
|
|
4
4
|
|
|
5
|
-
> 点击上下文圆圈(或输入框旁的"压缩"按钮)→
|
|
5
|
+
> 点击上下文圆圈(或输入框旁的"压缩"按钮)→ 填写保留最近 N 条 → 停止或分批压缩 → 每次压缩都有存档可查。
|
|
6
6
|
|
|
7
7
|
## 功能
|
|
8
8
|
|
|
9
|
-
- **保留最近 N
|
|
9
|
+
- **保留最近 N 条**:直接输入保留数量(默认 4,建议 1–4 条)
|
|
10
10
|
- **处理方式**:
|
|
11
11
|
- 完成一批后停止
|
|
12
12
|
- 分批处理直到完成
|
|
13
|
+
- **取消压缩**:压缩过程中可随时取消
|
|
14
|
+
- **压缩进度**:分批模式下实时显示进度条(已处理 / 总数)
|
|
15
|
+
- **可读结果文件**:每次压缩自动追加到 `~/.dsh/manual-compact/<会话>.md`,含时间 / 保留数 / 压缩条数 / 摘要,可用任意文本编辑器打开
|
|
13
16
|
- **压缩存档**:每次压缩显示时间、条数、约计 tokens,点击展开完整摘要
|
|
14
17
|
- 调用 DSH 官方 compaction API(`compaction.compactRegion`):不拆开工具调用对、会话忙时自动拒绝、失败不改动会话
|
|
15
18
|
|
package/lib/client.js
CHANGED
|
@@ -39,6 +39,10 @@ window.__ModuleLoader__.load({
|
|
|
39
39
|
".dsmc-actions button{border:0;border-radius:6px;padding:5px 10px;cursor:pointer;font-size:12px}",
|
|
40
40
|
".dsmc-actions button:disabled{cursor:default;opacity:.6}",
|
|
41
41
|
".dsmc-confirm{background:var(--dsw-alias-interactive-bg-primary);color:var(--dsw-alias-label-on-color)}",
|
|
42
|
+
".dsmc-cancel{background:transparent;color:var(--dsw-alias-state-error-primary);border:1px solid var(--dsw-alias-state-error-primary)}",
|
|
43
|
+
".dsmc-progress{height:6px;border-radius:999px;background:var(--dsw-alias-bg-layer-2);overflow:hidden;margin-top:8px;width:100%}",
|
|
44
|
+
".dsmc-progress-fill{height:100%;border-radius:999px;background:var(--dsw-alias-interactive-bg-primary);transition:width .2s ease}",
|
|
45
|
+
".dsmc-progress-txt{margin-top:4px;font-size:11px;color:var(--dsw-alias-label-tertiary)}",
|
|
42
46
|
".dsmc-msg{margin-top:6px;font-size:12px;line-height:16px;color:var(--dsw-alias-label-tertiary)}",
|
|
43
47
|
".dsmc-msg.dsmc-err{color:var(--dsw-alias-state-error-primary)}",
|
|
44
48
|
".dsmc-archive{max-height:160px;overflow:auto}",
|
|
@@ -97,15 +101,22 @@ window.__ModuleLoader__.load({
|
|
|
97
101
|
function CompactControls(props) {
|
|
98
102
|
var state = useNamespaceSnapshot(props.scope);
|
|
99
103
|
var value = state.value || {};
|
|
100
|
-
var [keep, setKeep] = useState("
|
|
101
|
-
var [customKeep, setCustomKeep] = useState("");
|
|
104
|
+
var [keep, setKeep] = useState("4");
|
|
102
105
|
var [mode, setMode] = useState("stop");
|
|
103
106
|
var [localError, setLocalError] = useState("");
|
|
104
107
|
var [expandedSeq, setExpandedSeq] = useState(null);
|
|
108
|
+
var [cancelling, setCancelling] = useState(false);
|
|
105
109
|
|
|
106
110
|
var request = value.request;
|
|
107
111
|
var busy = request !== null && request !== undefined;
|
|
108
112
|
var lastRun = value.lastRun;
|
|
113
|
+
var progress = value.progress;
|
|
114
|
+
var progVisible = busy && progress && progress.nonce === (request && request.nonce) && progress.total > 0;
|
|
115
|
+
|
|
116
|
+
// Once the request clears, reset the "cancelling" local flag.
|
|
117
|
+
useEffect(function () {
|
|
118
|
+
if (!busy) setCancelling(false);
|
|
119
|
+
}, [busy]);
|
|
109
120
|
|
|
110
121
|
var legacy = props.session && props.session.chat && props.session.chat.legacy;
|
|
111
122
|
var nodes = legacy && Array.isArray(legacy.nodes) ? legacy.nodes : [];
|
|
@@ -115,7 +126,15 @@ window.__ModuleLoader__.load({
|
|
|
115
126
|
if (n && n.kind === "compaction") entries.push(n);
|
|
116
127
|
}
|
|
117
128
|
|
|
118
|
-
|
|
129
|
+
function newNonce() { return Date.now() * 1000 + Math.floor(Math.random() * 1000); }
|
|
130
|
+
function sendRequest(req) {
|
|
131
|
+
props.scope.set("request", req).catch(function (error) {
|
|
132
|
+
console.error("[dsh-manual-compact-plugin] request failed:", error);
|
|
133
|
+
setLocalError("请求发送失败,请稍后重试。");
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
var effectiveKeep = keep;
|
|
119
138
|
function submit() {
|
|
120
139
|
var n = Number(effectiveKeep);
|
|
121
140
|
if (!Number.isInteger(n) || n < 1) {
|
|
@@ -127,15 +146,12 @@ window.__ModuleLoader__.load({
|
|
|
127
146
|
setLocalError("当前没有可压缩的会话。");
|
|
128
147
|
return;
|
|
129
148
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
console.error("[dsh-manual-compact-plugin] submit failed:", error);
|
|
137
|
-
setLocalError("请求发送失败,请稍后重试。");
|
|
138
|
-
});
|
|
149
|
+
sendRequest({ action: "compact", nonce: newNonce(), sessionId: props.sessionId, keep: n, mode: mode });
|
|
150
|
+
}
|
|
151
|
+
function cancelCurrent() {
|
|
152
|
+
if (props.sessionId === undefined || props.sessionId === null) return;
|
|
153
|
+
setCancelling(true);
|
|
154
|
+
sendRequest({ action: "cancel", nonce: newNonce(), sessionId: props.sessionId, keep: Number(effectiveKeep) || 4, mode: mode });
|
|
139
155
|
}
|
|
140
156
|
|
|
141
157
|
return react.createElement(
|
|
@@ -147,28 +163,17 @@ window.__ModuleLoader__.load({
|
|
|
147
163
|
"div",
|
|
148
164
|
{ className: "dsmc-row" },
|
|
149
165
|
react.createElement("label", null, "保留最近"),
|
|
150
|
-
react.createElement(
|
|
151
|
-
"select",
|
|
152
|
-
{ value: keep, disabled: busy, onChange: function (e) { setKeep(e.target.value); } },
|
|
153
|
-
react.createElement("option", { value: "1" }, "1 条"),
|
|
154
|
-
react.createElement("option", { value: "3" }, "3 条"),
|
|
155
|
-
react.createElement("option", { value: "5" }, "5 条(推荐)"),
|
|
156
|
-
react.createElement("option", { value: "10" }, "10 条"),
|
|
157
|
-
react.createElement("option", { value: "20" }, "20 条"),
|
|
158
|
-
react.createElement("option", { value: "50" }, "50 条"),
|
|
159
|
-
react.createElement("option", { value: "custom" }, "自定义")
|
|
160
|
-
)
|
|
161
|
-
),
|
|
162
|
-
keep === "custom"
|
|
163
|
-
? react.createElement("input", {
|
|
166
|
+
react.createElement("input", {
|
|
164
167
|
type: "number",
|
|
165
168
|
min: 1,
|
|
166
169
|
max: 10000,
|
|
167
|
-
placeholder: "
|
|
170
|
+
placeholder: "输入保留条数",
|
|
171
|
+
value: keep,
|
|
168
172
|
disabled: busy,
|
|
169
|
-
onChange: function (e) {
|
|
173
|
+
onChange: function (e) { setKeep(e.target.value); },
|
|
170
174
|
})
|
|
171
|
-
|
|
175
|
+
),
|
|
176
|
+
react.createElement("div", { className: "dsmc-msg" }, "建议保留 1–4 条(DSH 单轮输出较大)"),
|
|
172
177
|
react.createElement(
|
|
173
178
|
"div",
|
|
174
179
|
{ className: "dsmc-row" },
|
|
@@ -187,8 +192,29 @@ window.__ModuleLoader__.load({
|
|
|
187
192
|
"button",
|
|
188
193
|
{ type: "button", className: "dsmc-confirm", disabled: busy, onClick: submit },
|
|
189
194
|
busy ? "处理中…" : "开始压缩"
|
|
190
|
-
)
|
|
195
|
+
),
|
|
196
|
+
busy
|
|
197
|
+
? react.createElement(
|
|
198
|
+
"button",
|
|
199
|
+
{ type: "button", className: "dsmc-cancel", disabled: cancelling, onClick: cancelCurrent },
|
|
200
|
+
cancelling ? "正在取消…" : "取消压缩"
|
|
201
|
+
)
|
|
202
|
+
: null
|
|
191
203
|
),
|
|
204
|
+
progVisible
|
|
205
|
+
? react.createElement(
|
|
206
|
+
"div",
|
|
207
|
+
null,
|
|
208
|
+
react.createElement(
|
|
209
|
+
"div",
|
|
210
|
+
{ className: "dsmc-progress" },
|
|
211
|
+
react.createElement("div", { className: "dsmc-progress-fill", style: { width: Math.round((progress.done / progress.total) * 100) + "%" } })
|
|
212
|
+
),
|
|
213
|
+
react.createElement("div", { className: "dsmc-progress-txt" },
|
|
214
|
+
"压缩进度 " + progress.done + " / " + progress.total
|
|
215
|
+
)
|
|
216
|
+
)
|
|
217
|
+
: null,
|
|
192
218
|
localError
|
|
193
219
|
? react.createElement("div", { className: "dsmc-msg dsmc-err" }, localError)
|
|
194
220
|
: lastRun
|
package/lib/index.js
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dsh-manual-compact — host face.
|
|
2
|
+
* dsh-manual-compact-plugin — host face.
|
|
3
3
|
*
|
|
4
4
|
* Registers the `manual-compact` settings namespace as the Client<->Host
|
|
5
5
|
* transport (the same pattern dsh-plugin-proxy uses). The browser half writes
|
|
6
|
-
* a `request` object
|
|
7
|
-
* agent's official compaction seam
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* a `request` object with an `action`; this half executes the compaction
|
|
7
|
+
* through the current agent's official compaction seam
|
|
8
|
+
* (`compaction.compactRegion(..., signal)`), supports cancellation via an
|
|
9
|
+
* AbortController, publishes live progress, and appends a readable
|
|
10
|
+
* per-session markdown archive to `$DSH_HOME/manual-compact/<session>.md`.
|
|
11
|
+
* The outcome is published into `lastRun` and the request is cleared.
|
|
10
12
|
*/
|
|
11
13
|
|
|
12
14
|
import z from '@deepseek-ai/schemastery'
|
|
13
15
|
import { installSettingsSection } from '@deepseek-ai/dsh-settings'
|
|
16
|
+
import { mkdir, appendFile } from 'node:fs/promises'
|
|
17
|
+
import os from 'node:os'
|
|
14
18
|
|
|
15
19
|
const name = 'dsh-manual-compact-plugin'
|
|
16
20
|
const inject = ['settings', 'agents']
|
|
@@ -23,6 +27,12 @@ const Config = z.object({
|
|
|
23
27
|
sessionId: z.string(),
|
|
24
28
|
keep: z.number(),
|
|
25
29
|
mode: z.union([z.const('stop'), z.const('batch')]),
|
|
30
|
+
action: z.union([z.const('compact'), z.const('cancel')]).default('compact'),
|
|
31
|
+
})]).default(null),
|
|
32
|
+
progress: z.union([z.const(null), z.object({
|
|
33
|
+
nonce: z.number(),
|
|
34
|
+
done: z.number(),
|
|
35
|
+
total: z.number(),
|
|
26
36
|
})]).default(null),
|
|
27
37
|
lastRun: z.union([z.const(null), z.object({
|
|
28
38
|
at: z.number(),
|
|
@@ -31,49 +41,107 @@ const Config = z.object({
|
|
|
31
41
|
ok: z.boolean(),
|
|
32
42
|
shadowed: z.number(),
|
|
33
43
|
message: z.string(),
|
|
44
|
+
cancelled: z.boolean().default(false),
|
|
45
|
+
file: z.string().default(''),
|
|
34
46
|
})]).default(null),
|
|
35
47
|
})
|
|
36
48
|
|
|
49
|
+
/** Best-effort JSON-friendly timestamp. */
|
|
50
|
+
function fmtTime(ms) {
|
|
51
|
+
const d = new Date(ms)
|
|
52
|
+
const pad = (v) => String(v).padStart(2, '0')
|
|
53
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Locate the newest landed compaction node, if any. */
|
|
57
|
+
function newestCompactionNode(snapshot) {
|
|
58
|
+
const nodes = snapshot && snapshot.surface && snapshot.surface.nodes
|
|
59
|
+
if (!Array.isArray(nodes)) return null
|
|
60
|
+
let newest = null
|
|
61
|
+
for (const n of nodes) {
|
|
62
|
+
if (n && n.kind === 'compaction') newest = n
|
|
63
|
+
}
|
|
64
|
+
return newest
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Append a readable markdown record for every completed region. */
|
|
68
|
+
async function writeArchiveFile(sessionId, keep, mode, records, shadowed) {
|
|
69
|
+
if (!records.length) return ''
|
|
70
|
+
const dir = path(process.env.DSH_HOME || homeDotDsh(), 'manual-compact')
|
|
71
|
+
try { await mkdir(dir, { recursive: true }) } catch { /* best effort */ }
|
|
72
|
+
const file = path(dir, sessionId + '.md')
|
|
73
|
+
const chunks = records.map((r) => [
|
|
74
|
+
`## 压缩记录 · ${fmtTime(r.time)}`,
|
|
75
|
+
`- 保留最近:${keep} 条`,
|
|
76
|
+
`- 压缩:${shadowed} 条 · ~${fmtTokens(r.shadowedTokenCount)} tokens`,
|
|
77
|
+
`- 方式:${mode === 'batch' ? '分批处理直到完成' : '完成一批后停止'}`,
|
|
78
|
+
'',
|
|
79
|
+
r.summary || '',
|
|
80
|
+
'',
|
|
81
|
+
'---',
|
|
82
|
+
'',
|
|
83
|
+
].join('\n'))
|
|
84
|
+
try { await appendFile(file, chunks.join('\n') + '\n', 'utf8') } catch { /* best effort */ }
|
|
85
|
+
return file
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function homeDotDsh() {
|
|
89
|
+
return os.homedir() + (process.platform === 'win32' ? '\\.dsh' : '/.dsh')
|
|
90
|
+
}
|
|
91
|
+
function path(...parts) { return parts.join(process.platform === 'win32' ? '\\' : '/') }
|
|
92
|
+
function fmtTokens(v) { return typeof v === 'number' && isFinite(v) ? (v >= 1000 ? Math.round(v / 1000) + 'k' : String(v)) : '?' }
|
|
93
|
+
|
|
94
|
+
const ERROR_MESSAGES = {
|
|
95
|
+
busy: '当前正在压缩或模型仍在工作,请稍后再试。',
|
|
96
|
+
changed: '会话发生变化,本次压缩已停止。',
|
|
97
|
+
summary: '无法生成有效摘要,本次压缩已停止。',
|
|
98
|
+
commit: '压缩提交未完成。',
|
|
99
|
+
persistence: '摘要生成完成,但保存会话失败。',
|
|
100
|
+
}
|
|
101
|
+
|
|
37
102
|
/**
|
|
38
103
|
* Run one manual compaction request against the requesting session.
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* @param request - validated request payload.
|
|
42
|
-
* @returns the outcome: ok, shadowed item count, and a human message.
|
|
104
|
+
* Supports cancellation through `signal` and reports progress through
|
|
105
|
+
* `onProgress`. Returns the outcome including a readable file path.
|
|
43
106
|
*/
|
|
44
|
-
async function executeCompact(ctx, agents, request) {
|
|
107
|
+
async function executeCompact(ctx, agents, request, signal, onProgress) {
|
|
45
108
|
const agent = agents.get(request.sessionId)
|
|
46
109
|
const compaction = agent && agent.ctx && agent.ctx.get('compaction')
|
|
47
110
|
if (!agent || !compaction) {
|
|
48
|
-
return { ok: false, shadowed: 0, message: '当前会话暂时没有可用的压缩服务。' }
|
|
111
|
+
return { ok: false, shadowed: 0, message: '当前会话暂时没有可用的压缩服务。', cancelled: false, file: '' }
|
|
49
112
|
}
|
|
113
|
+
const records = []
|
|
50
114
|
try {
|
|
115
|
+
let done = 0
|
|
51
116
|
let total = 0
|
|
52
117
|
while (true) {
|
|
118
|
+
if (signal && signal.aborted) throw { name: 'AbortError' }
|
|
53
119
|
const nodes = agent.session.surface.nodes
|
|
54
120
|
if (!Array.isArray(nodes) || nodes.length <= request.keep) break
|
|
55
|
-
const
|
|
121
|
+
const toCompress = nodes.length - request.keep
|
|
122
|
+
if (total === 0) total = toCompress
|
|
123
|
+
const endIndex = Math.min(toCompress - 1, request.mode === 'batch' ? 19 : toCompress - 1)
|
|
56
124
|
if (endIndex < 0) break
|
|
57
|
-
const result = await compaction.compactRegion(nodes[0], nodes[endIndex], agent)
|
|
58
|
-
|
|
125
|
+
const result = await compaction.compactRegion(nodes[0], nodes[endIndex], agent, signal)
|
|
126
|
+
done += Array.isArray(result.shadowedSeqs) ? result.shadowedSeqs.length : 0
|
|
127
|
+
const rec = newestCompactionNode(agent.session.surface.nodes)
|
|
128
|
+
if (rec) {
|
|
129
|
+
records.push({ time: rec.time, shadowedItemCount: rec.shadowedItemCount, shadowedTokenCount: rec.shadowedTokenCount, summary: rec.summary })
|
|
130
|
+
}
|
|
131
|
+
if (onProgress) await onProgress({ nonce: request.nonce, done, total })
|
|
59
132
|
if (request.mode !== 'batch') break
|
|
60
133
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
: `没有可压缩的历史,已保留最近 ${request.keep} 条。`,
|
|
67
|
-
}
|
|
134
|
+
const file = await writeArchiveFile(request.sessionId, request.keep, request.mode, records, done)
|
|
135
|
+
const message = done
|
|
136
|
+
? `已压缩 ${done} 条历史,保留最近 ${request.keep} 条${done > 0 && file ? `;结果已保存到 ${file}` : ''}。`
|
|
137
|
+
: `没有可压缩的历史,已保留最近 ${request.keep} 条。`
|
|
138
|
+
return { ok: true, shadowed: done, message, cancelled: false, file }
|
|
68
139
|
} catch (error) {
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
persistence: '摘要生成完成,但保存会话失败。',
|
|
75
|
-
}
|
|
76
|
-
return { ok: false, shadowed: 0, message: messages[error && error.code] || `压缩失败:${error && error.message ? error.message : String(error)}` }
|
|
140
|
+
const cancelled = !!(signal && signal.aborted) || (error && error.name === 'AbortError')
|
|
141
|
+
const reason = cancelled
|
|
142
|
+
? '已取消压缩。'
|
|
143
|
+
: ERROR_MESSAGES[error && error.code] || `压缩失败:${error && error.message ? error.message : String(error)}`
|
|
144
|
+
return { ok: false, shadowed: 0, message: reason, cancelled, file: '' }
|
|
77
145
|
}
|
|
78
146
|
}
|
|
79
147
|
|
|
@@ -86,17 +154,38 @@ function apply(ctx, config) {
|
|
|
86
154
|
let getter = () => config
|
|
87
155
|
let lastHandledNonce = null
|
|
88
156
|
let handling = null
|
|
157
|
+
const controllers = new Map() // sessionId -> AbortController
|
|
158
|
+
|
|
89
159
|
const handle = () => {
|
|
160
|
+
const current = getter()
|
|
161
|
+
const request = current && current.request
|
|
162
|
+
if (request === null || request === undefined) return
|
|
163
|
+
|
|
164
|
+
// Cancel: abort any active compaction for this session.
|
|
165
|
+
if (request.action === 'cancel') {
|
|
166
|
+
const controller = controllers.get(request.sessionId)
|
|
167
|
+
if (!controller) {
|
|
168
|
+
void ctx.settings.update(NS, { request: null }).catch(() => {})
|
|
169
|
+
return
|
|
170
|
+
}
|
|
171
|
+
controller.abort()
|
|
172
|
+
return // the running task publishes the cancelled lastRun and clears request
|
|
173
|
+
}
|
|
174
|
+
|
|
90
175
|
if (handling !== null) return
|
|
176
|
+
if (request.nonce === lastHandledNonce) return
|
|
177
|
+
lastHandledNonce = request.nonce
|
|
91
178
|
handling = (async () => {
|
|
179
|
+
const controller = new AbortController()
|
|
180
|
+
controllers.set(request.sessionId, controller)
|
|
92
181
|
try {
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const result = await executeCompact(ctx, ctx.agents, request)
|
|
182
|
+
const onProgress = async (p) => {
|
|
183
|
+
try { await ctx.settings.update(NS, { progress: p }) } catch {}
|
|
184
|
+
}
|
|
185
|
+
const result = await executeCompact(ctx, ctx.agents, request, controller.signal, onProgress)
|
|
98
186
|
await ctx.settings.update(NS, {
|
|
99
187
|
request: null,
|
|
188
|
+
progress: null,
|
|
100
189
|
lastRun: {
|
|
101
190
|
at: Date.now(),
|
|
102
191
|
keep: request.keep,
|
|
@@ -104,15 +193,26 @@ function apply(ctx, config) {
|
|
|
104
193
|
ok: result.ok,
|
|
105
194
|
shadowed: result.shadowed,
|
|
106
195
|
message: result.message,
|
|
196
|
+
cancelled: !!result.cancelled,
|
|
197
|
+
file: result.file || '',
|
|
107
198
|
},
|
|
108
199
|
})
|
|
109
200
|
} catch (error) {
|
|
110
201
|
ctx.logger.warn('manual-compact: handling a request failed: %s', String(error))
|
|
202
|
+
try {
|
|
203
|
+
await ctx.settings.update(NS, {
|
|
204
|
+
request: null,
|
|
205
|
+
progress: null,
|
|
206
|
+
lastRun: { at: Date.now(), keep: request.keep, mode: request.mode, ok: false, shadowed: 0, message: String(error), cancelled: (controller.signal && controller.signal.aborted), file: '' },
|
|
207
|
+
})
|
|
208
|
+
} catch {}
|
|
111
209
|
} finally {
|
|
210
|
+
controllers.delete(request.sessionId)
|
|
112
211
|
handling = null
|
|
113
212
|
}
|
|
114
213
|
})()
|
|
115
214
|
}
|
|
215
|
+
|
|
116
216
|
installSettingsSection(ctx, NS, Config, config, {
|
|
117
217
|
setSource: (current) => {
|
|
118
218
|
getter = current
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-manual-compact-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Manual context compaction for DeepSeek Harness: keep the latest N conversation items with stop or batch mode and a per-session compaction archive — embedded in the context meter popup when the meter panel slot exists, or a composer button otherwise.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -31,16 +31,16 @@
|
|
|
31
31
|
"client": {
|
|
32
32
|
"inject": [
|
|
33
33
|
"@deepseek-ai/dsh-client-ui-conversation",
|
|
34
|
-
"@deepseek-ai/dsh-settings"
|
|
34
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
35
35
|
],
|
|
36
36
|
"platform": "web"
|
|
37
37
|
}
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
41
|
-
"@deepseek-ai/dsh-agent": "^0.1.
|
|
42
|
-
"@deepseek-ai/dsh-settings": "^0.1.
|
|
43
|
-
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.
|
|
41
|
+
"@deepseek-ai/dsh-agent": "^0.1.1-rc.1",
|
|
42
|
+
"@deepseek-ai/dsh-settings": "^0.1.1-rc.1",
|
|
43
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.1-rc.1",
|
|
44
44
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
45
45
|
"react": "^18.2.0"
|
|
46
46
|
},
|
|
@@ -54,11 +54,11 @@
|
|
|
54
54
|
},
|
|
55
55
|
"repository": {
|
|
56
56
|
"type": "git",
|
|
57
|
-
"url": "git+https://github.com/kimkingyu/dsh-manual-compact.git"
|
|
57
|
+
"url": "git+https://github.com/kimkingyu/dsh-manual-compact-plugin.git"
|
|
58
58
|
},
|
|
59
|
-
"homepage": "https://github.com/kimkingyu/dsh-manual-compact#readme",
|
|
59
|
+
"homepage": "https://github.com/kimkingyu/dsh-manual-compact-plugin#readme",
|
|
60
60
|
"bugs": {
|
|
61
|
-
"url": "https://github.com/kimkingyu/dsh-manual-compact/issues"
|
|
61
|
+
"url": "https://github.com/kimkingyu/dsh-manual-compact-plugin/issues"
|
|
62
62
|
},
|
|
63
63
|
"publishConfig": {
|
|
64
64
|
"access": "public"
|