dsh-as-aistudio 0.5.16 → 0.5.18

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/CHANGELOG.md CHANGED
@@ -4,6 +4,10 @@
4
4
 
5
5
  ## 中文
6
6
 
7
+ **0.5.18** —— 跟进 dsh-log-trim 0.7.5(裁掉被检查点遮蔽的前缀,窗口数真的降下来)。
8
+
9
+ **0.5.17** —— 跟进 dsh-log-trim 0.7.4(启动立即扫描、最近日志优先、解锁后补裁)。
10
+
7
11
  **0.5.16** —— 跟进 dsh-log-trim 0.7.3(迟到 tool/result 归位,窗口裁剪不再被校验挡住)。
8
12
 
9
13
  **0.5.15** —— 跟进 dsh-log-trim 0.7.2(重建可用:标题 / 工具通知 / seq 引用全部重映射)。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-as-aistudio",
3
- "version": "0.5.16",
3
+ "version": "0.5.18",
4
4
  "description": "Google-AI-Studio-style turn controls for DeepSeek Harness, in one install: edit a prompt and re-run it, re-run a reply in place, delete a turn from the model context, render sent prompts as Markdown, and trim idle session logs on boot. Self-contained: the plugin list shows this one row, and the five components (four actions + one maintenance) are vendored inside it - installing the studio installs nothing else.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/client.js CHANGED
@@ -9642,7 +9642,7 @@ window.__ModuleLoader__.load({
9642
9642
  const react = require('react')
9643
9643
  const { jsx, jsxs } = require('react/jsx-runtime')
9644
9644
 
9645
- const PLUGIN_VERSION = '0.7.3'
9645
+ const PLUGIN_VERSION = '0.7.5'
9646
9646
  const ROUTE_PREFIX = '/api/dsh-log-trim'
9647
9647
 
9648
9648
  /** The knobs this card edits, in the order they are drawn. */
@@ -10168,7 +10168,7 @@ window.__ModuleLoader__.load({
10168
10168
  const NS = 'dsh-as-aistudio'
10169
10169
 
10170
10170
  /** Keep in sync with package.json and src/components.js. */
10171
- const PLUGIN_VERSION = '0.5.16'
10171
+ const PLUGIN_VERSION = '0.5.18'
10172
10172
 
10173
10173
  /** Presence marker the live verifier reads. */
10174
10174
  const DEBUG_KEY = '__DSH_AS_AISTUDIO__'
package/src/components.js CHANGED
@@ -26,7 +26,7 @@
26
26
  export const STUDIO_ID = 'dsh-as-aistudio'
27
27
 
28
28
  /** Keep in sync with package.json and src/client.js. */
29
- export const STUDIO_VERSION = '0.5.16'
29
+ export const STUDIO_VERSION = '0.5.18'
30
30
 
31
31
  /**
32
32
  * The AI Studio action strip this studio composes, in the order the user meets
@@ -1,6 +1,6 @@
1
1
  // dsh-edit-turn host half (dsh-edit-turn.js), VENDORED by tools/vendor.mjs - DO NOT EDIT.
2
2
  //
3
- // Source: ../dsh-edit-turn/lib/index.js (v0.5.20, sha256 2e006e68f0591665)
3
+ // Source: ../dsh-edit-turn/lib/index.js (v0.5.21, sha256 1502010fdd847526)
4
4
  // Regenerate with `npm run vendor`; test/sync.test.js fails when this is stale.
5
5
  //
6
6
  // src/shell.js imports the copy named after the component, which is why the
@@ -85,7 +85,7 @@ export const PLUGIN_ID = 'dsh-edit-turn'
85
85
  export const name = PLUGIN_ID
86
86
 
87
87
  /** Keep in sync with package.json and lib/client.js. */
88
- export const PLUGIN_VERSION = '0.5.20'
88
+ export const PLUGIN_VERSION = '0.5.21'
89
89
 
90
90
  // A ring of the last few requests, answering "did the browser half even ask, and
91
91
  // what did it get?" without needing its console. Read-only diagnostics: the
@@ -1,6 +1,6 @@
1
1
  // dsh-edit-turn host half (dsh-edit-turn.patch.js), VENDORED by tools/vendor.mjs - DO NOT EDIT.
2
2
  //
3
- // Source: ../dsh-edit-turn/lib/patch.js (v0.5.20, sha256 5e1e8cce1d168f6c)
3
+ // Source: ../dsh-edit-turn/lib/patch.js (v0.5.21, sha256 5e1e8cce1d168f6c)
4
4
  // Regenerate with `npm run vendor`; test/sync.test.js fails when this is stale.
5
5
  //
6
6
  // src/shell.js imports the copy named after the component, which is why the
@@ -1,6 +1,6 @@
1
1
  // dsh-log-trim host half (dsh-log-trim.flatten.js), VENDORED by tools/vendor.mjs - DO NOT EDIT.
2
2
  //
3
- // Source: ../dsh-log-trim/lib/flatten.js (v0.7.3, sha256 3aa1fdcbb120ab06)
3
+ // Source: ../dsh-log-trim/lib/flatten.js (v0.7.5, sha256 3aa1fdcbb120ab06)
4
4
  // Regenerate with `npm run vendor`; test/sync.test.js fails when this is stale.
5
5
  //
6
6
  // src/shell.js imports the copy named after the component, which is why the
@@ -1,6 +1,6 @@
1
1
  // dsh-log-trim host half (dsh-log-trim.goal-repair.js), VENDORED by tools/vendor.mjs - DO NOT EDIT.
2
2
  //
3
- // Source: ../dsh-log-trim/lib/goal-repair.js (v0.7.3, sha256 0801a28f35667ee7)
3
+ // Source: ../dsh-log-trim/lib/goal-repair.js (v0.7.5, sha256 0801a28f35667ee7)
4
4
  // Regenerate with `npm run vendor`; test/sync.test.js fails when this is stale.
5
5
  //
6
6
  // src/shell.js imports the copy named after the component, which is why the
@@ -1,6 +1,6 @@
1
1
  // dsh-log-trim host half (dsh-log-trim.host-libs.mjs), VENDORED by tools/vendor.mjs - DO NOT EDIT.
2
2
  //
3
- // Source: ../dsh-log-trim/lib/host-libs.mjs (v0.7.3, sha256 5ebed01988b5bfcf)
3
+ // Source: ../dsh-log-trim/lib/host-libs.mjs (v0.7.5, sha256 5ebed01988b5bfcf)
4
4
  // Regenerate with `npm run vendor`; test/sync.test.js fails when this is stale.
5
5
  //
6
6
  // src/shell.js imports the copy named after the component, which is why the
@@ -1,6 +1,6 @@
1
1
  // dsh-log-trim host half (dsh-log-trim.js), VENDORED by tools/vendor.mjs - DO NOT EDIT.
2
2
  //
3
- // Source: ../dsh-log-trim/lib/index.js (v0.7.3, sha256 e35a3a2d18c9a4fa)
3
+ // Source: ../dsh-log-trim/lib/index.js (v0.7.5, sha256 a32940b526c93896)
4
4
  // Regenerate with `npm run vendor`; test/sync.test.js fails when this is stale.
5
5
  //
6
6
  // src/shell.js imports the copy named after the component, which is why the
@@ -44,7 +44,7 @@ import { readLedger, recordFor } from './dsh-log-trim.ledger.js'
44
44
 
45
45
  export const name = 'dsh-log-trim'
46
46
  export const PLUGIN_ID = name
47
- export const PLUGIN_VERSION = '0.7.3'
47
+ export const PLUGIN_VERSION = '0.7.5'
48
48
  export const ROUTE_PREFIX = '/api/dsh-log-trim'
49
49
 
50
50
  /**
@@ -62,7 +62,12 @@ const LEGACY_MEMORY_FILE = 'dsh-session-compact/scan-memory.json'
62
62
  /** Where the settings card's values are kept. */
63
63
  const CONFIG_FILE = 'dsh-log-trim/config.json'
64
64
  /** 开机扫描先等一下界面:第一屏还没拿到会话列表时不该跟它抢线程池。 */
65
- const BOOT_SCAN_DELAY_MS = 3000
65
+ // 启动扫描的延迟。worker 扫描不占主线程,所以越早越好:宿主会在启动后很快
66
+ // 打开上次的会话并持有 session.lock,晚一步就永远轮不到那个会话。
67
+ const BOOT_SCAN_DELAY_MS = 0
68
+ // 被锁住的会话多久后再试一次;试满 20 次(10 分钟)就放弃,等下次启动。
69
+ const LOCKED_RETRY_MS = 30000
70
+ const LOCKED_RETRIES = 20
66
71
  /** 重命名前的目录,只读兜底。 */
67
72
  const LEGACY_CONFIG_FILE = 'dsh-session-compact/config.json'
68
73
 
@@ -162,6 +167,50 @@ async function noteWindowTrim(logFile, result, record, beforeEvents = [], afterE
162
167
  }
163
168
  }
164
169
 
170
+
171
+ /**
172
+ * 被宿主打开的会话先记下来,每隔 30 秒看一次锁还在不在;一解锁就单独裁它。
173
+ *
174
+ * 启动扫描唯一的空窗是「宿主还没打开会话」,而 DSH 会在启动后很快恢复上次的会话。
175
+ * 赶不上就退而求其次:等用户切走、宿主释放 session.lock 之后再补一刀。
176
+ *
177
+ * @param {object[]} locked - 带 logFile 的被锁会话。
178
+ * @param {object} config - 解析后的配置。
179
+ * @param {object} ctx - 插件上下文(只用 logger)。
180
+ * @param {boolean} cancelled - 启动扫描是否已被取消。
181
+ * @param {() => boolean} isCancelled - 重新读取取消状态。
182
+ */
183
+ function watchUnlocked(locked, config, ctx, cancelled, isCancelled) {
184
+ let remaining = [...locked]
185
+ let attempts = 0
186
+ const timer = setInterval(() => {
187
+ attempts += 1
188
+ if (cancelled === true || isCancelled() === true || attempts > LOCKED_RETRIES) {
189
+ clearInterval(timer)
190
+ return
191
+ }
192
+ void (async () => {
193
+ const next = []
194
+ for (const item of remaining) {
195
+ if (isSessionLocked(item.logFile)) {
196
+ next.push(item)
197
+ continue
198
+ }
199
+ try {
200
+ await trimOne(item.logFile, config)
201
+ } catch (error) {
202
+ if (typeof ctx.logger?.warn === 'function') {
203
+ ctx.logger.warn(`[dsh-log-trim] 解锁后裁剪失败(${item.sessionId}):${error instanceof Error ? error.message : String(error)}`)
204
+ }
205
+ }
206
+ }
207
+ remaining = next
208
+ if (remaining.length === 0) clearInterval(timer)
209
+ })()
210
+ }, LOCKED_RETRY_MS)
211
+ if (typeof timer.unref === 'function') timer.unref()
212
+ }
213
+
165
214
  export async function trimOne(logFile, config) {
166
215
  if (isSessionLocked(logFile)) {
167
216
  throw new Error('这个会话正被宿主打开着(session.lock)。先切到别的对话或重启 DSH,再压缩它')
@@ -921,7 +970,15 @@ export async function runScan(config, logger = {}) {
921
970
  summary.roots = roots
922
971
  const legacy = roots.flatMap((root) => listLegacy(root))
923
972
  summary.legacy = { files: legacy.length, bytes: legacy.reduce((sum, item) => sum + item.bytes, 0) }
924
- const allLogs = roots.flatMap((root) => listLogs(root))
973
+ // 最近改过的日志先扫:宿主启动后最先打开的正是它们,早一步就有机会在
974
+ // session.lock 出现之前把窗口裁掉。
975
+ const allLogs = roots.flatMap((root) => listLogs(root)).sort((left, right) => {
976
+ try {
977
+ return fs.statSync(right).mtimeMs - fs.statSync(left).mtimeMs
978
+ } catch {
979
+ return 0
980
+ }
981
+ })
925
982
  for (const logFile of allLogs) {
926
983
  // 每个会话之间让出一次事件循环:宿主还要应答界面和工具调用,
927
984
  // 一轮扫描(162 个会话)不该把它按住。
@@ -929,7 +986,7 @@ export async function runScan(config, logger = {}) {
929
986
  summary.scanned += 1
930
987
  const sessionId = path.basename(path.dirname(logFile))
931
988
  if (isSessionLocked(logFile)) {
932
- summary.skipped.push({ sessionId, reason: '正被宿主打开(session.lock)' })
989
+ summary.skipped.push({ sessionId, logFile, reason: '正被宿主打开(session.lock)' })
933
990
  continue
934
991
  }
935
992
  // A log the host cannot load is worse than a big log: the session vanishes
@@ -1374,7 +1431,11 @@ export function apply(ctx, config = {}) {
1374
1431
  // 先等界面第一屏拿完数据再干活:开机那几秒是宿主最要紧的窗口。
1375
1432
  await new Promise((resolve) => setTimeout(resolve, BOOT_SCAN_DELAY_MS))
1376
1433
  if (cancelled) return
1377
- await run()
1434
+ const summary = await run()
1435
+ if (!cancelled && summary && Array.isArray(summary.skipped)) {
1436
+ const locked = summary.skipped.filter((item) => typeof item?.logFile === 'string' && String(item.reason ?? '').includes('session.lock'))
1437
+ if (locked.length > 0) watchUnlocked(locked, resolved, ctx, cancelled, () => cancelled)
1438
+ }
1378
1439
  } catch (error) {
1379
1440
  if (!cancelled && typeof ctx.logger?.warn === 'function') {
1380
1441
  ctx.logger.warn(`[dsh-log-trim] 扫描失败:${error instanceof Error ? error.message : String(error)}`)
@@ -1,6 +1,6 @@
1
1
  // dsh-log-trim host half (dsh-log-trim.ledger.js), VENDORED by tools/vendor.mjs - DO NOT EDIT.
2
2
  //
3
- // Source: ../dsh-log-trim/lib/ledger.js (v0.7.3, sha256 5ca2460b42a3a776)
3
+ // Source: ../dsh-log-trim/lib/ledger.js (v0.7.5, sha256 5ca2460b42a3a776)
4
4
  // Regenerate with `npm run vendor`; test/sync.test.js fails when this is stale.
5
5
  //
6
6
  // src/shell.js imports the copy named after the component, which is why the
@@ -1,6 +1,6 @@
1
1
  // dsh-log-trim host half (dsh-log-trim.lossless.js), VENDORED by tools/vendor.mjs - DO NOT EDIT.
2
2
  //
3
- // Source: ../dsh-log-trim/lib/lossless.js (v0.7.3, sha256 7e8478a2fd2ec10b)
3
+ // Source: ../dsh-log-trim/lib/lossless.js (v0.7.5, sha256 7e8478a2fd2ec10b)
4
4
  // Regenerate with `npm run vendor`; test/sync.test.js fails when this is stale.
5
5
  //
6
6
  // src/shell.js imports the copy named after the component, which is why the
@@ -1,6 +1,6 @@
1
1
  // dsh-log-trim host half (dsh-log-trim.roots.js), VENDORED by tools/vendor.mjs - DO NOT EDIT.
2
2
  //
3
- // Source: ../dsh-log-trim/lib/roots.js (v0.7.3, sha256 028d9c12a395aaab)
3
+ // Source: ../dsh-log-trim/lib/roots.js (v0.7.5, sha256 028d9c12a395aaab)
4
4
  // Regenerate with `npm run vendor`; test/sync.test.js fails when this is stale.
5
5
  //
6
6
  // src/shell.js imports the copy named after the component, which is why the
@@ -1,6 +1,6 @@
1
1
  // dsh-log-trim host half (dsh-log-trim.vendor.compact-session.mjs), VENDORED by tools/vendor.mjs - DO NOT EDIT.
2
2
  //
3
- // Source: ../dsh-log-trim/lib/vendor.compact-session.mjs (v0.7.3, sha256 1b0499e0c4c11122)
3
+ // Source: ../dsh-log-trim/lib/vendor.compact-session.mjs (v0.7.5, sha256 f0c5dcc018253ea4)
4
4
  // Regenerate with `npm run vendor`; test/sync.test.js fails when this is stale.
5
5
  //
6
6
  // src/shell.js imports the copy named after the component, which is why the
@@ -2142,17 +2142,70 @@ export function repairLateToolResults(events) {
2142
2142
  return { events: list, moved, dropped }
2143
2143
  }
2144
2144
 
2145
+
2146
+ /**
2147
+ * 被 checkpoint 的 `replace` 区间盖住的前缀:模型与界面都看不到,留着只是占空间,
2148
+ * 窗口页还会把它算成一窗。
2149
+ *
2150
+ * 不逐行删(会切坏 step/turn 括号),而是把保留区改成「连续尾巴 + frame」:
2151
+ * 从最后一个存活 checkpoint 的 replace 末尾之后、对齐到轮次起点开始保留,
2152
+ * 再加系统提示词与设置事件。这样结构始终是自洽的。
2153
+ *
2154
+ * @param {object[]} events - 候选保留事件(keepLastWindows 的结果)。
2155
+ * @returns {{ events: object[], dropped: number }} 结果。
2156
+ */
2157
+ function dropShadowedPrefix(events) {
2158
+ const checkpoints = events.filter((event) => event.type === 'user/message' && event.data?.source?.kind === 'compact-checkpoint')
2159
+ const last = checkpoints[checkpoints.length - 1]
2160
+ const shadowEnd = last !== undefined && typeof last.surfaceOp?.endSeq === 'number' ? last.surfaceOp.endSeq : null
2161
+ if (shadowEnd === null) return { events, dropped: 0 }
2162
+ const aligned = events.find((event) => event.seq > shadowEnd && event.type === 'turn/start')
2163
+ if (aligned === undefined) return { events, dropped: 0 }
2164
+ const liveStart = aligned.seq
2165
+ const frame = new Set()
2166
+ const visible = foldSurface(events).visible
2167
+ const system = visible.map((seq) => events.find((event) => event.seq === seq)).find((event) => event !== undefined && (event.type === 'system/message' || event.type === 'developer/message'))
2168
+ if (system !== undefined) frame.add(system.seq)
2169
+ for (const type of ['agent-preset/selected', 'permission/preset', 'sandbox/mode', 'approval/policy', 'session/title', 'session/end-seed']) {
2170
+ const hit = events.filter((event) => event.type === type && event.seq < liveStart).pop()
2171
+ if (hit !== undefined) frame.add(hit.seq)
2172
+ }
2173
+ // 结构性事件不受“前缀”限制:compaction 组、seeded 标记、inbox 拼接都是按顺序
2174
+ // 重放的记账,丢掉半组会让整份日志装不上;它们不占模型视图,留着也便宜。
2175
+ const structural = (event) =>
2176
+ String(event.type).startsWith('compaction/') ||
2177
+ String(event.type).startsWith('session/') ||
2178
+ event.type === 'agent/inbox/spliced'
2179
+ const out = events.filter((event) => event.seq >= liveStart || frame.has(event.seq) || structural(event))
2180
+ // compaction 是一组(start / summary / end 同一个 compactionId):end 落在尾巴里而
2181
+ // start/summary 落在被丢的前缀里时,宿主要求「成功的 compaction/end 必须有一条 summary」。
2182
+ // 只要有同组的行留下,就把整组补回来(都是记账行,不影响模型视图)。
2183
+ const compactionIds = new Set()
2184
+ for (const event of out) {
2185
+ if (typeof event.data?.compactionId === 'string') compactionIds.add(event.data.compactionId)
2186
+ }
2187
+ if (compactionIds.size > 0) {
2188
+ for (const event of events) {
2189
+ if (typeof event.data?.compactionId === 'string' && compactionIds.has(event.data.compactionId) && !out.includes(event)) out.push(event)
2190
+ }
2191
+ out.sort((left, right) => left.seq - right.seq)
2192
+ }
2193
+ return { events: out, dropped: events.length - out.length }
2194
+ }
2195
+
2145
2196
  export async function stageTrim(logFile, keep, options = {}) {
2146
2197
  if (isSessionLocked(logFile)) {
2147
2198
  throw new Error('会话正被宿主持有(session.lock 被打开),拒绝改动;请先关掉该会话或重启宿主')
2148
2199
  }
2149
2200
  const original = await readLogAsync(logFile)
2150
2201
  const trimmed = keepLastWindows(original.events, keep)
2151
- if (trimmed.cutSeq === null) throw new Error(`只有 ${trimmed.windows} 个窗口,不需要裁`)
2152
2202
  // 旧回合的流式回放记录:与 data.message.content 逐块重复,留最近几轮就够。
2153
2203
  const streamKeepTurns = options.streamKeepTurns === undefined ? Infinity : options.streamKeepTurns
2154
- const stripped = stripOldStreams(trimmed.events, streamKeepTurns)
2204
+ // 先丢掉被 checkpoint 遮蔽的前缀(连续尾巴 + frame),再清流式回放。
2205
+ const shadowed = options.shadowPrefix === false ? { events: trimmed.events, dropped: 0 } : dropShadowedPrefix(trimmed.events)
2206
+ const stripped = stripOldStreams(shadowed.events, streamKeepTurns)
2155
2207
  assertNoGoalEventsDropped(original.events, stripped.events)
2208
+ if (trimmed.cutSeq === null && shadowed.dropped === 0) throw new Error(`只有 ${trimmed.windows} 个窗口,不需要裁`)
2156
2209
  let renamed = renumber(stripped.events)
2157
2210
  const repaired = repairLateToolResults(renamed.events)
2158
2211
  if (repaired.moved > 0 || repaired.dropped > 0) {
@@ -2186,7 +2239,7 @@ export async function stageTrim(logFile, keep, options = {}) {
2186
2239
  backup,
2187
2240
  before: { events: original.events.length, bytes: original.compressedBytes, windows: trimmed.windows },
2188
2241
  after: { events: renamed.events.length, bytes: (await fs.promises.stat(staging)).size },
2189
- dropped: trimmed.dropped,
2242
+ dropped: trimmed.dropped + shadowed.dropped,
2190
2243
  refsFixed: renamed.refsFixed,
2191
2244
  titlesDropped: renamed.titlesDropped,
2192
2245
  compactionDropped: renamed.compactionDropped,
@@ -2224,7 +2277,7 @@ export async function commitTrim(staged, logFile) {
2224
2277
  * @returns {Promise<object>} 结果摘要。
2225
2278
  */
2226
2279
  export async function applyTrim(logFile, keep, options = {}) {
2227
- const staged = await stageTrim(logFile, keep, options)
2280
+ let staged = await stageTrim(logFile, keep, options)
2228
2281
  if (options.verify !== false) {
2229
2282
  let result
2230
2283
  try {
@@ -2236,6 +2289,20 @@ export async function applyTrim(logFile, keep, options = {}) {
2236
2289
  }
2237
2290
  if (!result.ok) {
2238
2291
  fs.rmSync(staged.staging, { force: true })
2292
+ // 丢掉「被 checkpoint 遮蔽的前缀」是收益、不是前提:这份日志上它可能撞到
2293
+ // compaction / 标题 / inbox 的结构约束。退回不丢前缀的老做法再验一次,
2294
+ // 两次都不过才真的失败。
2295
+ if (options.shadowPrefix !== false) {
2296
+ staged = await stageTrim(logFile, keep, { ...options, shadowPrefix: false })
2297
+ const retried = await (async () => {
2298
+ const { verifyLog } = await import('./dsh-log-trim.verify-session-log.mjs')
2299
+ return verifyLog(staged.staging)
2300
+ })()
2301
+ if (retried.ok) return commitTrim(staged, logFile)
2302
+ fs.rmSync(staged.staging, { force: true })
2303
+ const bad = retried.checks.filter((check) => !check.ok).map((check) => `${check.name} ${check.detail}`).join(';')
2304
+ throw new Error(`裁剪结果没通过宿主校验,未写入:${bad}`)
2305
+ }
2239
2306
  const bad = result.checks.filter((check) => !check.ok).map((check) => `${check.name} ${check.detail}`).join(';')
2240
2307
  throw new Error(`裁剪结果没通过宿主校验,未写入:${bad}`)
2241
2308
  }
@@ -1,6 +1,6 @@
1
1
  // dsh-log-trim host half (dsh-log-trim.verify-session-log.mjs), VENDORED by tools/vendor.mjs - DO NOT EDIT.
2
2
  //
3
- // Source: ../dsh-log-trim/lib/verify-session-log.mjs (v0.7.3, sha256 7cf835c053942961)
3
+ // Source: ../dsh-log-trim/lib/verify-session-log.mjs (v0.7.5, sha256 7cf835c053942961)
4
4
  // Regenerate with `npm run vendor`; test/sync.test.js fails when this is stale.
5
5
  //
6
6
  // src/shell.js imports the copy named after the component, which is why the
@@ -1,6 +1,6 @@
1
1
  // dsh-log-trim host half (dsh-log-trim.worker.mjs), VENDORED by tools/vendor.mjs - DO NOT EDIT.
2
2
  //
3
- // Source: ../dsh-log-trim/lib/worker.mjs (v0.7.3, sha256 675a759a767b7e38)
3
+ // Source: ../dsh-log-trim/lib/worker.mjs (v0.7.5, sha256 675a759a767b7e38)
4
4
  // Regenerate with `npm run vendor`; test/sync.test.js fails when this is stale.
5
5
  //
6
6
  // src/shell.js imports the copy named after the component, which is why the
@@ -1,7 +1,7 @@
1
1
  {
2
- "dsh-edit-turn": "0.5.20",
2
+ "dsh-edit-turn": "0.5.21",
3
3
  "dsh-rerun-turn": "0.2.11",
4
4
  "dsh-delete-turn": "0.2.4",
5
5
  "dsh-markdown-bubble": "0.1.5",
6
- "dsh-log-trim": "0.7.3"
6
+ "dsh-log-trim": "0.7.5"
7
7
  }