dsh-code-index 0.11.1 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-code-index",
3
- "version": "0.11.1",
3
+ "version": "0.12.0",
4
4
  "description": "Impact X-Ray for DSH: inspect potential code-change impact, provenance and real source evidence before AI edits.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -51,7 +51,7 @@
51
51
  },
52
52
  "peerDependencies": {
53
53
  "@deepseek-ai/cordis": "^4.0.1",
54
- "@deepseek-ai/dsh-tools": "0.2.0-rc.2 || 0.2.1-rc.2 || 0.2.1-rc.3"
54
+ "@deepseek-ai/dsh-tools": ">=0.2.0-rc.2 || >=0.2.1-rc.2 <0.2.2 || >=0.2.2-rc.1 <0.2.3"
55
55
  },
56
56
  "peerDependenciesMeta": {
57
57
  "@deepseek-ai/cordis": {
@@ -64,6 +64,7 @@
64
64
  "@types/node": "^26.2.0",
65
65
  "@types/react": "^18.3.31",
66
66
  "react": "^18.3.1",
67
+ "semver": "^7.8.5",
67
68
  "tsup": "^8.5.0",
68
69
  "typescript": "^6.0.3",
69
70
  "vitest": "^4.1.8"
@@ -4,7 +4,9 @@ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'nod
4
4
  import os from 'node:os'
5
5
  import { createRequire } from 'node:module'
6
6
  import path from 'node:path'
7
+ import semver from 'semver'
7
8
  import { fileURLToPath, pathToFileURL } from 'node:url'
9
+ import { createHash } from 'node:crypto'
8
10
 
9
11
  const root = path.resolve(fileURLToPath(new URL('..', import.meta.url)))
10
12
  const packageJson = JSON.parse(readFileSync(path.join(root, 'package.json'), 'utf8'))
@@ -15,6 +17,9 @@ function shellQuote(value) {
15
17
  }
16
18
 
17
19
  function run(command, args, cwd) {
20
+ if (command === npm && process.env.CIX_NPM_CLI) return execFileSync(process.execPath, [process.env.CIX_NPM_CLI, ...args], {
21
+ cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'inherit'],
22
+ })
18
23
  const invocation = [command, ...args].map(shellQuote).join(' ')
19
24
  const commandArgs = process.platform === 'win32'
20
25
  ? ['/d', '/s', '/c', invocation]
@@ -66,10 +71,11 @@ function parseJsonArrayOutput(output, command) {
66
71
 
67
72
  // A release gate can reuse one immutable candidate across Node versions.
68
73
  const suppliedTarball = process.argv[2] ? path.resolve(process.argv[2]) : null
69
- // Exercise each supported host group against the same immutable candidate.
74
+ // Exercise a selected host version against the same immutable candidate.
70
75
  const toolsVersion = process.argv[3] ?? '0.2.1-rc.3'
71
- const supportedToolsVersions = packageJson.peerDependencies['@deepseek-ai/dsh-tools'].split(' || ')
72
- assert.ok(supportedToolsVersions.includes(toolsVersion), 'smoke requires an explicitly supported DSH tools version')
76
+ const toolsRange = packageJson.peerDependencies['@deepseek-ai/dsh-tools']
77
+ assert.ok(semver.satisfies(toolsVersion, toolsRange, { includePrerelease: true }), 'smoke requires a DSH tools version matching the peer range')
78
+ assert.ok(semver.satisfies(toolsVersion, toolsRange), 'smoke requires normal npm prerelease peer compatibility')
73
79
  const packed = suppliedTarball ? null : parseJsonArrayOutput(run(npm, ['pack', '--ignore-scripts', '--json'], root), 'npm pack')
74
80
  if (packed) assert.equal(packed.length, 1, 'npm pack must produce exactly one artifact')
75
81
  const tarball = suppliedTarball ?? path.resolve(root, packed[0].filename)
@@ -95,8 +101,10 @@ const expectedFiles = [
95
101
  for (const file of expectedFiles) assert.ok(listed.has(file), `tarball is missing ${file}`)
96
102
 
97
103
  const smokeDir = mkdtempSync(path.join(os.tmpdir(), 'dsh-code-index-release-'))
104
+ let nativeCalls = 0
98
105
  try {
99
106
  run(npm, ['init', '--yes'], smokeDir)
107
+ console.log('smoke fixture: normal npm peer resolution; no force or legacy-peer-deps')
100
108
  run(npm, ['install', '--ignore-scripts', '--no-save', tarball, `@deepseek-ai/dsh-tools@${toolsVersion}`], smokeDir)
101
109
 
102
110
  const installedPackage = JSON.parse(
@@ -108,7 +116,7 @@ try {
108
116
  assert.match(installedPackage.engines.node, />=22/)
109
117
  assert.equal(installedPackage.license, 'MIT')
110
118
  const installedTools = JSON.parse(readFileSync(path.join(smokeDir, 'node_modules', '@deepseek-ai', 'dsh-tools', 'package.json'), 'utf8'))
111
- assert.equal(installedTools.version, toolsVersion, 'consumer must use the selected matching RC group')
119
+ assert.equal(installedTools.version, toolsVersion, 'consumer must use the selected DSH tools version')
112
120
 
113
121
  const plugin = await import(
114
122
  pathToFileURL(path.join(smokeDir, 'node_modules', packageJson.name, 'dist', 'index.js')).href,
@@ -168,6 +176,26 @@ try {
168
176
  assert.ok(contextPack.items.some(item => item.kind === 'primary' && item.name === 'buildIndex'))
169
177
  assert.ok(contextPack.items.some(item => item.code !== undefined))
170
178
  assert.ok(JSON.stringify(contextPack).length <= 5000)
179
+ const evidenceRoot = path.join(smokeDir, 'evidence')
180
+ mkdirSync(path.join(evidenceRoot, '.git'), { recursive: true })
181
+ writeFileSync(path.join(evidenceRoot, 'core.ts'), 'export function lonelyMarker() { return 7 }\n')
182
+ for (const budgetChars of [300, 500, 5000]) {
183
+ const args = { repoRoot: evidenceRoot, task: '定位 lonelyMarker 的实现,不要修改代码', budgetChars }
184
+ const pack = await invoke('code_context', { ...args, outputFormat: 'pack' })
185
+ const text = await invoke('code_context', args)
186
+ assert.equal(pack.version, 1)
187
+ assert.ok(JSON.stringify(pack).length <= budgetChars)
188
+ assert.ok(text.length <= budgetChars)
189
+ assert.equal(text, plugin.renderContextPack(pack))
190
+ if (budgetChars === 5000) {
191
+ assert.equal(pack.evidence.scope, 'indexed-static-only')
192
+ assert.equal(pack.evidence.tests.verification, 'not-run')
193
+ assert.equal(pack.evidence.callers.zero[0].name, 'lonelyMarker')
194
+ assert.match(text, /not proof of no callers/)
195
+ }
196
+ }
197
+ assert.match(await invoke('code_refs', { repoRoot: evidenceRoot, symbol: 'lonelyMarker' }), /not proof of no callers/)
198
+ assert.match(await invoke('code_change_context', { repoRoot: evidenceRoot, files: ['core.ts'] }), /Evidence \(indexed static scope/)
171
199
  assert.match(await invoke('code_health', { repoRoot: root }), /repo health/)
172
200
 
173
201
  // Issue #2 must also be fixed in the installed tarball, not just TS sources.
@@ -275,6 +303,7 @@ try {
275
303
  signal: new AbortController().signal,
276
304
  })
277
305
  assert.equal(result.isError, false, JSON.stringify(result.content))
306
+ nativeCalls++
278
307
  return result
279
308
  }
280
309
  await nativeInvoke('code_index', { action: 'build', repoRoot: arkRoot })
@@ -318,6 +347,8 @@ try {
318
347
  assert.equal(xray.meta.edges.filter(e => e.kind === 'call').length, 6)
319
348
  assert.equal(xray.meta.edges.filter(e => e.kind === 'import').length, 3)
320
349
  assert.equal(xray.meta.tests.length, 1)
350
+ assert.equal(xray.meta.evidence.scope, 'indexed-static-only')
351
+ assert.equal(xray.meta.evidence.tests.verification, 'not-run')
321
352
  assert.deepEqual(new Set(xray.meta.edges.map(e => e.resolution)), new Set(['exact', 'import-scoped', 'name-only']))
322
353
  assert.ok(xray.meta.paths.some(p => p.edgeIds.length === 2 && p.resolution === 'exact' && !p.omitted))
323
354
  assert.ok(Buffer.byteLength(JSON.stringify(xray.meta)) <= plugin.XRAY_LIMITS.metadataBytes)
@@ -339,8 +370,20 @@ try {
339
370
  for (const dispose of nativeDisposers.reverse()) dispose()
340
371
  await nativeContext.fiber.dispose()
341
372
  }
342
- console.log(`release smoke passed for ${packageJson.name}@${packageJson.version} with dsh-tools@${toolsVersion}`)
373
+ console.log(`release smoke passed (normal npm peer resolution and DSH runtime) for ${packageJson.name}@${packageJson.version} with dsh-tools@${toolsVersion}`)
374
+ if (process.env.CIX_SMOKE_RECORD) writeFileSync(process.env.CIX_SMOKE_RECORD, JSON.stringify({
375
+ node: process.version, version: installedPackage.version, toolsVersion, nativeCalls,
376
+ tarball, sha256: createHash('sha256').update(readFileSync(tarball)).digest('hex'),
377
+ installedRoot: path.join(smokeDir, 'node_modules', packageJson.name),
378
+ methods: ['clean npm install --ignore-scripts; normal peer resolution', 'plugin apply/dispose', 'real ToolRuntime dispatch'],
379
+ evidence: true, budgets: [300, 500, 5000], passed: true,
380
+ }, null, 2) + '\n')
343
381
  } finally {
344
- rmSync(smokeDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 })
382
+ if (process.env.CIX_SMOKE_KEEP === '1') console.log(`retained isolated smoke directory: ${smokeDir}`)
383
+ else {
384
+ assert.equal(path.dirname(path.resolve(smokeDir)), path.resolve(os.tmpdir()))
385
+ assert.ok(path.basename(smokeDir).startsWith('dsh-code-index-release-'))
386
+ rmSync(smokeDir, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 })
387
+ }
345
388
  if (!suppliedTarball) rmSync(tarball, { force: true })
346
389
  }