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/CHANGELOG.md +16 -0
- package/README.md +32 -19
- package/README.zh.md +32 -19
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +55 -1
- package/dist/index.js +433 -100
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/scripts/release-smoke.mjs +49 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-code-index",
|
|
3
|
-
"version": "0.
|
|
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.
|
|
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
|
|
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
|
|
72
|
-
assert.ok(
|
|
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
|
|
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
|
-
|
|
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
|
}
|