@godv61/dsh-task-engine 0.25.0 → 0.26.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/.acceptance.mjs +150 -150
- package/.assessment-batch1.mjs +20 -20
- package/.enforce-test.mjs +138 -138
- package/.evidence-test.mjs +118 -119
- package/.filter-test.mjs +92 -92
- package/.hook-test.mjs +195 -195
- package/.p0-test.mjs +59 -59
- package/.preset-test.mjs +160 -160
- package/.revision-test.mjs +30 -16
- package/.roundtrip-test.mjs +178 -63
- package/.workflow-test.mjs +86 -0
- package/README.md +7 -7
- package/cordis.patch.yml +10 -10
- package/defaults/eng.json +70 -22
- package/docs/BRIEF-FOR-REVIEW.md +162 -162
- package/docs/CHANGELOG.md +12 -0
- package/docs/README.md +40 -40
- package/docs/configuration.md +12 -9
- package/docs/development.md +1 -1
- package/docs/faq.md +4 -4
- package/docs/listing/godv61__dsh-task-engine.yml +5 -5
- package/docs/listing/submission.md +83 -83
- package/docs/manual.html +31 -26
- package/docs/releases/0.23.2.md +21 -21
- package/docs/roadmap.md +34 -34
- package/docs/testing/0.23.2/R02/344/270/232/345/212/241/346/265/213/350/257/225/346/230/216/347/273/206.md +56 -56
- package/docs/testing/0.23.2/R03/344/270/232/345/212/241/346/265/213/350/257/225/346/230/216/347/273/206.md +38 -38
- package/docs/testing/0.23.2//346/265/213/350/257/225/346/212/245/345/221/212.md +65 -65
- package/hooks/commit-msg +70 -1
- package/lib/client.js +825 -570
- package/lib/client.js.map +3 -3
- package/lib/controller.d.ts +2 -1
- package/lib/controller.js +6 -3
- package/lib/controller.js.map +1 -1
- package/lib/dev-task.js +79 -11
- package/lib/dev-task.js.map +1 -1
- package/lib/engine.d.ts +15 -0
- package/lib/engine.js +29 -5
- package/lib/engine.js.map +1 -1
- package/lib/hook.js +3 -0
- package/lib/hook.js.map +1 -1
- package/lib/skill-audit.js +3 -3
- package/lib/skill-audit.js.map +1 -1
- package/lib/workflows.d.ts +4 -1
- package/lib/workflows.js +90 -2
- package/lib/workflows.js.map +1 -1
- package/package.json +1 -1
- package/preset/agent.cordis.yml +21 -21
- package/preset/enable.mjs +87 -87
- package/preset/persona.md +4 -4
- package/preset/preset.yml +1 -1
- package/rules/coding-conventions.md +6 -6
- package/rules/commit-conventions.md +6 -6
- package/rules/security-redlines.md +5 -5
- package/scripts/verify-dsh-compat.mjs +144 -144
- package/skills/code-verify/SKILL.md +3 -3
|
@@ -1,145 +1,145 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DSH codec-contract compatibility check.
|
|
3
|
-
*
|
|
4
|
-
* The plugin's Typert Remote contribution must satisfy whichever strict-codec
|
|
5
|
-
* contract the installed DSH expects. DSH 0.1.6-alpha.2 replaced the
|
|
6
|
-
* materialized `schema` field with a lazy `create: () => TypertSchema` factory
|
|
7
|
-
* and rejects the old shape at plugin load, which took the whole contribution
|
|
8
|
-
* down at boot — a failure the unit tests could not see, because they never
|
|
9
|
-
* load the descriptors through a real registry.
|
|
10
|
-
*
|
|
11
|
-
* npm semver cannot wildcard prereleases, so the peer range enumerates them and
|
|
12
|
-
* a new DSH alpha silently falls outside it; pnpm only warns at install time.
|
|
13
|
-
* This check runs against a real DSH checkout, where the contract actually
|
|
14
|
-
* lives, and fails loudly when the two drift apart again.
|
|
15
|
-
*
|
|
16
|
-
* Run: `node scripts/verify-dsh-compat.mjs [path-to-dsh-checkout]`
|
|
17
|
-
* @module dsh-task-engine/scripts/verify-dsh-compat
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
|
-
import { existsSync, readFileSync } from 'node:fs'
|
|
21
|
-
import { join } from 'node:path'
|
|
22
|
-
import { fileURLToPath } from 'node:url'
|
|
23
|
-
|
|
24
|
-
const DEFAULT_DSH_ROOT = 'D:/dsharness/deepseek-harness'
|
|
25
|
-
|
|
26
|
-
const problems = []
|
|
27
|
-
function check(name, ok, detail = '') {
|
|
28
|
-
console.log(`${ok ? 'ok ' : 'FAIL'} ${name}${detail === '' ? '' : `: ${detail}`}`)
|
|
29
|
-
if (!ok) problems.push(name)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** Locate the typert protocol package inside a DSH checkout. */
|
|
33
|
-
function protocolDir(root) {
|
|
34
|
-
const candidates = [
|
|
35
|
-
join(root, 'packages', 'typert', 'protocol'),
|
|
36
|
-
join(root, 'node_modules', '@deepseek-ai', 'dsh-typert-protocol'),
|
|
37
|
-
]
|
|
38
|
-
return candidates.find(dir => existsSync(join(dir, 'package.json')))
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const dshRoot = process.argv[2] ?? DEFAULT_DSH_ROOT
|
|
42
|
-
console.log(`DSH checkout: ${dshRoot}`)
|
|
43
|
-
|
|
44
|
-
if (!existsSync(dshRoot)) {
|
|
45
|
-
// Absent checkout is not a failure: this script is advisory outside CI.
|
|
46
|
-
console.log('ok (skipped) no DSH checkout at that path')
|
|
47
|
-
process.exit(0)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const dir = protocolDir(dshRoot)
|
|
51
|
-
if (dir === undefined) {
|
|
52
|
-
check('locate the typert protocol package', false, 'not found under the DSH checkout')
|
|
53
|
-
process.exit(1)
|
|
54
|
-
}
|
|
55
|
-
const protocol = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'))
|
|
56
|
-
console.log(` typert protocol version: ${protocol.version}`)
|
|
57
|
-
|
|
58
|
-
// 1. Which contract does this DSH expect? Read the type, not a guess.
|
|
59
|
-
const typesPath = [
|
|
60
|
-
join(dir, 'src', 'types.ts'),
|
|
61
|
-
join(dir, 'lib', 'types', 'types.d.ts'),
|
|
62
|
-
].find(path => existsSync(path))
|
|
63
|
-
const typesText = typesPath === undefined ? '' : readFileSync(typesPath, 'utf8')
|
|
64
|
-
const wantsCreate = /readonly create: \(\) => TypertSchema/u.test(typesText)
|
|
65
|
-
const wantsSchema = /readonly schema: TypertSchema/u.test(typesText)
|
|
66
|
-
console.log(` contract: ${wantsCreate ? 'create() factory' : wantsSchema ? 'schema field' : 'unknown'}`)
|
|
67
|
-
|
|
68
|
-
// 2. Our descriptors must satisfy it. Import the built contribution and inspect
|
|
69
|
-
// every strict codec exactly as the DSH registry would.
|
|
70
|
-
const pluginRoot = fileURLToPath(new URL('..', import.meta.url))
|
|
71
|
-
const clientBundle = join(pluginRoot, 'lib', 'client.js')
|
|
72
|
-
if (!existsSync(clientBundle)) {
|
|
73
|
-
check('built client bundle exists', false, 'run `npm run build` first')
|
|
74
|
-
process.exit(1)
|
|
75
|
-
}
|
|
76
|
-
const bundleText = readFileSync(clientBundle, 'utf8')
|
|
77
|
-
const strictCodecs = (bundleText.match(/mode:\s*"strict"/gu) ?? []).length
|
|
78
|
-
const withCreate = (bundleText.match(/create:\s*\(\)\s*=>/gu) ?? []).length
|
|
79
|
-
const withSchema = (bundleText.match(/schema:/gu) ?? []).length
|
|
80
|
-
|
|
81
|
-
check('the bundle carries strict codecs', strictCodecs > 0, `${strictCodecs} found`)
|
|
82
|
-
if (wantsCreate) {
|
|
83
|
-
check('every strict codec provides create()', withCreate >= strictCodecs,
|
|
84
|
-
`${withCreate} of ${strictCodecs}`)
|
|
85
|
-
}
|
|
86
|
-
if (wantsSchema) {
|
|
87
|
-
check('every strict codec provides schema', withSchema >= strictCodecs,
|
|
88
|
-
`${withSchema} of ${strictCodecs}`)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// 3. The peer range must actually admit the installed DSH version, because npm
|
|
92
|
-
// semver will not match a prerelease the range does not name. Implemented
|
|
93
|
-
// here rather than via the `semver` package: that is a devDependency, so a
|
|
94
|
-
// consumer running this script from the installed tarball has no copy, and
|
|
95
|
-
// the whole point of this check is to run against whatever DSH is present.
|
|
96
|
-
const pkg = JSON.parse(readFileSync(join(pluginRoot, 'package.json'), 'utf8'))
|
|
97
|
-
const range = pkg.peerDependencies['@deepseek-ai/dsh-typert-protocol'] ?? ''
|
|
98
|
-
check(`peer range admits DSH ${protocol.version}`, rangeAdmits(range, protocol.version), range)
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Whether one of a `||`-joined range's comparators admits `version`.
|
|
102
|
-
*
|
|
103
|
-
* npm semver matches a prerelease only when the comparator names a prerelease
|
|
104
|
-
* on the SAME major.minor.patch, which is why enumerating versions is the only
|
|
105
|
-
* way to cover a DSH alpha. This mirrors that rule for the caret and exact
|
|
106
|
-
* forms the manifest actually uses; it is deliberately conservative, and an
|
|
107
|
-
* unrecognized comparator reports `false` so the check fails loudly rather than
|
|
108
|
-
* passing by accident.
|
|
109
|
-
* @param range - the peer range expression.
|
|
110
|
-
* @param version - the installed DSH version to test.
|
|
111
|
-
* @returns true when the range admits the version.
|
|
112
|
-
*/
|
|
113
|
-
function rangeAdmits(range, version) {
|
|
114
|
-
const parse = text => {
|
|
115
|
-
const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/u.exec(text.trim())
|
|
116
|
-
return match === null
|
|
117
|
-
? undefined
|
|
118
|
-
: { major: +match[1], minor: +match[2], patch: +match[3], pre: match[4] }
|
|
119
|
-
}
|
|
120
|
-
const target = parse(version)
|
|
121
|
-
if (target === undefined) return false
|
|
122
|
-
for (const part of range.split('||').map(text => text.trim()).filter(Boolean)) {
|
|
123
|
-
const caret = /^\^(.+)$/u.exec(part)
|
|
124
|
-
const lower = parse(caret === null ? part : caret[1])
|
|
125
|
-
if (lower === undefined) continue
|
|
126
|
-
// Same prerelease tuple, or a plain release on the same caret line.
|
|
127
|
-
const sameTuple = target.major === lower.major
|
|
128
|
-
&& target.minor === lower.minor
|
|
129
|
-
&& target.patch === lower.patch
|
|
130
|
-
if (lower.pre !== undefined) {
|
|
131
|
-
if (sameTuple) return true
|
|
132
|
-
} else if (target.pre === undefined && target.major === lower.major) {
|
|
133
|
-
if (caret === null ? sameTuple : target.minor >= lower.minor) return true
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return false
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (problems.length > 0) {
|
|
140
|
-
console.error(`\n${problems.length} DSH compatibility problem(s)`)
|
|
141
|
-
console.error('A new DSH alpha likely changed the Typert contract. Update src/client/remote.ts')
|
|
142
|
-
console.error('and add the version to peerDependencies before releasing.')
|
|
143
|
-
process.exit(1)
|
|
144
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* DSH codec-contract compatibility check.
|
|
3
|
+
*
|
|
4
|
+
* The plugin's Typert Remote contribution must satisfy whichever strict-codec
|
|
5
|
+
* contract the installed DSH expects. DSH 0.1.6-alpha.2 replaced the
|
|
6
|
+
* materialized `schema` field with a lazy `create: () => TypertSchema` factory
|
|
7
|
+
* and rejects the old shape at plugin load, which took the whole contribution
|
|
8
|
+
* down at boot — a failure the unit tests could not see, because they never
|
|
9
|
+
* load the descriptors through a real registry.
|
|
10
|
+
*
|
|
11
|
+
* npm semver cannot wildcard prereleases, so the peer range enumerates them and
|
|
12
|
+
* a new DSH alpha silently falls outside it; pnpm only warns at install time.
|
|
13
|
+
* This check runs against a real DSH checkout, where the contract actually
|
|
14
|
+
* lives, and fails loudly when the two drift apart again.
|
|
15
|
+
*
|
|
16
|
+
* Run: `node scripts/verify-dsh-compat.mjs [path-to-dsh-checkout]`
|
|
17
|
+
* @module dsh-task-engine/scripts/verify-dsh-compat
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
21
|
+
import { join } from 'node:path'
|
|
22
|
+
import { fileURLToPath } from 'node:url'
|
|
23
|
+
|
|
24
|
+
const DEFAULT_DSH_ROOT = 'D:/dsharness/deepseek-harness'
|
|
25
|
+
|
|
26
|
+
const problems = []
|
|
27
|
+
function check(name, ok, detail = '') {
|
|
28
|
+
console.log(`${ok ? 'ok ' : 'FAIL'} ${name}${detail === '' ? '' : `: ${detail}`}`)
|
|
29
|
+
if (!ok) problems.push(name)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Locate the typert protocol package inside a DSH checkout. */
|
|
33
|
+
function protocolDir(root) {
|
|
34
|
+
const candidates = [
|
|
35
|
+
join(root, 'packages', 'typert', 'protocol'),
|
|
36
|
+
join(root, 'node_modules', '@deepseek-ai', 'dsh-typert-protocol'),
|
|
37
|
+
]
|
|
38
|
+
return candidates.find(dir => existsSync(join(dir, 'package.json')))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const dshRoot = process.argv[2] ?? DEFAULT_DSH_ROOT
|
|
42
|
+
console.log(`DSH checkout: ${dshRoot}`)
|
|
43
|
+
|
|
44
|
+
if (!existsSync(dshRoot)) {
|
|
45
|
+
// Absent checkout is not a failure: this script is advisory outside CI.
|
|
46
|
+
console.log('ok (skipped) no DSH checkout at that path')
|
|
47
|
+
process.exit(0)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const dir = protocolDir(dshRoot)
|
|
51
|
+
if (dir === undefined) {
|
|
52
|
+
check('locate the typert protocol package', false, 'not found under the DSH checkout')
|
|
53
|
+
process.exit(1)
|
|
54
|
+
}
|
|
55
|
+
const protocol = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'))
|
|
56
|
+
console.log(` typert protocol version: ${protocol.version}`)
|
|
57
|
+
|
|
58
|
+
// 1. Which contract does this DSH expect? Read the type, not a guess.
|
|
59
|
+
const typesPath = [
|
|
60
|
+
join(dir, 'src', 'types.ts'),
|
|
61
|
+
join(dir, 'lib', 'types', 'types.d.ts'),
|
|
62
|
+
].find(path => existsSync(path))
|
|
63
|
+
const typesText = typesPath === undefined ? '' : readFileSync(typesPath, 'utf8')
|
|
64
|
+
const wantsCreate = /readonly create: \(\) => TypertSchema/u.test(typesText)
|
|
65
|
+
const wantsSchema = /readonly schema: TypertSchema/u.test(typesText)
|
|
66
|
+
console.log(` contract: ${wantsCreate ? 'create() factory' : wantsSchema ? 'schema field' : 'unknown'}`)
|
|
67
|
+
|
|
68
|
+
// 2. Our descriptors must satisfy it. Import the built contribution and inspect
|
|
69
|
+
// every strict codec exactly as the DSH registry would.
|
|
70
|
+
const pluginRoot = fileURLToPath(new URL('..', import.meta.url))
|
|
71
|
+
const clientBundle = join(pluginRoot, 'lib', 'client.js')
|
|
72
|
+
if (!existsSync(clientBundle)) {
|
|
73
|
+
check('built client bundle exists', false, 'run `npm run build` first')
|
|
74
|
+
process.exit(1)
|
|
75
|
+
}
|
|
76
|
+
const bundleText = readFileSync(clientBundle, 'utf8')
|
|
77
|
+
const strictCodecs = (bundleText.match(/mode:\s*"strict"/gu) ?? []).length
|
|
78
|
+
const withCreate = (bundleText.match(/create:\s*\(\)\s*=>/gu) ?? []).length
|
|
79
|
+
const withSchema = (bundleText.match(/schema:/gu) ?? []).length
|
|
80
|
+
|
|
81
|
+
check('the bundle carries strict codecs', strictCodecs > 0, `${strictCodecs} found`)
|
|
82
|
+
if (wantsCreate) {
|
|
83
|
+
check('every strict codec provides create()', withCreate >= strictCodecs,
|
|
84
|
+
`${withCreate} of ${strictCodecs}`)
|
|
85
|
+
}
|
|
86
|
+
if (wantsSchema) {
|
|
87
|
+
check('every strict codec provides schema', withSchema >= strictCodecs,
|
|
88
|
+
`${withSchema} of ${strictCodecs}`)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 3. The peer range must actually admit the installed DSH version, because npm
|
|
92
|
+
// semver will not match a prerelease the range does not name. Implemented
|
|
93
|
+
// here rather than via the `semver` package: that is a devDependency, so a
|
|
94
|
+
// consumer running this script from the installed tarball has no copy, and
|
|
95
|
+
// the whole point of this check is to run against whatever DSH is present.
|
|
96
|
+
const pkg = JSON.parse(readFileSync(join(pluginRoot, 'package.json'), 'utf8'))
|
|
97
|
+
const range = pkg.peerDependencies['@deepseek-ai/dsh-typert-protocol'] ?? ''
|
|
98
|
+
check(`peer range admits DSH ${protocol.version}`, rangeAdmits(range, protocol.version), range)
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Whether one of a `||`-joined range's comparators admits `version`.
|
|
102
|
+
*
|
|
103
|
+
* npm semver matches a prerelease only when the comparator names a prerelease
|
|
104
|
+
* on the SAME major.minor.patch, which is why enumerating versions is the only
|
|
105
|
+
* way to cover a DSH alpha. This mirrors that rule for the caret and exact
|
|
106
|
+
* forms the manifest actually uses; it is deliberately conservative, and an
|
|
107
|
+
* unrecognized comparator reports `false` so the check fails loudly rather than
|
|
108
|
+
* passing by accident.
|
|
109
|
+
* @param range - the peer range expression.
|
|
110
|
+
* @param version - the installed DSH version to test.
|
|
111
|
+
* @returns true when the range admits the version.
|
|
112
|
+
*/
|
|
113
|
+
function rangeAdmits(range, version) {
|
|
114
|
+
const parse = text => {
|
|
115
|
+
const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/u.exec(text.trim())
|
|
116
|
+
return match === null
|
|
117
|
+
? undefined
|
|
118
|
+
: { major: +match[1], minor: +match[2], patch: +match[3], pre: match[4] }
|
|
119
|
+
}
|
|
120
|
+
const target = parse(version)
|
|
121
|
+
if (target === undefined) return false
|
|
122
|
+
for (const part of range.split('||').map(text => text.trim()).filter(Boolean)) {
|
|
123
|
+
const caret = /^\^(.+)$/u.exec(part)
|
|
124
|
+
const lower = parse(caret === null ? part : caret[1])
|
|
125
|
+
if (lower === undefined) continue
|
|
126
|
+
// Same prerelease tuple, or a plain release on the same caret line.
|
|
127
|
+
const sameTuple = target.major === lower.major
|
|
128
|
+
&& target.minor === lower.minor
|
|
129
|
+
&& target.patch === lower.patch
|
|
130
|
+
if (lower.pre !== undefined) {
|
|
131
|
+
if (sameTuple) return true
|
|
132
|
+
} else if (target.pre === undefined && target.major === lower.major) {
|
|
133
|
+
if (caret === null ? sameTuple : target.minor >= lower.minor) return true
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return false
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (problems.length > 0) {
|
|
140
|
+
console.error(`\n${problems.length} DSH compatibility problem(s)`)
|
|
141
|
+
console.error('A new DSH alpha likely changed the Typert contract. Update src/client/remote.ts')
|
|
142
|
+
console.error('and add the version to peerDependencies before releasing.')
|
|
143
|
+
process.exit(1)
|
|
144
|
+
}
|
|
145
145
|
console.log('\nDSH compatibility verified')
|
|
@@ -11,9 +11,9 @@ description: 交付验证节点:执行目标测试、编译与契约检查,
|
|
|
11
11
|
4. 文件或范围变更会使旧验证回执失效,审核修复后可在当前阶段重跑 verify。沙箱拒绝属于环境阻塞,不能改跑不相关的简单命令来冒充原验收通过。
|
|
12
12
|
5. 环境受阻时如实记"未编译/未联调";high_risk 核心行为无法验证时不得通过。
|
|
13
13
|
|
|
14
|
-
权限或沙箱拒绝后,不得切换等价命令、修改 ACL 或安全策略来规避限制。确认错误来自宿主权限后使用 Harness 正式审批;审批不可用时报告失败路径和所需授权,等待处理,不把工具访问限制推断为服务不可达。
|
|
15
|
-
|
|
16
|
-
`verify` / `skill_result` 的验证命令因沙箱受阻时,保持原命令,增加 `sandbox_permissions: "danger-full-access"` 和具体 `justification` 申请单次重试。批准发生在命令执行之前,只对本次调用生效;回执中的实际模式与退出码才是本次结果,不能引用之前 shell 调用通过的结果替代。保存完整测试输出后从已有日志提取用例,不为截取不同摘要重复跑已通过测试。
|
|
14
|
+
权限或沙箱拒绝后,不得切换等价命令、修改 ACL 或安全策略来规避限制。确认错误来自宿主权限后使用 Harness 正式审批;审批不可用时报告失败路径和所需授权,等待处理,不把工具访问限制推断为服务不可达。
|
|
15
|
+
|
|
16
|
+
`verify` / `skill_result` 的验证命令因沙箱受阻时,保持原命令,增加 `sandbox_permissions: "danger-full-access"` 和具体 `justification` 申请单次重试。批准发生在命令执行之前,只对本次调用生效;回执中的实际模式与退出码才是本次结果,不能引用之前 shell 调用通过的结果替代。保存完整测试输出后从已有日志提取用例,不为截取不同摘要重复跑已通过测试。
|
|
17
17
|
|
|
18
18
|
验证失败不得 advance。
|
|
19
19
|
|