dsh-update-center 0.8.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/LICENSE +29 -0
- package/README.md +93 -0
- package/cordis.patch.yml +4 -0
- package/data/extra-plugins.json +112 -0
- package/data/registry-snapshot.json +7636 -0
- package/lib/client.js +606 -0
- package/lib/client.js.map +1 -0
- package/lib/github-topic.mjs +80 -0
- package/lib/index.js +1048 -0
- package/lib/index.js.map +1 -0
- package/lib/npm-mapping.mjs +43 -0
- package/lib/run-command.mjs +58 -0
- package/lib/types/client/index.d.ts +12 -0
- package/lib/types/index.d.ts +43 -0
- package/package.json +76 -0
- package/plugins.json +7636 -0
- package/scripts/build.mjs +101 -0
- package/scripts/build.sh +4 -0
- package/scripts/refresh-snapshot.mjs +93 -0
- package/scripts/update-worker.mjs +598 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, symlinkSync } from 'node:fs'
|
|
2
|
+
import { homedir } from 'node:os'
|
|
3
|
+
import { dirname, join, resolve } from 'node:path'
|
|
4
|
+
import { spawnSync } from 'node:child_process'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
|
|
7
|
+
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
8
|
+
const mode = process.argv[2] ?? '--all'
|
|
9
|
+
|
|
10
|
+
function packageName(dir) {
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')).name
|
|
13
|
+
} catch {
|
|
14
|
+
return null
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function findCheckout() {
|
|
19
|
+
const candidates = [
|
|
20
|
+
process.env.DSH_CHECKOUT,
|
|
21
|
+
resolve(root, '..', '..', 'deepseek-harness'),
|
|
22
|
+
join(homedir(), 'dsh-harness'),
|
|
23
|
+
join(homedir(), 'deepseek-harness'),
|
|
24
|
+
join(homedir(), '.dsh', 'dsh-harness'),
|
|
25
|
+
].filter(Boolean)
|
|
26
|
+
return candidates.find((candidate) => packageName(candidate) === '@deepseek-ai/dsh-root') ?? null
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const checkout = findCheckout()
|
|
30
|
+
if (!checkout) {
|
|
31
|
+
console.error('build: cannot locate the dsh checkout; set DSH_CHECKOUT')
|
|
32
|
+
process.exit(1)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function linkPackage(name, targetRelative) {
|
|
36
|
+
const target = resolve(checkout, targetRelative)
|
|
37
|
+
const link = resolve(root, 'node_modules', ...name.split('/'))
|
|
38
|
+
if (!existsSync(target)) throw new Error(`dependency target missing: ${target}`)
|
|
39
|
+
rmSync(link, { recursive: true, force: true })
|
|
40
|
+
mkdirSync(dirname(link), { recursive: true })
|
|
41
|
+
symlinkSync(target, link, process.platform === 'win32' ? 'junction' : 'dir')
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function linkStandardSchema() {
|
|
45
|
+
const store = join(checkout, 'node_modules', '.pnpm')
|
|
46
|
+
if (!existsSync(store)) return
|
|
47
|
+
const entry = readdirSync(store).find((name) => name.toLowerCase().startsWith('@standard-schema+spec@'))
|
|
48
|
+
if (!entry) return
|
|
49
|
+
const target = join(store, entry, 'node_modules', '@standard-schema', 'spec')
|
|
50
|
+
if (existsSync(target)) linkAbsolute('@standard-schema/spec', target)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function linkAbsolute(name, target) {
|
|
54
|
+
const link = resolve(root, 'node_modules', ...name.split('/'))
|
|
55
|
+
rmSync(link, { recursive: true, force: true })
|
|
56
|
+
mkdirSync(dirname(link), { recursive: true })
|
|
57
|
+
symlinkSync(resolve(target), link, process.platform === 'win32' ? 'junction' : 'dir')
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function prepareDependencies() {
|
|
61
|
+
linkPackage('cordis', 'vendor/cordis')
|
|
62
|
+
linkPackage('cosmokit', 'vendor/cosmokit')
|
|
63
|
+
linkPackage('schemastery', 'vendor/schemastery')
|
|
64
|
+
linkPackage('@deepseek-ai/dsh-tools', 'packages/core/tools')
|
|
65
|
+
linkPackage('@deepseek-ai/dsh-llm', 'packages/llm/llm')
|
|
66
|
+
linkPackage('@deepseek-ai/dsh-system-prompt', 'packages/core/system-prompt')
|
|
67
|
+
linkPackage('@deepseek-ai/dsh-client-ui-slots', 'packages/client/ui-slots')
|
|
68
|
+
linkPackage('@types/node', 'node_modules/@types/node')
|
|
69
|
+
linkStandardSchema()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function runNode(entry, args) {
|
|
73
|
+
const result = spawnSync(process.execPath, [entry, ...args], {
|
|
74
|
+
cwd: root,
|
|
75
|
+
encoding: 'utf8',
|
|
76
|
+
stdio: 'inherit',
|
|
77
|
+
})
|
|
78
|
+
if (result.error) throw result.error
|
|
79
|
+
if (result.status !== 0) process.exit(result.status ?? 1)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
prepareDependencies()
|
|
83
|
+
|
|
84
|
+
const tsc = join(checkout, 'node_modules', 'typescript', 'bin', 'tsc')
|
|
85
|
+
const tsdown = join(checkout, 'node_modules', 'tsdown', 'dist', 'run.mjs')
|
|
86
|
+
|
|
87
|
+
if (mode === '--typecheck') {
|
|
88
|
+
runNode(tsc, ['-p', 'tsconfig.json', '--noEmit'])
|
|
89
|
+
} else if (mode === '--client') {
|
|
90
|
+
runNode(tsdown, [])
|
|
91
|
+
} else if (mode === '--all') {
|
|
92
|
+
runNode(tsc, ['-p', 'tsconfig.json'])
|
|
93
|
+
runNode(tsdown, [])
|
|
94
|
+
// host 产物由 tsc 逐文件转译(不打包),共享的 .mjs 模块需随产物分发。
|
|
95
|
+
for (const shared of ['run-command.mjs', 'github-topic.mjs', 'npm-mapping.mjs']) {
|
|
96
|
+
copyFileSync(join(root, 'src', shared), join(root, 'lib', shared))
|
|
97
|
+
}
|
|
98
|
+
} else {
|
|
99
|
+
console.error(`build: unknown mode ${mode}`)
|
|
100
|
+
process.exit(2)
|
|
101
|
+
}
|
package/scripts/build.sh
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 维护本仓库根目录的 plugins.json 注册表(像 awesome-dsh-plugin 一样对外提供):
|
|
3
|
+
* plugins.json —— 已有注册表(若存在)作为基底累计合并 GitHub topic:dsh-plugin
|
|
4
|
+
* 星标前 500(排除 fork)+ 本插件自身,按 owner/name 去重:掉出扫描窗口
|
|
5
|
+
* 的老条目保留,新条目追加,已知条目刷新星标。
|
|
6
|
+
* data/registry-snapshot.json —— 同一份数据的随包离线快照。
|
|
7
|
+
* data/extra-plugins.json —— 常驻条目(加载时无条件合并,保证 0 星新插件可见)。
|
|
8
|
+
*
|
|
9
|
+
* 运行:npm run refresh:snapshot(需网络可达 api.github.com)
|
|
10
|
+
*/
|
|
11
|
+
import { readFile, writeFile } from 'node:fs/promises'
|
|
12
|
+
import { dirname, join } from 'node:path'
|
|
13
|
+
import { fileURLToPath } from 'node:url'
|
|
14
|
+
import { buildRegistryFromRepos, mergeGithubTopic } from '../src/github-topic.mjs'
|
|
15
|
+
import { applyNpmMapping } from '../src/npm-mapping.mjs'
|
|
16
|
+
|
|
17
|
+
const root = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
18
|
+
const SELF_REPO = 'Britneycode/dsh-update-center'
|
|
19
|
+
const TOPIC_PAGES = 5
|
|
20
|
+
const MAX_ENTRIES = 2000
|
|
21
|
+
|
|
22
|
+
async function fetchJson(url) {
|
|
23
|
+
const response = await fetch(url, { headers: { accept: 'application/vnd.github+json' } })
|
|
24
|
+
if (!response.ok) throw new Error(`${response.status} ${url}`)
|
|
25
|
+
return response.json()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function fetchGithubTopicRepos() {
|
|
29
|
+
const repos = []
|
|
30
|
+
for (let page = 1; page <= TOPIC_PAGES; page++) {
|
|
31
|
+
const url = new URL('https://api.github.com/search/repositories')
|
|
32
|
+
url.searchParams.set('q', 'topic:dsh-plugin')
|
|
33
|
+
url.searchParams.set('sort', 'stars')
|
|
34
|
+
url.searchParams.set('order', 'desc')
|
|
35
|
+
url.searchParams.set('per_page', '100')
|
|
36
|
+
url.searchParams.set('page', String(page))
|
|
37
|
+
if (url.protocol !== 'https:' || url.hostname !== 'api.github.com') throw new Error(`endpoint check failed: ${url.host}`)
|
|
38
|
+
const payload = await fetchJson(url)
|
|
39
|
+
if (!Array.isArray(payload?.items)) break
|
|
40
|
+
repos.push(...payload.items.filter((repo) => repo && repo.fork !== true))
|
|
41
|
+
if (payload.items.length < 100) break
|
|
42
|
+
}
|
|
43
|
+
return repos
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function loadExistingRegistry() {
|
|
47
|
+
try {
|
|
48
|
+
const data = JSON.parse(await readFile(join(root, 'plugins.json'), 'utf8'))
|
|
49
|
+
if (Array.isArray(data?.plugins) && data.plugins.length) return data
|
|
50
|
+
} catch { /* 首次生成时没有存量 */ }
|
|
51
|
+
return null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function fetchNpmSearchObjects() {
|
|
55
|
+
const objects = []
|
|
56
|
+
for (let from = 0; from < 1000; from += 250) {
|
|
57
|
+
const url = new URL('https://registry.npmjs.org/-/v1/search')
|
|
58
|
+
url.searchParams.set('text', 'keywords:dsh-plugin')
|
|
59
|
+
url.searchParams.set('size', '250')
|
|
60
|
+
url.searchParams.set('from', String(from))
|
|
61
|
+
if (url.protocol !== 'https:' || url.hostname !== 'registry.npmjs.org') throw new Error(`endpoint check failed: ${url.host}`)
|
|
62
|
+
const payload = await fetchJson(url)
|
|
63
|
+
const items = Array.isArray(payload?.objects) ? payload.objects : []
|
|
64
|
+
if (!items.length) break
|
|
65
|
+
objects.push(...items)
|
|
66
|
+
if (from + items.length >= Number(payload?.total ?? 0)) break
|
|
67
|
+
}
|
|
68
|
+
return objects
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const topicRepos = await fetchGithubTopicRepos()
|
|
72
|
+
if (!topicRepos.length) throw new Error('GitHub topic scan returned nothing')
|
|
73
|
+
const selfRepo = await fetchJson(`https://api.github.com/repos/${SELF_REPO}`)
|
|
74
|
+
if (!selfRepo?.name) throw new Error('self repo info invalid')
|
|
75
|
+
|
|
76
|
+
const existing = await loadExistingRegistry()
|
|
77
|
+
const data = existing ?? buildRegistryFromRepos(topicRepos)
|
|
78
|
+
const merged = mergeGithubTopic(data, [...topicRepos, selfRepo])
|
|
79
|
+
const npmObjects = await fetchNpmSearchObjects()
|
|
80
|
+
const mapped = applyNpmMapping(data, npmObjects)
|
|
81
|
+
if (data.plugins.length > MAX_ENTRIES) {
|
|
82
|
+
data.plugins.sort((a, b) => Number(b.stars ?? 0) - Number(a.stars ?? 0))
|
|
83
|
+
data.plugins = data.plugins.slice(0, MAX_ENTRIES)
|
|
84
|
+
}
|
|
85
|
+
data.updated = new Date().toISOString().slice(0, 10)
|
|
86
|
+
data.count = data.plugins.length
|
|
87
|
+
|
|
88
|
+
const text = JSON.stringify(data, null, 1) + '\n'
|
|
89
|
+
await writeFile(join(root, 'plugins.json'), text, 'utf8')
|
|
90
|
+
await writeFile(join(root, 'data', 'registry-snapshot.json'), text, 'utf8')
|
|
91
|
+
await writeFile(join(root, 'data', 'extra-plugins.json'), JSON.stringify([selfRepo], null, 1) + '\n', 'utf8')
|
|
92
|
+
const base = existing ? `存量 ${existing.plugins.length}` : '新建'
|
|
93
|
+
console.log(`plugins.json 已生成:${base} + 本轮扫描新增 ${merged.added}(含去重)+ npm 映射 ${mapped} = 共 ${data.plugins.length} 条(上限 ${MAX_ENTRIES})`)
|