@noob-stupid/dsh-plugin-console 0.3.66 → 0.4.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/README.md +1 -1
- package/README.zh.md +1 -1
- package/lib/client.js +127 -32
- package/lib/index.js +60 -9687
- package/lib/server/domain/ai-run.js +479 -0
- package/lib/server/domain/ai.js +246 -0
- package/lib/server/domain/compat.js +474 -0
- package/lib/server/domain/components.js +108 -0
- package/lib/server/domain/dep-source.js +122 -0
- package/lib/server/domain/format-contract.js +265 -0
- package/lib/server/domain/format-scan.js +431 -0
- package/lib/server/domain/framework.js +393 -0
- package/lib/server/domain/install-job.js +561 -0
- package/lib/server/domain/install.js +599 -0
- package/lib/server/domain/jobs.js +28 -0
- package/lib/server/domain/market.js +409 -0
- package/lib/server/domain/patch.js +203 -0
- package/lib/server/domain/presets.js +93 -0
- package/lib/server/domain/quarantine.js +224 -0
- package/lib/server/domain/release-source.js +504 -0
- package/lib/server/domain/repoland.js +119 -0
- package/lib/server/domain/revoke.js +184 -0
- package/lib/server/domain/runtime.js +118 -0
- package/lib/server/domain/selfupdate.js +319 -0
- package/lib/server/domain/skills.js +234 -0
- package/lib/server/domain/sources.js +297 -0
- package/lib/server/domain/suite.js +220 -0
- package/lib/server/infra/exec.js +98 -0
- package/lib/server/infra/fsx.js +163 -0
- package/lib/server/infra/fw-integrity-check.js +37 -0
- package/lib/server/infra/http.js +373 -0
- package/lib/server/infra/httpd.js +51 -0
- package/lib/server/infra/mask.js +19 -0
- package/lib/server/infra/paths.js +177 -0
- package/lib/server/infra/semver.js +168 -0
- package/lib/server/routes/ai.js +172 -0
- package/lib/server/routes/components.js +254 -0
- package/lib/server/routes/framework-preflight.js +154 -0
- package/lib/server/routes/framework-upgrade.js +679 -0
- package/lib/server/routes/framework.js +544 -0
- package/lib/server/routes/github-login.js +198 -0
- package/lib/server/routes/index.js +128 -0
- package/lib/server/routes/install.js +116 -0
- package/lib/server/routes/market.js +415 -0
- package/lib/server/routes/plugins.js +562 -0
- package/lib/server/routes/skills.js +107 -0
- package/lib/server/routes/sources.js +437 -0
- package/lib/server/routes/state.js +125 -0
- package/lib/server/state.js +22 -0
- package/package.json +1 -1
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// L2 · routes —— 会话格式契约预检(Step 1+2)
|
|
2
|
+
// POST /plugin-console/framework-preflight 只读预检:抓目标版本契约 + 扫描本地生产方
|
|
3
|
+
// POST /plugin-console/framework-preflight-patch 补丁:mode=plan 出 diff;mode=apply 备份后写回
|
|
4
|
+
//
|
|
5
|
+
// 为什么要有它(2026-09-24 事故):框架 0.1.5-rc.2 → 0.1.7-rc.1 把会话消息格式升到 V4,
|
|
6
|
+
// 运行期生产方(agent-presets + 插件 runtime)仍写 V3 的 `kind: 'plugin'` 包装 →
|
|
7
|
+
// 「一发消息就报错、会话整体不可用」。包级适配门(peerDependencies / 版本号)看不见这类
|
|
8
|
+
// 运行期契约破坏,所以必须在**升级前**单独预检、先把本地适配好再装。
|
|
9
|
+
|
|
10
|
+
import { dirname, join } from 'node:path'
|
|
11
|
+
import { isFrameworkOwnedPackage } from '../domain/compat.js'
|
|
12
|
+
import { discoverFormatContract, summarizeContract } from '../domain/format-contract.js'
|
|
13
|
+
import { applyFormatPatch, collectProducerTargets, scanProducerFiles } from '../domain/format-scan.js'
|
|
14
|
+
import { currentFrameworkVersion } from '../domain/framework.js'
|
|
15
|
+
import { listEntries } from '../domain/runtime.js'
|
|
16
|
+
import { curlText, fetchJsonUrl } from '../infra/http.js'
|
|
17
|
+
import { sendError, sendJson } from '../infra/httpd.js'
|
|
18
|
+
import { baseDirOf, dshHome, profileDirOf, resolvePackageJson } from '../infra/paths.js'
|
|
19
|
+
|
|
20
|
+
const REGISTRY = 'https://registry.npmmirror.com'
|
|
21
|
+
|
|
22
|
+
/** 预检的两个扫描面:用户预设目录 + profile 内每个已装插件包。
|
|
23
|
+
* 框架自带包(解析到 profile 之外,即 npx 缓存里的 @deepseek-ai/*)标成 kind='framework':
|
|
24
|
+
* 仍然扫(能暴露框架自身的契约不一致),但**只报告不改**——改它等于污染框架安装树。 */
|
|
25
|
+
function preflightRoots(ports, profileDir) {
|
|
26
|
+
const roots = [{ root: join(dshHome(), 'agent-presets'), kind: 'preset' }]
|
|
27
|
+
let entries = []
|
|
28
|
+
try { entries = listEntries(ports) } catch {}
|
|
29
|
+
const baseDir = baseDirOf(ports?.baseUrl ?? 'file:///')
|
|
30
|
+
for (const entry of entries) {
|
|
31
|
+
if (typeof entry.moduleName !== 'string' || entry.moduleName === '' || entry.moduleName.startsWith('cordis:')) continue
|
|
32
|
+
let pkgPath = null
|
|
33
|
+
try { pkgPath = resolvePackageJson(entry.moduleName, baseDir, profileDir) } catch {}
|
|
34
|
+
if (pkgPath === null) continue
|
|
35
|
+
const pkgDir = dirname(pkgPath)
|
|
36
|
+
let kind = 'plugin'
|
|
37
|
+
// 框架自带包判定用两个信号(缺一不可):
|
|
38
|
+
// ① 解析到 profile 之外(junction 进 npx 缓存的常见形态);
|
|
39
|
+
// ② 包名落在 @deepseek-ai/ 作用域 —— profile 里存在**手工铺的真实副本**(实网见到
|
|
40
|
+
// @deepseek-ai/dsh-schedule@0.0.1-rc.3、schemastery@3.18.1 这种陈旧副本),
|
|
41
|
+
// 它们物理上在 profile 内,路径判定认不出来,但同样不该被预检手改(正确处置是升级/回滚该包)。
|
|
42
|
+
try {
|
|
43
|
+
if (isFrameworkOwnedPackage(pkgDir, profileDir) || entry.moduleName.startsWith('@deepseek-ai/')) kind = 'framework'
|
|
44
|
+
} catch {}
|
|
45
|
+
roots.push({ root: pkgDir, kind, moduleName: entry.moduleName })
|
|
46
|
+
}
|
|
47
|
+
return roots
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** 目标版本:请求体优先,缺省用当前已装版本(预检当前版本同样能发现历史遗留的旧形状)。 */
|
|
51
|
+
function resolveTargetVersion(rc, body) {
|
|
52
|
+
if (typeof body?.targetVersion === 'string' && body.targetVersion.trim() !== '') return body.targetVersion.trim()
|
|
53
|
+
try { return currentFrameworkVersion(rc.ctx) } catch { return null }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** 当前已装版本(用于算「目标版本新增了哪条迁移边」——这才是契约变更的信号)。 */
|
|
57
|
+
function resolveCurrentVersion(rc) {
|
|
58
|
+
try { return currentFrameworkVersion(rc.ctx) } catch { return null }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** 测试/离线模式:CI 里 DSH_TEST_SKIP_NETWORK=1,跳过 registry 拉取(扫描仍照跑)。 */
|
|
62
|
+
function networkAllowed() {
|
|
63
|
+
return process.env.DSH_TEST_SKIP_NETWORK !== '1'
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function routeFrameworkPreflight(req, res, rc) {
|
|
67
|
+
const body = rc.body ?? {}
|
|
68
|
+
const profileDir = profileDirOf(rc.ctx)
|
|
69
|
+
const targetVersion = resolveTargetVersion(rc, body)
|
|
70
|
+
if (targetVersion === null) { sendError(res, 400, '无法确定目标框架版本(请在请求里带 targetVersion)'); return }
|
|
71
|
+
|
|
72
|
+
const roots = preflightRoots(rc.ctx, profileDir)
|
|
73
|
+
const targets = collectProducerTargets(roots)
|
|
74
|
+
|
|
75
|
+
let contract = null
|
|
76
|
+
let contractError = null
|
|
77
|
+
let contractWarnings = []
|
|
78
|
+
if (!networkAllowed()) {
|
|
79
|
+
contractError = '已跳过网络(DSH_TEST_SKIP_NETWORK=1):仅使用内置规则扫描'
|
|
80
|
+
} else {
|
|
81
|
+
const discovered = await discoverFormatContract({
|
|
82
|
+
targetVersion,
|
|
83
|
+
currentVersion: resolveCurrentVersion(rc),
|
|
84
|
+
registry: REGISTRY,
|
|
85
|
+
fetchJson: (url) => fetchJsonUrl(url, 20000),
|
|
86
|
+
fetchText: (url) => curlText(url, 12000),
|
|
87
|
+
})
|
|
88
|
+
contract = discovered.contract
|
|
89
|
+
contractError = discovered.error
|
|
90
|
+
contractWarnings = discovered.warnings ?? []
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const rules = contract?.rules ?? { producerKindRequired: false, forbiddenKinds: ['plugin'], pluginPrefix: 'plugin:', renames: {} }
|
|
94
|
+
const scan = scanProducerFiles({ targets, rules, targetVersion })
|
|
95
|
+
|
|
96
|
+
sendJson(res, 200, {
|
|
97
|
+
ok: true,
|
|
98
|
+
targetVersion,
|
|
99
|
+
contract,
|
|
100
|
+
contractError,
|
|
101
|
+
contractWarnings,
|
|
102
|
+
contractSummary: contract === null ? null : summarizeContract(contract),
|
|
103
|
+
sessionFormatVersion: contract?.sessionFormatVersion ?? null,
|
|
104
|
+
roots: roots.map((r) => ({ root: r.root, kind: r.kind, moduleName: r.moduleName ?? null })),
|
|
105
|
+
scan,
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async function routeFrameworkPreflightPatch(req, res, rc) {
|
|
110
|
+
const body = rc.body ?? {}
|
|
111
|
+
const mode = body.mode === 'apply' ? 'apply' : 'plan'
|
|
112
|
+
const profileDir = profileDirOf(rc.ctx)
|
|
113
|
+
const targetVersion = resolveTargetVersion(rc, body)
|
|
114
|
+
if (targetVersion === null) { sendError(res, 400, '无法确定目标框架版本(请在请求里带 targetVersion)'); return }
|
|
115
|
+
|
|
116
|
+
const roots = preflightRoots(rc.ctx, profileDir)
|
|
117
|
+
const allTargets = collectProducerTargets(roots)
|
|
118
|
+
// 允许名单:请求可收窄到指定文件(dry-run 后前端只提交它看到的那几条),否则用全量。
|
|
119
|
+
const picked = Array.isArray(body.files) && body.files.length > 0
|
|
120
|
+
? allTargets.filter((t) => body.files.some((f) => String(f).toLowerCase() === t.file.toLowerCase()))
|
|
121
|
+
: allTargets
|
|
122
|
+
|
|
123
|
+
let rules = { producerKindRequired: false, forbiddenKinds: ['plugin'], pluginPrefix: 'plugin:', renames: {} }
|
|
124
|
+
if (networkAllowed()) {
|
|
125
|
+
try {
|
|
126
|
+
const discovered = await discoverFormatContract({
|
|
127
|
+
targetVersion,
|
|
128
|
+
currentVersion: resolveCurrentVersion(rc),
|
|
129
|
+
registry: REGISTRY,
|
|
130
|
+
fetchJson: (url) => fetchJsonUrl(url, 20000),
|
|
131
|
+
fetchText: (url) => curlText(url, 12000),
|
|
132
|
+
})
|
|
133
|
+
if (discovered.contract !== null) rules = discovered.contract.rules
|
|
134
|
+
} catch {}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const result = applyFormatPatch({ targets: picked, rules, targetVersion, dryRun: mode !== 'apply' })
|
|
138
|
+
// 应用后复扫(同一批目标),给前端一个「还剩几条」的确定答案
|
|
139
|
+
const remaining = scanProducerFiles({ targets: picked, rules, targetVersion })
|
|
140
|
+
|
|
141
|
+
sendJson(res, 200, {
|
|
142
|
+
ok: true,
|
|
143
|
+
mode,
|
|
144
|
+
targetVersion,
|
|
145
|
+
applied: mode === 'apply',
|
|
146
|
+
changes: result.changes,
|
|
147
|
+
backups: result.backups,
|
|
148
|
+
skipped: result.skipped,
|
|
149
|
+
unresolved: result.unresolved,
|
|
150
|
+
remaining,
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export { routeFrameworkPreflight, routeFrameworkPreflightPatch, preflightRoots, resolveTargetVersion, resolveCurrentVersion }
|