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,4 +1,3 @@
1
- import { execFileSync } from 'node:child_process'
2
1
  import { createHash } from 'node:crypto'
3
2
  import { readdir, readFile, stat } from 'node:fs/promises'
4
3
  import { join, relative } from 'node:path'
@@ -6,42 +5,62 @@ import { fileURLToPath } from 'node:url'
6
5
 
7
6
  const root = fileURLToPath(new URL('..', import.meta.url))
8
7
 
9
- const fail = (message: string): never => {
8
+ const fail = (message) => {
10
9
  throw new Error(`release verification: ${message}`)
11
10
  }
12
11
 
13
- const json = async (path: string) => JSON.parse(await readFile(path, 'utf8')) as Record<string, unknown>
12
+ const json = async (path) => JSON.parse(await readFile(path, 'utf8'))
14
13
  const rootPackage = await json(join(root, 'package.json'))
15
- const selectorPackage = await json(join(root, 'packages/selector/package.json')) as Record<string, Record<string, unknown>>
14
+ const selectorPackage = await json(join(root, 'packages/selector/package.json'))
16
15
 
17
- const rootScripts = rootPackage.scripts as Record<string, string> | undefined
18
- const selectorScripts = selectorPackage.scripts as Record<string, string> | undefined
19
-
20
- if (!(rootScripts?.typecheck as string)?.includes('pnpm run typecheck:tests')
21
- || rootScripts?.['typecheck:tests'] !== 'tsc --noEmit -p tsconfig.tests.json') {
16
+ if (!rootPackage.scripts?.typecheck?.includes('pnpm run typecheck:tests')
17
+ || rootPackage.scripts?.['typecheck:tests'] !== 'tsc --noEmit -p tsconfig.tests.json') {
22
18
  fail('root typecheck must include the strict active-test TypeScript gate')
23
19
  }
24
- if (selectorScripts?.test
20
+ // The root manifest is the install surface for git installs: one package
21
+ // carries the runtime, the settings UI and the bundle patch.
22
+ if (rootPackage.name !== 'dsh-context-compression-improved') fail('unexpected root package name')
23
+ for (const specifier of ['.', './invariant', './pruner', './client']) {
24
+ if (rootPackage.exports?.[specifier] === undefined) {
25
+ fail(`root exports are missing the ${specifier} specifier`)
26
+ }
27
+ }
28
+ if (rootPackage.dsh?.bundle?.patch !== './packages/selector/cordis.patch.yml') {
29
+ fail('root must declare the DSH Bundle patch of the selector package')
30
+ }
31
+ for (const dependency of ['@huggingface/tokenizers', 'js-yaml']) {
32
+ if (rootPackage.dependencies?.[dependency] === undefined) {
33
+ fail(`root dependencies are missing ${dependency}`)
34
+ }
35
+ }
36
+ for (const specifier of ['.', './invariant', './pruner', './client']) {
37
+ if (selectorPackage.exports?.[specifier] === undefined) {
38
+ fail(`selector exports are missing the ${specifier} specifier`)
39
+ }
40
+ }
41
+ if (selectorPackage.scripts?.test
25
42
  !== 'vitest run --root ../.. --config vitest.config.ts --project runtime --project selector-host --project selector-client') {
26
- fail('Package-local test script is not the verified root project command')
43
+ fail('Selector package-local test script is not the verified root project command')
27
44
  }
28
45
  const ci = await readFile(join(root, '.github/workflows/ci.yml'), 'utf8')
29
- if (!ci.includes('pnpm --filter dsh-context-compression-improved test')) {
30
- fail('CI lacks the package-local gate: pnpm --filter dsh-context-compression-improved test')
46
+ for (const required of [
47
+ 'pnpm --filter dsh-context-compression-improved test',
48
+ ]) {
49
+ if (!ci.includes(required)) fail(`CI lacks package-local gate: ${required}`)
31
50
  }
32
51
  // The packed release E2E is the release gate that actually installs the
33
52
  // tarballs: verify it cannot be silently dropped or defanged. It must exist
34
53
  // as a root script, CI must run exactly that script, the script must default
35
54
  // to fail-closed release mode, and that mode must refuse every skip/null
36
55
  // lifecycle outcome.
37
- if (rootScripts?.['test:e2e:packed'] !== 'node scripts-dist/packed-install-e2e.js') {
56
+ if (rootPackage.scripts?.['test:e2e:packed'] !== 'node scripts/packed-install-e2e.mjs') {
38
57
  fail('root test:e2e:packed script is missing or does not run the packed E2E directly')
39
58
  }
40
59
  if (!ci.includes('pnpm run test:e2e:packed') && !ci.includes('pnpm test:e2e:packed')) {
41
60
  fail('CI does not run the packed release E2E gate')
42
61
  }
43
- const packedE2e = await readFile(join(root, 'scripts/packed-install-e2e.ts'), 'utf8')
44
- if (!/const e2eMode\s*(:\s*'dev'\s*\|\s*'release')?\s*=\s*process\.env\.DSH_E2E_MODE === 'dev' \? 'dev' : 'release'/u.test(packedE2e)) {
62
+ const packedE2e = await readFile(join(root, 'scripts/packed-install-e2e.mjs'), 'utf8')
63
+ if (!/const e2eMode = process\.env\.DSH_E2E_MODE === 'dev' \? 'dev' : 'release'/u.test(packedE2e)) {
45
64
  fail('packed E2E must default to release mode (dev only via an explicit DSH_E2E_MODE)')
46
65
  }
47
66
  for (const failClosed of [
@@ -52,7 +71,7 @@ for (const failClosed of [
52
71
  fail(`packed E2E release mode lost its fail-closed guard: ${failClosed}`)
53
72
  }
54
73
  }
55
- const packedComponents = await readFile(join(root, 'scripts/packed-components-smoke.ts'), 'utf8')
74
+ const packedComponents = await readFile(join(root, 'scripts/packed-components-smoke.mjs'), 'utf8')
56
75
  for (const required of [
57
76
  'Runtime.measureForCompaction(visionCtx, visionImage)',
58
77
  "estimatedImageCount?.kind === 'tokenizer-estimate'",
@@ -77,36 +96,30 @@ for (const required of [
77
96
  }
78
97
  await stat(join(root, 'tsconfig.tests.json'))
79
98
 
80
- if ((selectorPackage.dsh as Record<string, Record<string, string>>)?.bundle?.patch !== './cordis.patch.yml') {
99
+ if (selectorPackage.dsh?.bundle?.patch !== './cordis.patch.yml') {
81
100
  fail('selector must declare the DSH Bundle patch')
82
101
  }
83
- if ((selectorPackage.files as string[] | undefined)?.some((entry: string) => entry.endsWith('.css'))) {
102
+ if (selectorPackage.files?.some((entry) => entry.endsWith('.css'))) {
84
103
  fail('selector must not rely on separately served CSS assets')
85
104
  }
86
- if ((selectorPackage.name as unknown as string) !== 'dsh-context-compression-improved') fail('unexpected package name')
87
- if ((selectorPackage.publishConfig as Record<string, string>)?.access !== 'public') fail('publish access is not public')
88
- if ((selectorPackage.publishConfig as Record<string, string>)?.tag !== 'latest') fail('publish tag is not latest')
105
+ if (selectorPackage.name !== 'dsh-context-compression-improved') fail('unexpected selector package name')
106
+ if (selectorPackage.publishConfig?.access !== 'public') fail('selector publish access is not public')
107
+ if (selectorPackage.publishConfig?.tag !== 'latest') fail('selector publish tag is not latest')
89
108
  for (const peer of [
90
109
  '@deepseek-ai/dsh-command-compact',
91
110
  '@deepseek-ai/dsh-compaction-basic',
92
111
  ]) {
93
- if (((selectorPackage.peerDependencies as Record<string, string>) ?? {})[peer] !== '>=0.1.1-rc.2 <0.2.0') {
112
+ if (selectorPackage.peerDependencies?.[peer] !== '>=0.1.5-rc.2 <0.2.0-0') {
94
113
  fail(`selector peer ${peer} is missing or outside the verified range`)
95
114
  }
96
115
  }
97
- const notice = await readFile(join(root, 'packages/selector/THIRD_PARTY_NOTICES.md'), 'utf8')
116
+ const packageRoot = join(root, 'packages/selector')
117
+ const notice = await readFile(join(packageRoot, 'THIRD_PARTY_NOTICES.md'), 'utf8')
98
118
  if (!notice.includes('Copyright (c) 2026 DeepSeek')) {
99
119
  fail('packages/selector does not carry the full DeepSeek Harness MIT notice')
100
120
  }
101
121
 
102
- interface AssetManifest {
103
- directory: string
104
- repository: string
105
- modelIds: string
106
- revision?: string
107
- }
108
-
109
- const assetManifests: AssetManifest[] = [
122
+ const assetManifests = [
110
123
  {
111
124
  directory: 'deepseek-v4',
112
125
  repository: 'deepseek-ai/DeepSeek-V4-Pro',
@@ -121,12 +134,7 @@ const assetManifests: AssetManifest[] = [
121
134
  ]
122
135
  for (const expected of assetManifests) {
123
136
  const assetRoot = join(root, 'packages/selector/assets', expected.directory)
124
- const manifest = await json(join(assetRoot, 'manifest.json')) as {
125
- repository: string
126
- modelIds: string[]
127
- revision?: string
128
- files: Record<string, { bytes: number; sha256: string }>
129
- }
137
+ const manifest = await json(join(assetRoot, 'manifest.json'))
130
138
  if (manifest.repository !== expected.repository) fail(`${expected.directory} manifest repository differs`)
131
139
  if (!JSON.stringify(manifest.modelIds).includes(expected.modelIds)) {
132
140
  fail(`${expected.directory} manifest model ids differ`)
@@ -139,11 +147,15 @@ for (const expected of assetManifests) {
139
147
  const hash = createHash('sha256').update(bytes).digest('hex')
140
148
  if (bytes.byteLength !== descriptor.bytes) fail(`${expected.directory}/${name} byte length differs from manifest`)
141
149
  if (hash !== descriptor.sha256) fail(`${expected.directory}/${name} SHA-256 differs from manifest`)
150
+ // A checkout with core.autocrlf=true can rewrite these pinned bytes as CRLF;
151
+ // the `-text` attribute in .gitattributes prevents it, but only while the
152
+ // pattern still matches the path. Catch it here rather than in a consumer
153
+ // whose tokenizer would fail its own integrity check at run time.
154
+ if (bytes.includes(0x0d)) fail(`${expected.directory}/${name} contains CR bytes; the asset was rewritten`)
142
155
  }
143
- if (!(selectorPackage.files as string[] | undefined)?.some(
144
- entry => entry === 'assets' || entry === `assets/${expected.directory}/*`,
145
- )) {
146
- fail(`package files list omits assets for ${expected.directory}`)
156
+ const assetEntries = selectorPackage.files ?? []
157
+ if (!assetEntries.some(entry => entry === 'assets' || entry.startsWith('assets/'))) {
158
+ fail('selector package files list omits the tokenizer assets')
147
159
  }
148
160
  }
149
161
 
@@ -153,11 +165,13 @@ const forbidden = [
153
165
  { pattern: /@deepseek-ai\/[^'"\s]+\/src(?:\/|['"])/u, label: 'Harness source subpath import' },
154
166
  { pattern: /(?:\/home\/|[A-Za-z]:\\Users\\)/u, label: 'developer absolute path' },
155
167
  { pattern: /\.\.\/\.\.\/\.\.\/(?:core|packages)\//u, label: 'monorepo-relative source import' },
168
+ // The single-package merge must not leave a cross-package import behind.
169
+ { pattern: /from\s*['"]dsh-context-compression-improved-runtime/u, label: 'cross-package runtime import' },
156
170
  ]
157
171
 
158
- const walk = async (directory: string): Promise<string[]> => {
172
+ const walk = async (directory) => {
159
173
  const entries = await readdir(directory, { withFileTypes: true })
160
- const files: string[] = []
174
+ const files = []
161
175
  for (const entry of entries) {
162
176
  const path = join(directory, entry.name)
163
177
  if (entry.isDirectory()) files.push(...await walk(path))
@@ -175,52 +189,15 @@ for (const sourceRoot of sourceRoots) {
175
189
  }
176
190
  }
177
191
 
178
- const lib = join(root, 'packages/selector/lib')
192
+ const lib = join(packageRoot, 'lib')
179
193
  if (!(await stat(lib)).isDirectory()) fail(`${relative(root, lib)} is missing; run build first`)
180
194
  for (const path of await walk(lib)) {
181
195
  if (path.endsWith('.map')) fail(`${relative(root, path)} is a source map`)
182
- }
183
-
184
- // A git install ships exactly the tracked tree, so the artifact graph the
185
- // entries import must be complete AND committed. tsdown splits a shared chunk
186
- // out of every entry that reuses a module, and an untracked chunk makes the
187
- // installed entry crash at module-load time with ERR_MODULE_NOT_FOUND — the
188
- // same failure class as a cross-package import, so it gets the same gate.
189
- // Only the import graph is gated: build by-products nothing imports (for
190
- // example lib/style.css, whose rules the client artifact already carries
191
- // inline) are neither shipped nor required.
192
- const libArtifacts = await walk(lib)
193
- const libNames = new Set(libArtifacts.map(path => relative(lib, path).replaceAll('\\', '/')))
194
- const libScripts = [...libNames].filter(name => name.endsWith('.js')).sort()
195
- const libAllowedSuffixes = ((selectorPackage.files as unknown as string[]) ?? [])
196
- .filter(pattern => pattern.startsWith('lib/'))
197
- .map(pattern => pattern.slice(pattern.lastIndexOf('*') + 1))
198
- if (libAllowedSuffixes.length === 0) fail('selector package files allowlist covers no lib artifact')
199
- const isAllowed = (name: string) => libAllowedSuffixes.some(suffix => name.endsWith(suffix))
200
- const importedArtifacts = new Set<string>()
201
- for (const name of libScripts) {
202
- const text = await readFile(join(lib, name), 'utf8')
203
- for (const match of text.matchAll(/from\s*["'](\.\/[^"']+)["']/gu)) {
204
- const target = match[1]!.slice(2)
205
- if (!libNames.has(target)) fail(`lib/${name} imports missing artifact ${match[1]}`)
206
- importedArtifacts.add(target)
207
- }
208
- }
209
- for (const name of [...libScripts, ...importedArtifacts].sort()) {
210
- if (!isAllowed(name)) fail(`lib/${name} is part of the load graph but the package files allowlist would drop it`)
211
- }
212
- let trackedLib: Set<string> | undefined
213
- try {
214
- trackedLib = new Set(execFileSync('git', ['ls-files', '--', 'packages/selector/lib'], { cwd: root, encoding: 'utf8' })
215
- .split('\n').map(line => line.trim()).filter(Boolean))
216
- } catch (cause: unknown) {
217
- fail(`cannot read the tracked artifact list with git: ${(cause as Error).message}`)
218
- }
219
- if (trackedLib === undefined || trackedLib.size === 0) fail('git tracks no packages/selector/lib artifact; a git install would ship an unbuilt package')
220
- for (const name of [...libScripts, ...importedArtifacts].sort()) {
221
- const tracked = `packages/selector/lib/${name}`
222
- if (!trackedLib!.has(tracked)) {
223
- fail(`${tracked} is not committed; a git install would fetch an incomplete artifact graph`)
196
+ if (path.endsWith('.js')) {
197
+ const text = await readFile(path, 'utf8')
198
+ if (/from\s*["']dsh-context-compression-improved-runtime["']/u.test(text)) {
199
+ fail(`${relative(root, path)} still imports the removed runtime package`)
200
+ }
224
201
  }
225
202
  }
226
203
 
@@ -234,7 +211,7 @@ if (!clientArtifact.includes('data-plugin-css') || !clientArtifact.includes('doc
234
211
  if (/^\s*(?:import|export)\s/mu.test(clientArtifact)) fail('client.js contains ESM syntax')
235
212
  if (/(?:\/home\/|[A-Za-z]:\\Users\\)/u.test(clientArtifact)) fail('client.js contains a developer absolute path')
236
213
  if (clientArtifact.includes('sourceMappingURL')) fail('client.js contains a source map reference')
237
- const clientRequires = [...clientArtifact.matchAll(/require\("([^"]+)"\)/gu)].map(match => match[1]!).filter(Boolean)
214
+ const clientRequires = [...clientArtifact.matchAll(/require\("([^"]+)"\)/gu)].map(match => match[1])
238
215
  const allowedClientRequires = new Set([
239
216
  'react',
240
217
  'react/jsx-runtime',
@@ -244,7 +221,7 @@ for (const dependency of clientRequires) {
244
221
  if (!allowedClientRequires.has(dependency)) fail(`client.js has unexpected external dependency ${dependency}`)
245
222
  }
246
223
 
247
- const collectSpecs = async (directory: string) => (await walk(directory))
224
+ const collectSpecs = async (directory) => (await walk(directory))
248
225
  .filter(path => /\.spec\.tsx?$/u.test(path))
249
226
  .map(path => relative(root, path).replaceAll('\\', '/'))
250
227
  .sort()
@@ -289,11 +266,10 @@ for (const path of [...runtimeSpecs, ...selectorSpecs]) {
289
266
  }
290
267
  }
291
268
 
292
- const runtime = await import(new URL('../packages/selector/lib/pruner.js', import.meta.url).href)
293
- const defaults = runtime.DEFAULT_CUSTOM_COMPRESSION_POLICY as Record<string, Record<string, unknown>> | undefined
294
- if ((defaults?.history as Record<string, number>)?.trigger !== 500_000) fail('Custom History default is not 500000')
295
- if ((defaults?.tailTrim as Record<string, unknown>)?.trigger !== 700_000
296
- || (defaults?.tailTrim as Record<string, unknown>)?.enabled !== false) {
269
+ const runtime = await import(new URL('../packages/selector/lib/pruner.js', import.meta.url))
270
+ const defaults = runtime.DEFAULT_CUSTOM_COMPRESSION_POLICY
271
+ if (defaults?.history?.trigger !== 500_000) fail('Custom History default is not 500000')
272
+ if (defaults?.tailTrim?.trigger !== 700_000 || defaults?.tailTrim?.enabled !== false) {
297
273
  fail('Custom TailTrim default is not disabled at 700000')
298
274
  }
299
275
 
@@ -5,17 +5,16 @@ legacy-test allowlist.
5
5
 
6
6
  ## Root suite
7
7
 
8
- - Runtime: `packages/selector/tests/runtime/**/*.spec.ts` under the `runtime`
9
- project.
10
- - Selector Host: `cache-prefix-audit.spec.ts`, `estimator-catalog.spec.ts` plus
11
- every `*.host.spec.ts` under the `selector-host` project.
8
+ - Runtime: `packages/runtime/tests/**/*.spec.ts` under the `runtime` project.
9
+ - Selector Host: `cache-prefix-audit.spec.ts` plus every `*.host.spec.ts` under
10
+ the `selector-host` project.
12
11
  - Selector client: every `*.client.spec.ts` or `*.client.spec.tsx` under the
13
12
  `selector-client` project.
14
13
  - Built browser artifact: `packages/selector/tests/built/client-artifact.spec.ts`
15
14
  under the separate `vitest.built.config.ts` gate, after `pnpm build`.
16
15
 
17
- The root `pnpm test`, the package-local `pnpm test` command, and
18
- `pnpm test:built` are release gates. `scripts-dist/verify-release.js` (compiled from `scripts/verify-release.ts`) compares the
16
+ The root `pnpm test`, both package-local `pnpm test` commands, and
17
+ `pnpm test:built` are release gates. `scripts/verify-release.mjs` compares the
19
18
  checked-in spec inventory with these project rules so a new test cannot be
20
19
  silently excluded.
21
20
 
@@ -37,6 +36,6 @@ Their supported behavior is covered by active public tests:
37
36
  service identity: `packages/selector/tests/preset-overlay-loader.e2e.host.spec.ts`;
38
37
  - package/export/tarball contract:
39
38
  `packages/selector/tests/public/package-contract.client.spec.ts` and
40
- `scripts-dist/packed-install-e2e.js` (compiled from `scripts/packed-install-e2e.ts`);
39
+ `scripts/packed-install-e2e.mjs`;
41
40
  - profile and Custom editor behavior:
42
41
  `packages/selector/tests/profiles.client.spec.tsx`.
@@ -1,80 +0,0 @@
1
- /**
2
- * One-off baseline capture: freeze the resolvePolicy output for the pre-existing
3
- * profiles (before 'tokenpilot-inspired' is added) into a JSON fixture used by
4
- * tests/runtime/tokenpilot/profile-baseline.spec.ts as the backward-compat golden.
5
- *
6
- * Usage: node scripts-dist/capture-profile-baseline.js [baseline-file]
7
- */
8
- import { writeFileSync } from 'node:fs'
9
- import { createRequire } from 'node:module'
10
-
11
- /** The slice of the built pruner entry this capture consumes. */
12
- interface PrunerRuntime {
13
- resolveConfig: (input: Record<string, unknown>) => Record<string, unknown>
14
- resolvePolicy: (
15
- config: Record<string, unknown>,
16
- profile: string,
17
- custom: unknown,
18
- options: Record<string, unknown>,
19
- ) => Record<string, unknown>
20
- }
21
-
22
- /** One option matrix row. */
23
- interface OptionCase {
24
- label: string
25
- options: Record<string, unknown>
26
- }
27
-
28
- /** One custom-document matrix row. */
29
- interface CustomDocCase {
30
- label: string
31
- custom: unknown
32
- }
33
-
34
- /** The fixture shape `profile-baseline.spec.ts` reads back. */
35
- interface ProfileBaseline {
36
- capturedAt: string
37
- profiles: Record<string, Record<string, Record<string, unknown>>>
38
- }
39
-
40
- const require = createRequire(import.meta.url)
41
- const runtime = require('../packages/selector/lib/pruner.js') as PrunerRuntime
42
-
43
- const OLD_PROFILES: readonly string[] = [
44
- 'off',
45
- 'native',
46
- 'balanced',
47
- 'cache-strict',
48
- 'savings',
49
- 'adaptive',
50
- 'custom',
51
- ]
52
- const baseConfig = runtime.resolveConfig({})
53
- const OPTION_CASES: readonly OptionCase[] = [
54
- { label: 'defaults', options: {} },
55
- { label: 'linkage', options: { contextWindowTokens: 128_000, autoCompactThresholdPercent: 80 } },
56
- ]
57
- const CUSTOM_DOCS: readonly CustomDocCase[] = [
58
- { label: 'default-custom', custom: undefined },
59
- ]
60
-
61
- const snapshot: ProfileBaseline = { capturedAt: 'pre-tokenpilot-inspired', profiles: {} }
62
- for (const profile of OLD_PROFILES) {
63
- const byCase: Record<string, Record<string, unknown>> = {}
64
- snapshot.profiles[profile] = byCase
65
- for (const optionCase of OPTION_CASES) {
66
- for (const customCase of CUSTOM_DOCS) {
67
- const key = `${optionCase.label}${customCase.label === 'default-custom' ? '' : `/${customCase.label}`}`
68
- byCase[key] = runtime.resolvePolicy(
69
- baseConfig,
70
- profile,
71
- customCase.custom,
72
- optionCase.options,
73
- )
74
- }
75
- }
76
- }
77
-
78
- const out = process.argv[2] ?? 'packages/selector/tests/runtime/fixtures/profile-baseline.json'
79
- writeFileSync(out, `${JSON.stringify(snapshot, null, 2)}\n`)
80
- console.log(`baseline written: ${out}`)
@@ -1,13 +0,0 @@
1
- {
2
- "extends": "./tsconfig.base.json",
3
- "compilerOptions": {
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "allowImportingTsExtensions": false,
7
- "rootDir": "scripts",
8
- "outDir": "scripts-dist",
9
- "noEmit": false,
10
- "types": ["node"]
11
- },
12
- "include": ["scripts/**/*.ts"]
13
- }