@marsken/dsh-studio 0.1.19 → 0.1.21
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/AGENTS.md +9 -1
- package/README.md +2 -2
- package/client.js +41 -41
- package/dist/client.js +41 -41
- package/docs/compatibility.md +1 -1
- package/docs/publish.md +3 -0
- package/package.json +1 -1
- package/src/host/discovery.js +16 -0
- package/src/host/executor.js +34 -0
- package/src/host/routes/requirements.js +4 -2
package/docs/compatibility.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
| 项 | 值 |
|
|
8
8
|
| --- | --- |
|
|
9
|
-
| dsh-studio | `package.json` `version: 0.1.
|
|
9
|
+
| dsh-studio | `package.json` `version: 0.1.21` |
|
|
10
10
|
| DeepSeek Harness | `0.2.2-rc.1`(`dsh --version`) |
|
|
11
11
|
| Node | `v24.22.2`(Linux 目标机);本机 Windows `v24.19.0` |
|
|
12
12
|
| 目标系统 | Ubuntu 24.04,`dsh web` 监听 `18080`,nginx `:80` 反代并注入 `dsh-auth-*` cookie |
|
package/docs/publish.md
CHANGED
|
@@ -127,6 +127,9 @@ token 只写进临时 npmrc(放在仓库外或 `tmp/` 且不提交),发完
|
|
|
127
127
|
| --- | --- | --- |
|
|
128
128
|
| `0.1.0` | 2026-11-13 | 首个公开版:看板 / 需求 / 用例回归 / 效能 / 设计评审四期 |
|
|
129
129
|
| `0.1.1` | 2026-11-13 | 补三张 README 截图(npm 页可看图);默认值与文档去掉公司内网信息 |
|
|
130
|
+
| `0.1.21` | 2026-11-15 | 需求基线可回滚(版本 +1、签字作废、留痕) |
|
|
131
|
+
| `0.1.20` | 2026-11-15 | 拆卡时提示「有后端但功能点没覆盖后端」 |
|
|
132
|
+
| `0.1.19` | 2026-11-15 | 需求澄清三问 + 拆卡门禁;修补答保存不上的白名单漏字段 |
|
|
130
133
|
| `0.1.17` | 2026-11-15 | 截图补到 10 张,且有脚本可重跑 |
|
|
131
134
|
| `0.1.16` | 2026-11-15 | quickstart 命令修正 + GitLab 打桩验证配方 |
|
|
132
135
|
| `0.1.15` | 2026-11-15 | 清掉三处过期的「已知限制」 |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@marsken/dsh-studio",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "DSH Studio: role-based multi-agent workspace (product / architect / developer / QA) with a live work board, GitLab + Feishu connection settings, all configurable from the web GUI.",
|
|
6
6
|
"main": "index.js",
|
package/src/host/discovery.js
CHANGED
|
@@ -16,6 +16,22 @@ export function sanitizeDiscovery(raw) {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
const BACKEND_HINT = /接口|api|数据库|数据表|建表|后端|服务端|鉴权|sqlite|postgres|持久化|存储/i
|
|
20
|
+
const BACKEND_YES = /^(有|yes|是|需要|要)/i
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 说了「有服务端」,功能点里却没有一条跟后端有关 —— 大概率又要只交付一半。
|
|
24
|
+
* 只提示、不拦:有的需求后端在别的仓库或别的需求里,硬拦会误伤。
|
|
25
|
+
*/
|
|
26
|
+
export function backendCoverageWarning(requirement) {
|
|
27
|
+
const answer = String(requirement?.discovery?.server ?? '').trim()
|
|
28
|
+
if (answer === '' || BACKEND_YES.test(answer) !== true) return null
|
|
29
|
+
const points = Array.isArray(requirement?.points) ? requirement.points : []
|
|
30
|
+
const hit = points.some(point => BACKEND_HINT.test(String(point?.title ?? '') + ' ' + String(point?.description ?? '')))
|
|
31
|
+
if (hit) return null
|
|
32
|
+
return '澄清里说有服务端,但功能点没有一条讲接口 / 数据表 / 鉴权:后端在哪一块交付?'
|
|
33
|
+
}
|
|
34
|
+
|
|
19
35
|
/** 还缺哪几项澄清;空了才允许拆卡。 */
|
|
20
36
|
export function discoveryGaps(requirement) {
|
|
21
37
|
const discovery = requirement?.discovery ?? {}
|
package/src/host/executor.js
CHANGED
|
@@ -1245,6 +1245,16 @@ export async function syncRequirementArtifacts(store, requirementId) {
|
|
|
1245
1245
|
return report
|
|
1246
1246
|
}
|
|
1247
1247
|
|
|
1248
|
+
/** 回滚时给文档版本号 +1:v1.0 → v1.1;已经是 -rN 的就继续 +1。 */
|
|
1249
|
+
function bumpDocVersion(version) {
|
|
1250
|
+
const text = String(version ?? '').trim()
|
|
1251
|
+
const plain = /^v(\d+)\.(\d+)$/.exec(text)
|
|
1252
|
+
if (plain !== null) return 'v' + plain[1] + '.' + (Number(plain[2]) + 1)
|
|
1253
|
+
const rolled = /-r(\d+)$/.exec(text)
|
|
1254
|
+
if (rolled !== null) return text.replace(/-r\d+$/, '-r' + (Number(rolled[1]) + 1))
|
|
1255
|
+
return (text === '' ? 'v1.0' : text) + '-r1'
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1248
1258
|
/** 需求文档的增删改与「评审通过、冻结为基线」。 */
|
|
1249
1259
|
export async function mutateReqDoc(store, body) {
|
|
1250
1260
|
const requirementId = String(body.id ?? '')
|
|
@@ -1281,6 +1291,30 @@ export async function mutateReqDoc(store, body) {
|
|
|
1281
1291
|
by: String(body.by ?? '人').slice(0, 40),
|
|
1282
1292
|
})
|
|
1283
1293
|
if (requirement.status === 'draft') requirement.status = 'active'
|
|
1294
|
+
} else if (action === 'rollback') {
|
|
1295
|
+
// 回到基线正文:版本号 +1、签字作废、留一条历史——回滚是实质变更,不能悄悄改。
|
|
1296
|
+
const baseline = requirement.baseline
|
|
1297
|
+
if (baseline === null || baseline === undefined) throw new Error('这条需求还没有基线,先挑一份文档「设为基线」再回滚')
|
|
1298
|
+
const target = requirement.docs.find(item => item.id === baseline.docId) ?? requirement.docs[0]
|
|
1299
|
+
if (target === undefined) throw new Error('基线对应的文档已经删了,没法回滚')
|
|
1300
|
+
const by = String(body.by ?? '人').trim().slice(0, 40) || '人'
|
|
1301
|
+
const previousVersion = String(target.version ?? '')
|
|
1302
|
+
target.content = baseline.content
|
|
1303
|
+
target.version = bumpDocVersion(target.version)
|
|
1304
|
+
target.status = 'baseline'
|
|
1305
|
+
target.at = Date.now()
|
|
1306
|
+
for (const doc of requirement.docs) if (doc.id !== target.id && doc.status === 'baseline') doc.status = 'draft'
|
|
1307
|
+
requirement.baseline = sanitizeBaseline({ ...baseline, version: target.version, content: target.content, at: Date.now(), by })
|
|
1308
|
+
const hadSignoff = requirement.signoff !== null && requirement.signoff !== undefined
|
|
1309
|
+
requirement.signoff = null
|
|
1310
|
+
requirement.history = [...(requirement.history ?? []), {
|
|
1311
|
+
at: Date.now(),
|
|
1312
|
+
by,
|
|
1313
|
+
field: 'PRD 回滚',
|
|
1314
|
+
from: previousVersion,
|
|
1315
|
+
to: baseline.version,
|
|
1316
|
+
note: hadSignoff ? '回滚到基线,原验收签字作废' : '回滚到基线',
|
|
1317
|
+
}]
|
|
1284
1318
|
} else if (action === 'clear-baseline') {
|
|
1285
1319
|
requirement.baseline = null
|
|
1286
1320
|
for (const doc of requirement.docs) if (doc.status === 'baseline') doc.status = 'review'
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
sanitizeRequirementPool,
|
|
8
8
|
text,
|
|
9
9
|
} from '../domain.js'
|
|
10
|
-
import { discoveryGaps } from '../discovery.js'
|
|
10
|
+
import { backendCoverageWarning, discoveryGaps } from '../discovery.js'
|
|
11
11
|
import { casesOfTasks, impactSummary } from '../impact.js'
|
|
12
12
|
import {
|
|
13
13
|
ensureReqFolder,
|
|
@@ -219,7 +219,9 @@ export async function handleRequirementRoute({ method, route, req, res, store, u
|
|
|
219
219
|
})
|
|
220
220
|
created.push(task)
|
|
221
221
|
}
|
|
222
|
-
|
|
222
|
+
// 说了有后端却没有后端功能点:给个提示,不拦(后端可能确实在别的需求里)
|
|
223
|
+
const warning = backendCoverageWarning(requirement)
|
|
224
|
+
host.sendJson(res, 200, { ok: true, created, warnings: warning === null ? [] : [warning], state: host.publicState(store) })
|
|
223
225
|
return true
|
|
224
226
|
}
|
|
225
227
|
if (method === 'POST' && route === '/requirement/pool') {
|