dsh-code-index 0.11.2 → 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.2",
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"
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": {
@@ -6,6 +6,7 @@ import { createRequire } from 'node:module'
6
6
  import path from 'node:path'
7
7
  import semver from 'semver'
8
8
  import { fileURLToPath, pathToFileURL } from 'node:url'
9
+ import { createHash } from 'node:crypto'
9
10
 
10
11
  const root = path.resolve(fileURLToPath(new URL('..', import.meta.url)))
11
12
  const packageJson = JSON.parse(readFileSync(path.join(root, 'package.json'), 'utf8'))
@@ -16,6 +17,9 @@ function shellQuote(value) {
16
17
  }
17
18
 
18
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
+ })
19
23
  const invocation = [command, ...args].map(shellQuote).join(' ')
20
24
  const commandArgs = process.platform === 'win32'
21
25
  ? ['/d', '/s', '/c', invocation]
@@ -71,6 +75,7 @@ const suppliedTarball = process.argv[2] ? path.resolve(process.argv[2]) : null
71
75
  const toolsVersion = process.argv[3] ?? '0.2.1-rc.3'
72
76
  const toolsRange = packageJson.peerDependencies['@deepseek-ai/dsh-tools']
73
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')
74
79
  const packed = suppliedTarball ? null : parseJsonArrayOutput(run(npm, ['pack', '--ignore-scripts', '--json'], root), 'npm pack')
75
80
  if (packed) assert.equal(packed.length, 1, 'npm pack must produce exactly one artifact')
76
81
  const tarball = suppliedTarball ?? path.resolve(root, packed[0].filename)
@@ -96,13 +101,11 @@ const expectedFiles = [
96
101
  for (const file of expectedFiles) assert.ok(listed.has(file), `tarball is missing ${file}`)
97
102
 
98
103
  const smokeDir = mkdtempSync(path.join(os.tmpdir(), 'dsh-code-index-release-'))
104
+ let nativeCalls = 0
99
105
  try {
100
106
  run(npm, ['init', '--yes'], smokeDir)
101
- // npm's default peer checks exclude prereleases that DSH explicitly accepts.
102
- // --force only prepares this disposable runtime fixture; it does not prove
103
- // normal npm peer resolution. The range assertion above uses DSH's rules.
104
- console.log('smoke fixture: npm --force bypasses peer resolution; validating DSH range and runtime only')
105
- run(npm, ['install', '--ignore-scripts', '--no-save', '--force', tarball, `@deepseek-ai/dsh-tools@${toolsVersion}`], smokeDir)
107
+ console.log('smoke fixture: normal npm peer resolution; no force or legacy-peer-deps')
108
+ run(npm, ['install', '--ignore-scripts', '--no-save', tarball, `@deepseek-ai/dsh-tools@${toolsVersion}`], smokeDir)
106
109
 
107
110
  const installedPackage = JSON.parse(
108
111
  readFileSync(path.join(smokeDir, 'node_modules', packageJson.name, 'package.json'), 'utf8'),
@@ -173,6 +176,26 @@ try {
173
176
  assert.ok(contextPack.items.some(item => item.kind === 'primary' && item.name === 'buildIndex'))
174
177
  assert.ok(contextPack.items.some(item => item.code !== undefined))
175
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/)
176
199
  assert.match(await invoke('code_health', { repoRoot: root }), /repo health/)
177
200
 
178
201
  // Issue #2 must also be fixed in the installed tarball, not just TS sources.
@@ -280,6 +303,7 @@ try {
280
303
  signal: new AbortController().signal,
281
304
  })
282
305
  assert.equal(result.isError, false, JSON.stringify(result.content))
306
+ nativeCalls++
283
307
  return result
284
308
  }
285
309
  await nativeInvoke('code_index', { action: 'build', repoRoot: arkRoot })
@@ -323,6 +347,8 @@ try {
323
347
  assert.equal(xray.meta.edges.filter(e => e.kind === 'call').length, 6)
324
348
  assert.equal(xray.meta.edges.filter(e => e.kind === 'import').length, 3)
325
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')
326
352
  assert.deepEqual(new Set(xray.meta.edges.map(e => e.resolution)), new Set(['exact', 'import-scoped', 'name-only']))
327
353
  assert.ok(xray.meta.paths.some(p => p.edgeIds.length === 2 && p.resolution === 'exact' && !p.omitted))
328
354
  assert.ok(Buffer.byteLength(JSON.stringify(xray.meta)) <= plugin.XRAY_LIMITS.metadataBytes)
@@ -344,8 +370,20 @@ try {
344
370
  for (const dispose of nativeDisposers.reverse()) dispose()
345
371
  await nativeContext.fiber.dispose()
346
372
  }
347
- console.log(`release smoke passed (DSH range/runtime; npm peer resolution bypassed) 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')
348
381
  } finally {
349
- 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
+ }
350
388
  if (!suppliedTarball) rmSync(tarball, { force: true })
351
389
  }