dsh-context-compression-improved 0.2.1 → 0.3.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.
Files changed (80) hide show
  1. package/.gitattributes +1 -1
  2. package/.github/workflows/ci.yml +1 -7
  3. package/CHANGELOG.ja.md +18 -21
  4. package/CHANGELOG.ko.md +17 -21
  5. package/CHANGELOG.md +16 -17
  6. package/CHANGELOG.zh.md +15 -18
  7. package/CONTRIBUTING.md +1 -1
  8. package/README.ja.md +1 -20
  9. package/README.ko.md +12 -30
  10. package/README.md +1 -19
  11. package/README.zh.md +5 -21
  12. package/THIRD_PARTY_NOTICES.md +2 -2
  13. package/docs/compat-0.1.5-report.md +77 -0
  14. package/docs/installation.ja.md +6 -4
  15. package/docs/installation.ko.md +9 -7
  16. package/docs/installation.md +3 -1
  17. package/docs/installation.zh.md +3 -2
  18. package/docs/repair-log.md +54 -33
  19. package/eslint.config.js +2 -2
  20. package/package.json +56 -36
  21. package/packages/selector/README.md +7 -12
  22. package/packages/selector/README.zh.md +6 -13
  23. package/packages/selector/THIRD_PARTY_NOTICES.md +2 -8
  24. package/packages/selector/cordis.patch.yml +7 -5
  25. package/packages/selector/dsh.plugin.json +2 -2
  26. package/packages/selector/lib/client.d.ts +31 -5
  27. package/packages/selector/lib/client.js +100 -82
  28. package/packages/selector/lib/index.d.ts +8 -20
  29. package/packages/selector/lib/index.js +9 -14
  30. package/packages/selector/lib/invariant.js +4 -4
  31. package/packages/selector/lib/pruner.d.ts +13 -4
  32. package/packages/selector/lib/pruner.js +91 -46
  33. package/packages/selector/lib/tail-trim.js +13 -4
  34. package/packages/selector/package.json +23 -23
  35. package/packages/selector/screenshots.json +1 -4
  36. package/packages/selector/src/client/CompressionProfileControls.tsx +5 -8
  37. package/packages/selector/src/client/CompressionProfileSelector.tsx +9 -5
  38. package/packages/selector/src/client/EstimatorControls.tsx +28 -32
  39. package/packages/selector/src/client/index.ts +101 -63
  40. package/packages/selector/src/client/locales.ts +0 -2
  41. package/packages/selector/src/client/preset-options.ts +49 -35
  42. package/packages/selector/src/client/settings-section.tsx +4 -6
  43. package/packages/selector/src/deepseek-v4-tokenizer.ts +0 -5
  44. package/packages/selector/src/index.ts +41 -46
  45. package/packages/selector/src/invariant.ts +5 -5
  46. package/packages/selector/src/pruner.ts +67 -36
  47. package/packages/selector/src/runtime/measurement.ts +6 -2
  48. package/packages/selector/src/runtime/session-events.ts +14 -1
  49. package/packages/selector/src/runtime/tail-trim.ts +4 -4
  50. package/packages/selector/src/runtime/tokenpilot/estimator.ts +34 -3
  51. package/packages/selector/src/runtime/types.ts +1 -1
  52. package/packages/selector/tests/auto-compact.client.spec.tsx +0 -13
  53. package/packages/selector/tests/built/client-artifact.spec.ts +5 -1
  54. package/packages/selector/tests/code-skeleton.client.spec.ts +2 -1
  55. package/packages/selector/tests/custom-contract.client.spec.ts +2 -1
  56. package/packages/selector/tests/estimator-channel.client.spec.tsx +16 -11
  57. package/packages/selector/tests/estimator-route-registration.host.spec.ts +12 -0
  58. package/packages/selector/tests/host-preset-overlay.host.spec.ts +6 -4
  59. package/packages/selector/tests/preset-options-write.client.spec.ts +87 -79
  60. package/packages/selector/tests/preset-overlay-loader.e2e.host.spec.ts +17 -12
  61. package/packages/selector/tests/preset-overlay.host.spec.ts +5 -2
  62. package/packages/selector/tests/profiles.client.spec.tsx +3 -3
  63. package/packages/selector/tests/public/package-contract.client.spec.ts +27 -3
  64. package/packages/selector/tests/runtime/public/public-runtime.spec.ts +103 -81
  65. package/packages/selector/tests/runtime/session-events.spec.ts +1 -1
  66. package/packages/selector/tests/settings-seat.client.spec.ts +86 -0
  67. package/packages/selector/tests/standing-generation.host.spec.ts +88 -71
  68. package/packages/selector/tests/subagent-cache-reuse.host.spec.ts +24 -21
  69. package/pnpm-workspace.yaml +52 -5
  70. package/scripts/capture-profile-baseline.mjs +42 -0
  71. package/scripts/generate-tokenizer-fixtures.py +5 -5
  72. package/scripts/generate-vision-fixtures.py +2 -2
  73. package/scripts/{packed-components-smoke.ts → packed-components-smoke.mjs} +116 -119
  74. package/scripts/{packed-install-e2e.ts → packed-install-e2e.mjs} +188 -160
  75. package/scripts/{verify-release.ts → verify-release.mjs} +70 -94
  76. package/tests/TEST_INVENTORY.md +6 -7
  77. package/scripts/capture-profile-baseline.ts +0 -80
  78. package/tsconfig.scripts.json +0 -13
  79. /package/{packages/selector/assets/screenshots → docs/assets}/context-compression-selector-profiles.jpg +0 -0
  80. /package/{packages/selector/assets/screenshots → docs/assets}/context-compression-selector-settings.png +0 -0
@@ -1,12 +1,9 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/ban-ts-comment -- standalone E2E test script; DSH internal types unavailable */
2
- // @ts-nocheck
3
- // internals and cordis augmented services outside the scripts tsconfig scope.
4
1
  import { createHash } from 'node:crypto'
5
2
  import { spawn } from 'node:child_process'
6
3
  import { createReadStream } from 'node:fs'
7
4
  import { copyFile, mkdir, mkdtemp, readFile, readdir, realpath, rm, stat, writeFile } from 'node:fs/promises'
8
5
  import { readFileSync } from 'node:fs'
9
- import { createServer, IncomingMessage, ServerResponse, Server } from 'node:http'
6
+ import { createServer } from 'node:http'
10
7
  import { createRequire } from 'node:module'
11
8
  import { tmpdir } from 'node:os'
12
9
  import { basename, dirname, join } from 'node:path'
@@ -17,43 +14,21 @@ const root = fileURLToPath(new URL('..', import.meta.url))
17
14
  // Release mode (default) is fail-closed: the upgrade leg and the official
18
15
  // clean-harness lifecycle must both run to green or the gate exits non-zero.
19
16
  // Set DSH_E2E_MODE=dev for an offline smoke with explicit skip markers.
20
- const e2eMode: 'dev' | 'release' = process.env.DSH_E2E_MODE === 'dev' ? 'dev' : 'release'
17
+ const e2eMode = process.env.DSH_E2E_MODE === 'dev' ? 'dev' : 'release'
21
18
  const packages = [
22
19
  { directory: join(root, 'packages/selector') },
23
20
  ]
24
- const officialHostPackages = [
25
- '@deepseek-ai/cordis@4.0.1',
26
- '@deepseek-ai/cordis-plugin-group@1.0.1',
27
- '@deepseek-ai/cordis-plugin-include@1.0.6',
28
- '@deepseek-ai/cordis-plugin-loader@1.0.2',
29
- '@deepseek-ai/dsh-agent@0.1.1-rc.2',
30
- '@deepseek-ai/dsh-agent-loop@0.1.1-rc.2',
31
- '@deepseek-ai/dsh-agent-loop-testkit@0.1.1-rc.2',
32
- '@deepseek-ai/dsh-agent-presets@0.1.1-rc.2',
33
- '@deepseek-ai/dsh-commands@0.1.1-rc.2',
34
- '@deepseek-ai/dsh-command-compact@0.1.1-rc.2',
35
- '@deepseek-ai/dsh-compaction-basic@0.1.1-rc.2',
36
- '@deepseek-ai/dsh-llm@0.1.1-rc.2',
37
- '@deepseek-ai/dsh-session@0.1.1-rc.2',
38
- '@deepseek-ai/dsh-scope@0.1.1-rc.2',
39
- '@deepseek-ai/dsh-settings@0.1.1-rc.2',
40
- '@deepseek-ai/dsh-system-prompt@0.1.1-rc.2',
41
- '@deepseek-ai/dsh-token-meter@0.1.1-rc.2',
42
- '@deepseek-ai/dsh-tools@0.1.1-rc.2',
43
- ]
44
-
45
- // On Windows npm and pnpm only exist as .cmd shims, which Node refuses to
46
- // spawn directly, so those two are routed through the shell.
47
- const spawnTool = (command: string, args: string[], options?: Record<string, unknown>) => spawn(
48
- command,
49
- args,
50
- process.platform === 'win32' && (command === 'npm' || command === 'pnpm')
51
- ? { ...options, shell: true }
52
- : options,
53
- )
21
+ // The full @deepseek-ai/* host closure (pinned in the workspace root manifest,
22
+ // currently 0.1.5-rc.2): auto-installed peers must all resolve from the mock
23
+ // registry, so the list must cover every peer the packed plugins and the
24
+ // official packages declare.
25
+ const rootManifest = JSON.parse(await readFile(join(root, 'package.json'), 'utf8'))
26
+ const officialHostPackages = Object.entries(rootManifest.devDependencies)
27
+ .filter(([name]) => name.startsWith('@deepseek-ai/'))
28
+ .map(([name, version]) => `${name}@${version}`)
54
29
 
55
- const run = (command: string, args: string[], options: Record<string, unknown> = {}): Promise<void> => new Promise((resolve, reject) => {
56
- const child = spawnTool(command, args, { stdio: 'inherit', ...options })
30
+ const run = (command, args, options = {}) => new Promise((resolve, reject) => {
31
+ const child = spawn(command, args, { stdio: 'inherit', shell: process.platform === 'win32', ...options })
57
32
  child.once('error', reject)
58
33
  child.once('exit', (code, signal) => {
59
34
  if (code === 0) resolve()
@@ -61,14 +36,14 @@ const run = (command: string, args: string[], options: Record<string, unknown> =
61
36
  })
62
37
  })
63
38
 
64
- const capture = (command: string, args: string[], options: Record<string, unknown> = {}): Promise<{ stdout: string; stderr: string }> => new Promise((resolve, reject) => {
65
- const child = spawnTool(command, args, { ...options, stdio: ['ignore', 'pipe', 'pipe'] })
39
+ const capture = (command, args, options = {}) => new Promise((resolve, reject) => {
40
+ const child = spawn(command, args, { shell: process.platform === 'win32', ...options, stdio: ['ignore', 'pipe', 'pipe'] })
66
41
  let stdout = ''
67
42
  let stderr = ''
68
- child.stdout!.setEncoding('utf8')
69
- child.stderr!.setEncoding('utf8')
70
- child.stdout!.on('data', (chunk: string) => { stdout += chunk })
71
- child.stderr!.on('data', (chunk: string) => { stderr += chunk })
43
+ child.stdout.setEncoding('utf8')
44
+ child.stderr.setEncoding('utf8')
45
+ child.stdout.on('data', chunk => { stdout += chunk })
46
+ child.stderr.on('data', chunk => { stderr += chunk })
72
47
  child.once('error', reject)
73
48
  child.once('exit', (code, signal) => {
74
49
  if (code === 0) resolve({ stdout, stderr })
@@ -80,26 +55,19 @@ const capture = (command: string, args: string[], options: Record<string, unknow
80
55
  })
81
56
  })
82
57
 
83
- interface CaptureOutcome {
84
- code: number | null
85
- signal: NodeJS.Signals | null
86
- stdout: string
87
- stderr: string
88
- }
89
-
90
- const captureOutcome = (command: string, args: string[], options: Record<string, unknown> = {}): Promise<CaptureOutcome> => new Promise((resolve, reject) => {
91
- const child = spawnTool(command, args, { ...options, stdio: ['ignore', 'pipe', 'pipe'] })
58
+ const captureOutcome = (command, args, options = {}) => new Promise((resolve, reject) => {
59
+ const child = spawn(command, args, { shell: process.platform === 'win32', ...options, stdio: ['ignore', 'pipe', 'pipe'] })
92
60
  let stdout = ''
93
61
  let stderr = ''
94
- child.stdout!.setEncoding('utf8')
95
- child.stderr!.setEncoding('utf8')
96
- child.stdout!.on('data', (chunk: string) => { stdout += chunk })
97
- child.stderr!.on('data', (chunk: string) => { stderr += chunk })
62
+ child.stdout.setEncoding('utf8')
63
+ child.stderr.setEncoding('utf8')
64
+ child.stdout.on('data', chunk => { stdout += chunk })
65
+ child.stderr.on('data', chunk => { stderr += chunk })
98
66
  child.once('error', reject)
99
67
  child.once('exit', (code, signal) => resolve({ code, signal, stdout, stderr }))
100
68
  })
101
69
 
102
- const allocateLoopbackPort = (): Promise<number> => new Promise((resolve, reject) => {
70
+ const allocateLoopbackPort = () => new Promise((resolve, reject) => {
103
71
  const server = createServer()
104
72
  server.once('error', reject)
105
73
  server.listen(0, '127.0.0.1', () => {
@@ -112,19 +80,14 @@ const allocateLoopbackPort = (): Promise<number> => new Promise((resolve, reject
112
80
  })
113
81
  })
114
82
 
115
- const assert = (condition: unknown, message: string): asserts condition => {
83
+ const assert = (condition, message) => {
116
84
  if (!condition) throw new Error(`packed Host smoke: ${message}`)
117
85
  }
118
86
 
119
- interface Violation {
120
- label: string
121
- pattern: RegExp
122
- }
123
-
124
- async function scanPublishedTree(packageRoot: string) {
87
+ async function scanPublishedTree(packageRoot) {
125
88
  const pending = [packageRoot]
126
- const violations: string[] = []
127
- const forbidden: Violation[] = [
89
+ const violations = []
90
+ const forbidden = [
128
91
  { label: 'developer absolute path', pattern: /(?:\/home\/|[A-Za-z]:\\Users\\)/u },
129
92
  { label: 'OpenAI-style secret', pattern: /\bsk-[A-Za-z0-9_-]{20,}\b/u },
130
93
  { label: 'NPM token', pattern: /\bnpm_[A-Za-z0-9]{20,}\b/u },
@@ -132,7 +95,7 @@ async function scanPublishedTree(packageRoot: string) {
132
95
  { label: 'assigned DeepSeek API key', pattern: /DEEPSEEK_API_KEY\s*=\s*[^\s"']+/u },
133
96
  ]
134
97
  while (pending.length > 0) {
135
- const directory = pending.pop()!
98
+ const directory = pending.pop()
136
99
  for (const entry of await readdir(directory, { withFileTypes: true })) {
137
100
  const path = join(directory, entry.name)
138
101
  if (entry.isDirectory()) {
@@ -150,9 +113,9 @@ async function scanPublishedTree(packageRoot: string) {
150
113
  if (violations.length > 0) throw new Error(`packed content scan failed:\n${violations.join('\n')}`)
151
114
  }
152
115
 
153
- async function runPackedHostSmoke(consumerRoot: string) {
116
+ async function runPackedHostSmoke(consumerRoot) {
154
117
  const consumerRequire = createRequire(join(consumerRoot, 'package.json'))
155
- const load = async (specifier: string) => import(pathToFileURL(consumerRequire.resolve(specifier)).href)
118
+ const load = async specifier => import(pathToFileURL(consumerRequire.resolve(specifier)).href)
156
119
  const [
157
120
  cordis,
158
121
  groupModule,
@@ -167,6 +130,7 @@ async function runPackedHostSmoke(consumerRoot: string) {
167
130
  scopeModule,
168
131
  settingsModule,
169
132
  systemPromptModule,
133
+ sessionProjectionModule,
170
134
  tokenMeterModule,
171
135
  toolsModule,
172
136
  selectorModule,
@@ -184,10 +148,11 @@ async function runPackedHostSmoke(consumerRoot: string) {
184
148
  load('@deepseek-ai/dsh-scope'),
185
149
  load('@deepseek-ai/dsh-settings'),
186
150
  load('@deepseek-ai/dsh-system-prompt'),
151
+ load('@deepseek-ai/dsh-session-projection'),
187
152
  load('@deepseek-ai/dsh-token-meter'),
188
153
  load('@deepseek-ai/dsh-tools'),
189
154
  load('dsh-context-compression-improved'),
190
- ]) as any[]
155
+ ])
191
156
 
192
157
  class MemorySettings extends settingsModule.SettingsProvider {
193
158
  writable = true
@@ -215,46 +180,48 @@ async function runPackedHostSmoke(consumerRoot: string) {
215
180
  const runtime = new cordis.Context()
216
181
  try {
217
182
  runtime.baseUrl = `${pathToFileURL(presetRoot).href}/`
218
- await runtime.plugin(loaderModule.default)
183
+ await runtime.plugin(loaderModule.default).await()
219
184
  runtime.loader.builtins.include = includeModule.default
220
185
  runtime.loader.builtins.group = groupModule.default
221
- await runtime.plugin(llmModule.default)
222
- await runtime.plugin(sessionModule.default)
223
- await runtime.plugin(systemPromptModule.default, { persona: '' })
224
- await runtime.plugin(toolsModule.default)
225
- await runtime.plugin(agentModule.default)
226
- await runtime.plugin(agentLoopModule.default, { agents: [] })
227
- await runtime.plugin(commandsModule.default)
228
- await runtime.plugin(tokenMeterModule.default)
229
- await runtime.plugin(MemorySettings)
186
+ await runtime.plugin(llmModule.default).await()
187
+ await runtime.plugin(sessionModule.default).await()
188
+ await runtime.plugin(systemPromptModule.default, { personaPrefix: '' }).await()
189
+ await runtime.plugin(toolsModule.default).await()
190
+ await runtime.plugin(agentModule.default).await()
191
+ await runtime.plugin(agentLoopModule.default, { agents: [] }).await()
192
+ await runtime.plugin(commandsModule.default).await()
193
+ await runtime.plugin(sessionProjectionModule.default).await()
194
+ await runtime.plugin(tokenMeterModule.default).await()
195
+ await runtime.plugin(MemorySettings).await()
230
196
  await runtime.plugin(presetsModule.default, {
231
197
  default: 'standard',
232
198
  roots: [{ path: presetRoot, trust: 'system' }],
199
+ includeShippedRoot: false,
233
200
  includeUserRoot: false,
234
- })
201
+ }).await()
235
202
  await runtime.plugin({
236
- apply: (selectorCtx: any) => selectorModule.apply(selectorCtx, { presetOverlay: true }),
203
+ apply: selectorCtx => selectorModule.apply(selectorCtx, { presetOverlay: true }),
237
204
  }).await()
238
205
 
239
- const createAgent = async (sessionId: string, preset: string) => {
206
+ const createAgent = async (sessionId, preset) => {
240
207
  const handle = await runtime.agents.create({
241
208
  sessionId: sessionModule.SessionId(sessionId),
242
- setup: async (agentCtx: any) => void await runtime.agentPresets.mount(agentCtx, preset),
209
+ setup: async agentCtx => void await runtime.agentPresets.mount(agentCtx, preset),
243
210
  })
244
211
  return handle.agent
245
212
  }
246
- const hasRetrieve = (agent: any) => runtime.tools.get(
213
+ const hasRetrieve = agent => runtime.tools.get(
247
214
  'context_compression_retrieve',
248
215
  scopeModule.scopeOf(agent.ctx),
249
216
  ) !== undefined
250
- const hasCompact = (agent: any) => runtime.commands.list(agent)
251
- .some((command: any) => command.name === 'compact')
252
- const hasCompleteStack = (agent: any) =>
217
+ const hasCompact = agent => runtime.commands.list(agent)
218
+ .some(command => command.name === 'compact')
219
+ const hasCompleteStack = agent =>
253
220
  runtime.agentPresets.serviceFor(agent, 'toolResultPruner') !== undefined
254
221
  && runtime.agentPresets.serviceFor(agent, 'compaction') !== undefined
255
222
  && hasRetrieve(agent)
256
223
  && hasCompact(agent)
257
- const hasNoStack = (agent: any) =>
224
+ const hasNoStack = agent =>
258
225
  runtime.agentPresets.serviceFor(agent, 'toolResultPruner') === undefined
259
226
  && runtime.agentPresets.serviceFor(agent, 'compaction') === undefined
260
227
  && !hasRetrieve(agent)
@@ -278,7 +245,7 @@ async function runPackedHostSmoke(consumerRoot: string) {
278
245
  const parent = await createAgent('packed-host-parent', 'standard')
279
246
  const childHandle = await runtime.agents.create({
280
247
  sessionId: sessionModule.SessionId('packed-host-child'),
281
- setup: (childCtx: any) => void runtime.agentPresets.composeFrom(childCtx, parent.ctx),
248
+ setup: childCtx => void runtime.agentPresets.composeFrom(childCtx, parent.ctx),
282
249
  })
283
250
  const child = childHandle.agent
284
251
  const original = Symbol.for('cordis.original')
@@ -290,14 +257,14 @@ async function runPackedHostSmoke(consumerRoot: string) {
290
257
  'parent or child pruner is missing')
291
258
  assert(parentCompaction !== undefined && childCompaction !== undefined,
292
259
  'parent or child compaction engine is missing')
293
- assert(Object.is((childPruner as any)[original], (parentPruner as any)[original]),
260
+ assert(Object.is(childPruner[original], parentPruner[original]),
294
261
  'child did not inherit the parent pruner instance')
295
- assert(Object.is((childCompaction as any)[original], (parentCompaction as any)[original]),
262
+ assert(Object.is(childCompaction[original], parentCompaction[original]),
296
263
  'child did not inherit the parent compaction instance')
297
264
  assert(hasRetrieve(child) && hasCompact(child),
298
265
  'child lacks the inherited retrieve tool or compact command')
299
266
 
300
- const namespace = settingsModule.settingsNamespace('context-compression')
267
+ const namespace = 'context-compression'
301
268
  const settings = runtime.settings.get(namespace)
302
269
  assert(settings.custom.history.trigger === 500_000,
303
270
  'packed Host did not expose the 500000 History default')
@@ -318,24 +285,19 @@ async function runPackedHostSmoke(consumerRoot: string) {
318
285
  }
319
286
  }
320
287
 
321
- async function runOfficialCloneCliSmoke(
322
- referenceRoot: string,
323
- registry: string,
324
- upgradeFrom: string | undefined,
325
- candidateVersion: string,
326
- ) {
288
+ async function runOfficialCloneCliSmoke(referenceRoot, registry, upgradeFrom, candidateVersion) {
327
289
  const clone = await realpath(referenceRoot)
328
- const git = async (...args: string[]) => (await capture('git', args, { cwd: clone })).stdout.trim()
290
+ const git = async (...args) => (await capture('git', args, { cwd: clone })).stdout.trim()
329
291
  const before = {
330
292
  tag: await git('describe', '--tags', '--exact-match'),
331
293
  commit: await git('rev-parse', 'HEAD'),
332
294
  tree: await git('rev-parse', 'HEAD^{tree}'),
333
295
  status: await git('status', '--porcelain'),
334
296
  }
335
- assert(before.tag === 'dsh-v0.1.1-rc.2', `official clone tag is ${before.tag}`)
336
- assert(before.commit === 'b150a551b8d465e31e418e1b2eaf5e79bbb7d28e',
297
+ assert(before.tag === 'dsh-v0.1.5-rc.2', `official clone tag is ${before.tag}`)
298
+ assert(before.commit === 'fb2c4b9e698e30edb738bca4cf0618587db7d203',
337
299
  `official clone commit is ${before.commit}`)
338
- assert(before.tree === '53915efe4e2126cc7779b73dfc8a3bcec5318c44',
300
+ assert(before.tree === 'bd7dd6d90010a35d3d6ff9f12c1f6207d5b6fe38',
339
301
  `official clone tree is ${before.tree}`)
340
302
  assert(before.status === '', 'official clone is dirty before CLI smoke')
341
303
 
@@ -344,12 +306,13 @@ async function runOfficialCloneCliSmoke(
344
306
  const dshHome = join(temporaryRoot, 'dsh-home')
345
307
  let added = false
346
308
  const environment = { ...process.env, DSH_HOME: dshHome }
347
- const dsh = (...args: string[]) => run('pnpm', ['dsh', ...args], { cwd: worktree, env: environment })
309
+ const dsh = (...args) => run('pnpm', ['dsh', ...args], { cwd: worktree, env: environment })
348
310
  const dumpConfig = () => capture('pnpm', ['dsh', '--profile', 'web', '--dump-config'], {
349
311
  cwd: worktree,
350
312
  env: environment,
351
313
  }).then(captured => captured.stdout)
352
314
 
315
+ /** Installed manifest of the profile-resolved plugin package. */
353
316
  const profilePackages = () => {
354
317
  const profileRoot = join(dshHome, 'profiles/web')
355
318
  const profileRequire = createRequire(join(profileRoot, 'package.json'))
@@ -357,25 +320,45 @@ async function runOfficialCloneCliSmoke(
357
320
  return {
358
321
  profileRoot,
359
322
  selectorPath,
360
- selector: JSON.parse(readFileSync(selectorPath, 'utf8')) as Record<string, any>,
323
+ selector: JSON.parse(readFileSync(selectorPath, 'utf8')),
361
324
  }
362
325
  }
363
326
 
327
+ /**
328
+ * Peers a headless official profile can never provide: pure web-host UI
329
+ * packages supplied by the web app, not the CLI installation. The list is
330
+ * REVIEWED and exact — any OTHER unresolved selector peer fails the gate,
331
+ * and every web/client peer is still import-verified from the built
332
+ * client libraries below.
333
+ */
364
334
  const WEB_ONLY_HEADLESS_UNRESOLVED_PEERS = [
365
335
  '@deepseek-ai/dsh-client-ui-primitives',
366
336
  '@deepseek-ai/dsh-client-ui-slots',
367
337
  ]
368
338
 
339
+ /**
340
+ * Verify every web/client peer exists as a BUILT artifact resolvable from
341
+ * the packages that depend on it. Executable loading of the client stack
342
+ * happens under the web bundler, not bare Node (the UI packages ship CSS
343
+ * modules only a bundler can import): that load leg is the `build:web`
344
+ * step of the worktree's `pnpm run build` above, which fails closed when
345
+ * the client graph is broken.
346
+ */
369
347
  const proveBuiltClientPeersLoad = async () => {
370
348
  const clientPeers = [
371
349
  '@deepseek-ai/dsh-client-locale',
372
- '@deepseek-ai/dsh-client-runtime',
350
+ '@deepseek-ai/dsh-client-store',
373
351
  '@deepseek-ai/dsh-client-ui-primitives',
374
352
  '@deepseek-ai/dsh-client-ui-settings',
375
353
  '@deepseek-ai/dsh-client-ui-slots',
376
354
  '@deepseek-ai/dsh-client-ui-workspace',
377
355
  'react',
378
356
  ]
357
+ // pnpm's isolated layout keeps each package's dependents in ITS own
358
+ // node_modules, so anchor resolution at the packages that actually
359
+ // depend on the client stack: the web-app bundle (locale, store,
360
+ // ui-settings, ui-workspace), the client-locale package (react,
361
+ // ui-primitives, ui-slots), and the web app.
379
362
  const anchors = JSON.stringify([
380
363
  join(worktree, 'packages/bundle/web-app/package.json'),
381
364
  join(worktree, 'packages/client/locale/package.json'),
@@ -398,6 +381,15 @@ async function runOfficialCloneCliSmoke(
398
381
  return clientPeers.length
399
382
  }
400
383
 
384
+ /**
385
+ * Prove the plugin actually loads in the official profile: pnpm's peers
386
+ * check cannot see the healed profiles/node_modules fallback by design, so
387
+ * the release gate resolves and imports instead. Fail-closed parts: every
388
+ * RUNTIME peer (the engine surface the headless host must provide) and the
389
+ * selector's node entry with a callable apply(). The selector's remaining
390
+ * unresolved peers must equal the REVIEWED web-only whitelist above —
391
+ * anything else (a newly missing host dependency) fails immediately.
392
+ */
401
393
  const provePluginLoads = async () => {
402
394
  const { profileRoot, selector } = profilePackages()
403
395
  const selectorPeers = Object.keys(selector.peerDependencies ?? {})
@@ -431,7 +423,7 @@ async function runOfficialCloneCliSmoke(
431
423
  throw new Error(`official profile failed to load the plugin and its engine peers:\n${outcome.stdout}\n${outcome.stderr}`)
432
424
  }
433
425
  const unresolved = JSON.parse(marker.slice('LOAD_OK '.length))
434
- const unexpected = unresolved.filter((peer: string) => !WEB_ONLY_HEADLESS_UNRESOLVED_PEERS.includes(peer))
426
+ const unexpected = unresolved.filter(peer => !WEB_ONLY_HEADLESS_UNRESOLVED_PEERS.includes(peer))
435
427
  if (unexpected.length > 0) {
436
428
  throw new Error(`selector peers failed to resolve headless outside the reviewed web-only whitelist: ${unexpected.join(', ')}`)
437
429
  }
@@ -443,7 +435,18 @@ async function runOfficialCloneCliSmoke(
443
435
  }
444
436
  }
445
437
 
446
- const runProfileBootProbe = async (phase: string, expectSeeded: boolean) => {
438
+ /**
439
+ * Boot the official profile FOR REAL through the CLI's own profile-boot
440
+ * path — not --dump-config, which composes YAML without booting or
441
+ * executing plugins. The probe mounts the full bundle tree (selector
442
+ * included), then proves: the settings service resolves the registered
443
+ * document (before the upgrade: the previous release's schema defaults;
444
+ * after: the seeded savings/73 document parsed with the INSTALLED runtime),
445
+ * the AgentPresets service composed the selector's standing overlay, and
446
+ * the overlay's generated composition exists with the deterministic
447
+ * identity filename. Any failure exits non-zero.
448
+ */
449
+ const runProfileBootProbe = async (phase, expectSeeded) => {
447
450
  const profilePort = await allocateLoopbackPort()
448
451
  const { profileRoot } = profilePackages()
449
452
  const settingsProof = expectSeeded
@@ -457,6 +460,9 @@ async function runOfficialCloneCliSmoke(
457
460
  ' }',
458
461
  ]
459
462
  : [
463
+ // The previous release predates the autoCompact section and the
464
+ // public parser; prove its OWN schema resolved the registered
465
+ // namespace into a complete supported document instead.
460
466
  " if (raw?.profile !== 'balanced' || raw?.custom?.version !== 3) {",
461
467
  " throw new Error('boot probe: previous-release settings defaults did not resolve: ' + JSON.stringify(raw))",
462
468
  ' }',
@@ -470,6 +476,10 @@ async function runOfficialCloneCliSmoke(
470
476
  `const worktree = String.raw\`${worktree}\``,
471
477
  `const profileRoot = String.raw\`${join(profileRoot, 'package.json')}\``,
472
478
  'const bootModule = await import(pathToFileURL(join(worktree, \'apps/cli/src/profile-boot.ts\')).href)',
479
+ // Import the workspace packages from their source trees (pinned, like
480
+ // the profile-boot path above): the probe runs under tsx, and their
481
+ // lib/ artifacts are only produced by the full release build, not the
482
+ // library faces.
473
483
  "const appBoot = await import(pathToFileURL(join(worktree, 'packages/boot/app-boot/src/index.ts')).href)",
474
484
  "const settingsModule = await import(pathToFileURL(join(worktree, 'packages/settings/settings/src/index.ts')).href)",
475
485
  'const preBootStores = new Set(await readdir(tmpdir()))',
@@ -482,7 +492,7 @@ async function runOfficialCloneCliSmoke(
482
492
  'try {',
483
493
  " const settings = ctx.get('settings')",
484
494
  " if (settings === undefined) throw new Error('boot probe: settings service missing')",
485
- " const raw = settings.get(settingsModule.settingsNamespace('context-compression'))",
495
+ " const raw = settings.get('context-compression')",
486
496
  ...settingsProof,
487
497
  " const presets = ctx.get('agentPresets')",
488
498
  " if (presets === undefined) throw new Error('boot probe: agentPresets service missing')",
@@ -490,6 +500,8 @@ async function runOfficialCloneCliSmoke(
490
500
  ' if (key?.agentPreset !== \'standard\') {',
491
501
  " throw new Error('boot probe: standing key did not compose the default preset: ' + JSON.stringify(key))",
492
502
  ' }',
503
+ // Only stores CREATED BY THIS BOOT count: stale leftovers from earlier
504
+ // runs or concurrent harnesses must never satisfy the overlay proof.
493
505
  ' const generated = []',
494
506
  " for (const entry of await readdir(tmpdir(), { withFileTypes: true })) {",
495
507
  ' if (!entry.isDirectory() || preBootStores.has(entry.name)) continue',
@@ -498,7 +510,7 @@ async function runOfficialCloneCliSmoke(
498
510
  ' try {',
499
511
  ' children = await readdir(join(tmpdir(), entry.name))',
500
512
  ' } catch {',
501
- ' continue',
513
+ ' continue // a concurrent process disposed its store mid-scan',
502
514
  ' }',
503
515
  " for (const child of children) {",
504
516
  " if (/^standard-[0-9a-f]{24}\\.agent\\.cordis\\.yml$/u.test(child)) generated.push(child)",
@@ -526,6 +538,7 @@ async function runOfficialCloneCliSmoke(
526
538
  return JSON.parse(marker.slice('BOOT_PROBE_OK '.length))
527
539
  }
528
540
 
541
+ /** Seed real user settings through the plugin's own public surface. */
529
542
  const seedSettings = async () => {
530
543
  const { profileRoot } = profilePackages()
531
544
  const settingsPath = join(dshHome, 'settings.yaml')
@@ -558,7 +571,8 @@ async function runOfficialCloneCliSmoke(
558
571
  return settingsPath
559
572
  }
560
573
 
561
- const proveSettingsPreserved = async (settingsPath: string) => {
574
+ /** Read the seeded settings back through the upgraded plugin's parser. */
575
+ const proveSettingsPreserved = async (settingsPath) => {
562
576
  const { profileRoot } = profilePackages()
563
577
  const script = [
564
578
  "const { readFileSync } = require('node:fs')",
@@ -587,8 +601,15 @@ async function runOfficialCloneCliSmoke(
587
601
  await run('git', ['worktree', 'add', '--detach', worktree, before.commit], { cwd: clone })
588
602
  added = true
589
603
  await run('pnpm', ['install', '--frozen-lockfile', '--ignore-scripts'], { cwd: worktree })
604
+ // A source checkout ships no built artifacts (install above skips
605
+ // prepare scripts). The boot probes run the REAL web profile —
606
+ // dsh-base + dsh-web-app, the only bundle that mounts agent-presets and
607
+ // therefore the selector's preset overlay — so build both library faces
608
+ // AND the web frontend; the healed profiles/node_modules fallback also
609
+ // symlinks the CLI's own workspace packages.
590
610
  await run('pnpm', ['run', 'build'], { cwd: worktree })
591
611
 
612
+ // Real lifecycle: start on the published previous release.
592
613
  if (upgradeFrom === undefined) throw new Error('release gate requires the previous published release for the official lifecycle')
593
614
  await dsh('plugin', '--profile', 'web', 'add',
594
615
  `dsh-context-compression-improved@${upgradeFrom}`, '--registry', registry)
@@ -597,14 +618,24 @@ async function runOfficialCloneCliSmoke(
597
618
  throw new Error(`official lifecycle started on ${String(beforeUp.selector.version)}, expected ${upgradeFrom}`)
598
619
  }
599
620
 
621
+ // Boot the profile once on the previous release. This asserts the added
622
+ // bundle layer is live before any update and heals
623
+ // $DSH_HOME/profiles/node_modules — the shared-module fallback the
624
+ // plugin's harness peers resolve through in every later raw-node proof.
600
625
  const addedDump = await dumpConfig()
601
626
  assert(addedDump.includes('context-compression-selector-bundle'),
602
627
  'official post-add dump lacks the selector Bundle layer')
603
628
 
629
+ // Real profile start on the previous release, BEFORE seeding: the
630
+ // previous-release schema predates the autoCompact section, so this probe
631
+ // proves its own defaults resolve; the seeded document is asserted by the
632
+ // post-up probe through the upgraded runtime.
604
633
  const postAddBoot = await runProfileBootProbe('post-add', false)
605
634
 
606
635
  const settingsPath = await seedSettings()
607
636
 
637
+ // Standard update command moves the one install-facing package; assert the
638
+ // version it lands before anything else runs.
608
639
  await dsh('plugin', '--profile', 'web', 'up',
609
640
  'dsh-context-compression-improved@latest', '--registry', registry)
610
641
  const afterUp = profilePackages()
@@ -621,6 +652,8 @@ async function runOfficialCloneCliSmoke(
621
652
  assert(upDump.match(/context-compression-selector-bundle/gu)?.length === 1,
622
653
  'official post-up dump contains more than one selector Bundle layer')
623
654
 
655
+ // pnpm's peers check is informational: plugin peers resolve through the
656
+ // healed profiles/node_modules fallback, which pnpm cannot see by design.
624
657
  const peers = await captureOutcome('pnpm', ['peers', 'check'], {
625
658
  cwd: join(dshHome, 'profiles/web'),
626
659
  env: environment,
@@ -642,7 +675,7 @@ async function runOfficialCloneCliSmoke(
642
675
  commit: before.commit,
643
676
  tree: before.tree,
644
677
  status: 'clean',
645
- install: 'single-package',
678
+ install: 'entry-package-only',
646
679
  upgrade: {
647
680
  from: upgradeFrom,
648
681
  to: candidateVersion,
@@ -674,24 +707,13 @@ const comparisonRoot = fixedArtifactRoot === undefined
674
707
  ? undefined
675
708
  : await mkdtemp(join(tmpdir(), 'dsh-selector-rebuild-'))
676
709
  const consumerRoot = await mkdtemp(join(tmpdir(), 'dsh-selector-consumer-'))
677
- let server: Server | undefined
710
+ let server
678
711
 
679
712
  try {
680
- const registryPackages = new Map<string, {
681
- filename: string
682
- manifest: Record<string, any>
683
- tarball: string
684
- sha1: string
685
- sha256?: string
686
- integrity: string
687
- }>()
688
- const previousVersions = new Map<string, {
689
- filename: string
690
- manifest: Record<string, any>
691
- tarball: string
692
- sha1: string
693
- integrity: string
694
- }>()
713
+ const registryPackages = new Map()
714
+ // Published previous-release metadata served alongside the packed candidate
715
+ // so the upgrade leg can install the real shipped release first.
716
+ const previousVersions = new Map()
695
717
  // The predecessor is whatever the registry actually offers. This used to be
696
718
  // the pinned literal '0.1.0-beta.2', which only ever existed under this
697
719
  // package's pre-rename name, so it could never resolve under the current one.
@@ -710,13 +732,8 @@ try {
710
732
  break
711
733
  }
712
734
  if (!packumentResponse.ok) throw new Error(`packument responded ${packumentResponse.status}`)
713
- const packument = await packumentResponse.json() as {
714
- versions?: Record<string, unknown>
715
- time?: Record<string, string>
716
- }
717
- const localVersion = JSON.parse(
718
- await readFile(join(packages[0].directory, 'package.json'), 'utf8'),
719
- ).version as string
735
+ const packument = await packumentResponse.json()
736
+ const localVersion = JSON.parse(await readFile(join(packages[0].directory, 'package.json'), 'utf8')).version
720
737
  const times = packument.time ?? {}
721
738
  // Publication order, not semver order: the version a user would be
722
739
  // upgrading from is the most recently published one that is not the
@@ -732,7 +749,7 @@ try {
732
749
  previousRelease = earlier[0]
733
750
  const response = await fetch(`https://registry.npmjs.org/${name}/${previousRelease}`)
734
751
  if (!response.ok) throw new Error(`packument responded ${response.status}`)
735
- const manifest = await response.json() as Record<string, any>
752
+ const manifest = await response.json()
736
753
  const tarballResponse = await fetch(manifest.dist.tarball)
737
754
  if (!tarballResponse.ok) throw new Error(`tarball responded ${tarballResponse.status}`)
738
755
  const bytes = Buffer.from(await tarballResponse.arrayBuffer())
@@ -760,7 +777,7 @@ try {
760
777
  predecessorFound = true
761
778
  }
762
779
  for (const descriptor of packages) {
763
- const manifest = JSON.parse(await readFile(join(descriptor.directory, 'package.json'), 'utf8')) as Record<string, any>
780
+ const manifest = JSON.parse(await readFile(join(descriptor.directory, 'package.json'), 'utf8'))
764
781
  if (fixedArtifactRoot === undefined) {
765
782
  await run('npm', ['pack', '--pack-destination', artifactRoot, descriptor.directory], { cwd: root })
766
783
  }
@@ -787,13 +804,13 @@ try {
787
804
  })
788
805
  }
789
806
 
790
- server = createServer(async (request: IncomingMessage, response: ServerResponse) => {
807
+ server = createServer(async (request, response) => {
791
808
  try {
792
809
  const requestUrl = new URL(request.url ?? '/', 'http://127.0.0.1')
793
810
  const decodedPath = decodeURIComponent(requestUrl.pathname)
794
811
  for (const [name, descriptor] of registryPackages) {
795
812
  if (decodedPath === `/${name}`) {
796
- const address = server!.address()
813
+ const address = server.address()
797
814
  if (address === null || typeof address === 'string') throw new Error('registry has no TCP address')
798
815
  const tarballUrl = `http://127.0.0.1:${address.port}/${name}/-/${descriptor.filename}`
799
816
  const version = {
@@ -850,22 +867,22 @@ try {
850
867
  method: request.method,
851
868
  headers: { accept: request.headers.accept ?? '*/*' },
852
869
  })
853
- const headers: Record<string, string> = {}
870
+ const headers = {}
854
871
  for (const name of ['content-type', 'content-length', 'cache-control', 'etag', 'last-modified']) {
855
872
  const value = upstream.headers.get(name)
856
873
  if (value !== null) headers[name] = value
857
874
  }
858
875
  response.writeHead(upstream.status, headers)
859
876
  if (request.method === 'HEAD' || upstream.body === null) response.end()
860
- else Readable.fromWeb(upstream.body as any).pipe(response)
877
+ else Readable.fromWeb(upstream.body).pipe(response)
861
878
  } catch (error) {
862
879
  response.writeHead(502, { 'content-type': 'text/plain' })
863
880
  response.end(error instanceof Error ? error.message : String(error))
864
881
  }
865
882
  })
866
- await new Promise<void>((resolve, reject) => {
867
- server!.once('error', reject)
868
- server!.listen(0, '127.0.0.1', resolve)
883
+ await new Promise((resolve, reject) => {
884
+ server.once('error', reject)
885
+ server.listen(0, '127.0.0.1', resolve)
869
886
  })
870
887
  const address = server.address()
871
888
  if (address === null || typeof address === 'string') throw new Error('registry has no TCP address')
@@ -876,8 +893,13 @@ try {
876
893
  version: '0.0.0',
877
894
  private: true,
878
895
  }, null, 2))
879
- await writeFile(join(consumerRoot, 'pnpm-workspace.yaml'), 'packages: []\n')
896
+ // Stop pnpm's workspace walk-up: an ancestor with its own pnpm-workspace.yaml
897
+ // (e.g. a user home project) would otherwise absorb this consumer and land
898
+ // the install — and every resolution — outside the packed consumer.
899
+ await writeFile(join(consumerRoot, 'pnpm-workspace.yaml'), ['packages:', ' - .'].join(String.fromCharCode(10)))
880
900
  if (upgradeLeg === 'installed') {
901
+ // Real upgrade path: install the published previous release, then move to
902
+ // the packed candidate through the standard update command.
881
903
  await run('pnpm', [
882
904
  'add',
883
905
  `dsh-context-compression-improved@${previousRelease}`,
@@ -894,6 +916,7 @@ try {
894
916
  'dsh-context-compression-improved@latest',
895
917
  '--registry', registry,
896
918
  ], { cwd: consumerRoot })
919
+ // The up command must land the packed candidate version.
897
920
  const upgradedSelectorDir = await realpath(join(consumerRoot, 'node_modules/dsh-context-compression-improved'))
898
921
  const upgradedSelector = JSON.parse(await readFile(join(upgradedSelectorDir, 'package.json'), 'utf8'))
899
922
  const candidateVersion = registryPackages.get('dsh-context-compression-improved')?.manifest.version
@@ -917,22 +940,24 @@ try {
917
940
  throw new Error('packed package is not guarded by publishConfig.tag=latest')
918
941
  }
919
942
  for (const peer of ['@deepseek-ai/dsh-command-compact', '@deepseek-ai/dsh-compaction-basic']) {
920
- if (selector.peerDependencies?.[peer] !== '>=0.1.1-rc.2 <0.2.0') {
943
+ if (selector.peerDependencies?.[peer] !== '>=0.1.5-rc.2 <0.2.0-0') {
921
944
  throw new Error(`packed selector has an invalid ${peer} peer range`)
922
945
  }
923
946
  }
924
- const notice = await readFile(join(selectorDir, 'THIRD_PARTY_NOTICES.md'), 'utf8')
925
- if (!notice.includes('Copyright (c) 2026 DeepSeek')) {
926
- throw new Error(`${basename(selectorDir)} lacks the full DeepSeek Harness MIT notice`)
947
+ for (const directory of [selectorDir]) {
948
+ const notice = await readFile(join(directory, 'THIRD_PARTY_NOTICES.md'), 'utf8')
949
+ if (!notice.includes('Copyright (c) 2026 DeepSeek')) {
950
+ throw new Error(`${basename(directory)} lacks the full DeepSeek Harness MIT notice`)
951
+ }
952
+ await scanPublishedTree(directory)
927
953
  }
928
- await scanPublishedTree(selectorDir)
929
954
 
930
- const productionLicenses: Record<string, string> = Object.fromEntries(await Promise.all([
955
+ const productionLicenses = Object.fromEntries(await Promise.all([
931
956
  ['dsh-context-compression-improved', selectorDir, 'MIT'],
932
957
  ['@huggingface/tokenizers', join(dirname(selectorDir), '@huggingface/tokenizers'), 'Apache-2.0'],
933
958
  ['js-yaml', join(dirname(selectorDir), 'js-yaml'), 'MIT'],
934
959
  ].map(async ([name, directory, expected]) => {
935
- const resolved = await realpath(directory as string)
960
+ const resolved = await realpath(directory)
936
961
  const manifest = JSON.parse(await readFile(join(resolved, 'package.json'), 'utf8'))
937
962
  if (manifest.name !== name) throw new Error(`expected ${name}, found ${String(manifest.name)}`)
938
963
  if (manifest.license !== expected) {
@@ -948,7 +973,7 @@ try {
948
973
  }
949
974
  productionLicenses.argparse = argparse.license
950
975
 
951
- const packedTokenizerArtifacts: Record<string, { bytes: number; sha256: string }> = {}
976
+ const packedTokenizerArtifacts = {}
952
977
  for (const artifactDir of ['deepseek-v4', 'deepseek-v4-vision-exp']) {
953
978
  const manifest = JSON.parse(await readFile(join(selectorDir, 'assets', artifactDir, 'manifest.json'), 'utf8'))
954
979
  const tokenizerBytes = await readFile(join(selectorDir, 'assets', artifactDir, 'tokenizer.json'))
@@ -964,9 +989,8 @@ try {
964
989
  if (!client.startsWith('window.__ModuleLoader__.load({')) throw new Error('packed client is not lazy-CJS')
965
990
  if (/(?:\/home\/|[A-Za-z]:\\Users\\)/u.test(client)) throw new Error('packed client leaks a developer path')
966
991
  const hostSmoke = await runPackedHostSmoke(consumerRoot)
967
- // KEY CHANGE: copy compiled .js from scripts-dist/ instead of .mjs from scripts/
968
- const installedComponentsScript = join(consumerRoot, 'packed-components-smoke.js')
969
- await copyFile(join(root, 'scripts-dist/packed-components-smoke.js'), installedComponentsScript)
992
+ const installedComponentsScript = join(consumerRoot, 'packed-components-smoke.mjs')
993
+ await copyFile(join(root, 'scripts/packed-components-smoke.mjs'), installedComponentsScript)
970
994
  const installedComponentsOutput = await capture(process.execPath, [installedComponentsScript], {
971
995
  cwd: consumerRoot,
972
996
  })
@@ -1002,7 +1026,7 @@ try {
1002
1026
  && packedVisionSmoke.imageSession.exactRewriteIneligible === true
1003
1027
  && packedVisionSmoke.imageSession.originalIntact === true,
1004
1028
  'installed vision smoke did not prove estimate propagation and exact-only safety')
1005
- let officialCloneSmoke: any = null
1029
+ let officialCloneSmoke = null
1006
1030
  const candidateVersion = registryPackages.get('dsh-context-compression-improved')?.manifest.version
1007
1031
  if (candidateVersion === undefined) throw new Error('packed candidate version is unknown')
1008
1032
  const previousForLifecycle = predecessorFound ? previousRelease : undefined
@@ -1019,10 +1043,13 @@ try {
1019
1043
  candidateVersion,
1020
1044
  )
1021
1045
  } else {
1046
+ // Auto-provision a clean official checkout so the standard add → up →
1047
+ // remove lifecycle runs without manual setup. Release mode fails closed;
1048
+ // only dev mode may skip with an explicit marker.
1022
1049
  const cloneRoot = join(artifactRoot, 'official-clone')
1023
1050
  try {
1024
1051
  await run('git', [
1025
- 'clone', '--depth', '1', '--branch', 'dsh-v0.1.1-rc.2',
1052
+ 'clone', '--depth', '1', '--branch', 'dsh-v0.1.5-rc.2',
1026
1053
  'https://github.com/deepseek-ai/deepseek-harness.git', cloneRoot,
1027
1054
  ])
1028
1055
  officialCloneSmoke = await runOfficialCloneCliSmoke(
@@ -1050,7 +1077,8 @@ try {
1050
1077
  upgradeLeg,
1051
1078
  artifactSource: fixedArtifactRoot === undefined ? 'fresh-pack' : artifactRoot,
1052
1079
  workspaceRebuildMatched: fixedArtifactRoot === undefined ? null : true,
1053
- plugin: selector.version,
1080
+ selector: selector.version,
1081
+ prunerEntry: 'dsh-context-compression-improved/pruner',
1054
1082
  productionLicenses,
1055
1083
  tokenizerArtifacts: packedTokenizerArtifacts,
1056
1084
  tokenizerBytes: tokenizer.length,
@@ -1065,7 +1093,7 @@ try {
1065
1093
  }])),
1066
1094
  }, null, 2))
1067
1095
  } finally {
1068
- if (server !== undefined) await new Promise<void>(resolve => server!.close(() => resolve()))
1096
+ if (server !== undefined) await new Promise(resolve => server.close(resolve))
1069
1097
  if (comparisonRoot !== undefined) await rm(comparisonRoot, { recursive: true, force: true })
1070
1098
  if (ownsArtifactRoot) await rm(artifactRoot, { recursive: true, force: true })
1071
1099
  await rm(consumerRoot, { recursive: true, force: true })