@godv61/dsh-task-engine 0.27.1 → 0.29.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.
Files changed (63) hide show
  1. package/.acceptance.mjs +11 -11
  2. package/.adaptive-test.mjs +189 -0
  3. package/.assessment-batch1.mjs +14 -14
  4. package/.codex-project-test.mjs +80 -80
  5. package/.enforce-test.mjs +12 -12
  6. package/.evidence-test.mjs +8 -8
  7. package/.filter-test.mjs +6 -6
  8. package/.freeze-test.mjs +44 -44
  9. package/.hook-test.mjs +19 -2
  10. package/.p0-test.mjs +21 -21
  11. package/.preset-test.mjs +11 -1
  12. package/.revision-test.mjs +16 -16
  13. package/.roundtrip-test.mjs +247 -247
  14. package/.workflow-test.mjs +122 -120
  15. package/README.md +33 -27
  16. package/cordis.patch.yml +158 -9
  17. package/docs/CHANGELOG.md +44 -30
  18. package/docs/README.md +6 -5
  19. package/docs/adaptive-workflows.md +72 -0
  20. package/docs/configuration.md +25 -25
  21. package/docs/development.md +1 -1
  22. package/docs/faq.md +14 -6
  23. package/docs/getting-started.md +8 -5
  24. package/docs/manual-legacy.html +380 -0
  25. package/docs/manual.html +124 -378
  26. package/docs/resource-install.md +5 -5
  27. package/docs/roadmap.md +8 -9
  28. package/hooks/commit-msg +39 -22
  29. package/lib/adaptive.d.ts +15 -0
  30. package/lib/adaptive.js +54 -0
  31. package/lib/adaptive.js.map +1 -0
  32. package/lib/client.js +719 -433
  33. package/lib/client.js.map +3 -3
  34. package/lib/controller.d.ts +50 -0
  35. package/lib/controller.js +132 -0
  36. package/lib/controller.js.map +1 -1
  37. package/lib/dev-task.js +413 -18
  38. package/lib/dev-task.js.map +1 -1
  39. package/lib/engine.d.ts +20 -0
  40. package/lib/engine.js +4 -1
  41. package/lib/engine.js.map +1 -1
  42. package/lib/hook.js +50 -29
  43. package/lib/hook.js.map +1 -1
  44. package/lib/project-init.d.ts +23 -0
  45. package/lib/project-init.js +94 -0
  46. package/lib/project-init.js.map +1 -0
  47. package/lib/skill-audit.js +8 -7
  48. package/lib/skill-audit.js.map +1 -1
  49. package/lib/sonar.d.ts +33 -0
  50. package/lib/sonar.js +80 -0
  51. package/lib/sonar.js.map +1 -0
  52. package/package.json +15 -16
  53. package/preset/agent.cordis.yml +3 -3
  54. package/preset/enable.mjs +2 -2
  55. package/preset/persona.md +4 -2
  56. package/scripts/verify-package.mjs +9 -5
  57. package/skills/architecture-design/SKILL.md +11 -0
  58. package/skills/code-development/SKILL.md +11 -0
  59. package/skills/code-review/SKILL.md +11 -0
  60. package/skills/eng-delivery/SKILL.md +19 -15
  61. package/skills/requirements-analysis/SKILL.md +11 -0
  62. package/skills/task-orchestration/SKILL.md +11 -0
  63. package/skills/test-validation/SKILL.md +11 -0
package/docs/roadmap.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [← 文档导航](README.md)
4
4
 
5
- 本页记录**讨论中的方向,不代表已发布功能**;是否实现、何时实现都在开始编码前单独确认。
5
+ 本页记录已发布能力与后续方向;任务级流程见[自适应工程任务](adaptive-workflows.md)。
6
6
  已发布的能力与版本变化见[更新日志](CHANGELOG.md)。
7
7
 
8
8
  ## 当前能力边界
@@ -10,16 +10,16 @@
10
10
  | 能力 | 状态 |
11
11
  | :--- | :--- |
12
12
  | 三个内置流程(`standard`、`agile`、`minimal`) | ✅ 已发布,开箱即用 |
13
- | 阶段选择技能、规则归属技能 | ✅ 已发布 |
13
+ | 阶段选择技能、规则归属技能 | ✅ 已发布 |
14
14
  | 任务台账、验证与审核回执、提交门禁 | ✅ 已发布 |
15
- | 项目级与个人级资源安装、来源保留 | ✅ 已发布 |
16
- | **自由编辑流程阶段与条件** | ❌ **不在计划内** |
15
+ | 项目级与个人级资源安装、来源保留 | ✅ 已发布 |
16
+ | 四档任务级流程、元技能、项目扫描 init、可选审核期 SonarQube CI 接入 | ✅ 0.29.0 |
17
+ | **自由编辑流程阶段与条件** | ❌ **不在计划内** |
17
18
 
18
19
  **关于自定义流程**:让使用者自行设计阶段、条件与提交流程曾被评估,结论是**不列入计划**——
19
- 它把流程设计的负担转嫁给使用者,而三个内置流程已覆盖个人项目的常见需要。代码中不存在该能力的
20
- 实现;相关尝试保留在非发布分支,不在 `main` 上。
20
+ 任务级四档流程覆盖常见开发复杂度,用户可挂载项目技能;自由编辑状态机仍不在当前范围。
21
21
 
22
- 需要调整时,可修改项目根目录的 `.dsh/eng.json` 改变阶段资源绑定,或直接在三个内置流程中选择。
22
+ 旧任务继续读取 `.dsh/eng.json`;新任务用 `.dsh/meta.json` 管理元技能挂载,复杂度在任务创建时确定。
23
23
 
24
24
  ## 后续体验方向
25
25
 
@@ -30,5 +30,4 @@
30
30
 
31
31
  ## 产品范围
32
32
 
33
- 本项目服务本机个人开发工作台。多用户服务器的会话权限架构不列为当前版本的必修项。日常改进优先
34
- 解决工作区目标清晰、文件误操作、任务连续性和操作反馈。
33
+ 本项目服务本机与团队分支开发中的个人会话。多用户服务器的会话权限架构不列为当前版本的必修项。日常改进优先解决工作区目标清晰、文件误操作、任务连续性和操作反馈。
package/hooks/commit-msg CHANGED
@@ -148,7 +148,7 @@ function commitCheckpoint(state2, config2) {
148
148
  return { allowed: false, reason: "no commit is due at this stage under the current policy" };
149
149
  }
150
150
  function isEngineMeta(file) {
151
- return /^\.dsh\/(task-[^/]+\.json|eng\.json)$/.test(file);
151
+ return /^\.dsh\/(task-[^/]+\.json|eng\.json|meta\.json)$/.test(file);
152
152
  }
153
153
  function checkFileScope(state2, committing, config2) {
154
154
  if (!config2.commit.file_scope) return { ok: true, outside: [], noScope: false };
@@ -419,6 +419,9 @@ function normalizeTask(task) {
419
419
  branch: String(task.branch ?? ""),
420
420
  work_size: task.work_size ?? "standard",
421
421
  risk_level: task.risk_level ?? "standard",
422
+ ...task.complexity !== void 0 ? { complexity: task.complexity } : {},
423
+ ...task.sonar_policy !== void 0 ? { sonar_policy: task.sonar_policy } : {},
424
+ ...task.sonar_audit !== void 0 ? { sonar_audit: task.sonar_audit } : {},
422
425
  stage: String(task.stage ?? ""),
423
426
  requirement_confirmed: task.requirement_confirmed === true,
424
427
  solution_confirmed: task.solution_confirmed === true,
@@ -501,7 +504,21 @@ function extractTaskId(message2) {
501
504
  return match ? match[1] : void 0;
502
505
  }
503
506
  function isEngineMeta2(file) {
504
- return /^\.dsh\/(task-[^/]+\.json|eng\.json)$/.test(file);
507
+ return /^\.dsh\/(task-[^/]+\.json|eng\.json|meta\.json)$/.test(file);
508
+ }
509
+ function scopeHash(state2, root) {
510
+ const entries2 = [...new Set(state2.files)].filter((file) => !isEngineMeta2(file)).sort().map((file) => {
511
+ const target = import_node_path.default.resolve(root, file);
512
+ const inside = import_node_path.default.relative(root, target);
513
+ if (inside.startsWith("..") || import_node_path.default.isAbsolute(inside)) refuse(`\u4EFB\u52A1\u8303\u56F4\u8DEF\u5F84\u8D8A\u754C: ${file}`);
514
+ try {
515
+ return [file, hashText(import_node_fs.default.readFileSync(target, "utf8"))];
516
+ } catch (error) {
517
+ if (error.code === "ENOENT") return [file, null];
518
+ refuse(`\u65E0\u6CD5\u8BFB\u53D6\u4EFB\u52A1\u6587\u4EF6 ${file}: ${error instanceof Error ? error.message : String(error)}`);
519
+ }
520
+ });
521
+ return hashText(JSON.stringify(entries2));
505
522
  }
506
523
  function riskyPaths(entries2) {
507
524
  return entries2.filter((entry) => !isEngineMeta2(entry.path)).filter((entry) => DEFAULT_RISK_POLICY.sensitive_paths.some((prefix) => entry.path === prefix || entry.path.startsWith(`${prefix}/`))).map((entry) => entry.path);
@@ -536,30 +553,11 @@ function loadWorkflow(parsed) {
536
553
  }
537
554
  return resolved.config;
538
555
  }
539
- var cwd = process.cwd();
540
- var configPath = import_node_path.default.join(cwd, ".dsh", "eng.json");
541
- var config;
542
- if (import_node_fs.default.existsSync(configPath)) {
543
- let raw = "";
544
- try {
545
- raw = import_node_fs.default.readFileSync(configPath, "utf8");
546
- } catch {
547
- raw = "";
548
- }
549
- let parsed;
550
- try {
551
- parsed = JSON.parse(raw);
552
- } catch (error) {
553
- refuse("invalid JSON in .dsh/eng.json: " + (error instanceof Error ? error.message : String(error)));
554
- }
555
- config = loadWorkflow(parsed);
556
- } else {
557
- config = loadWorkflow(void 0);
558
- }
559
556
  if (!messageFile) {
560
557
  process.exit(0);
561
558
  }
562
559
  var message = readCommitMessage(messageFile);
560
+ var cwd = process.cwd();
563
561
  var tasks = loadTasks();
564
562
  var taskId = extractTaskId(message);
565
563
  var state;
@@ -578,8 +576,20 @@ if (!state) {
578
576
  if (state.flow?.hash !== void 0 && hashConfig(state.flow.config) !== state.flow.hash) {
579
577
  refuse(`\u4EFB\u52A1 ${state.id} \u7684\u6D41\u7A0B\u5FEB\u7167 hash \u4E0D\u5339\u914D\u2014\u2014task \u8BB0\u5F55\u5728\u521B\u5EFA\u540E\u88AB\u6539\u52A8\u8FC7\uFF0C\u4FEE\u590D\u6216\u91CD\u5EFA\u4EFB\u52A1\u540E\u518D\u63D0\u4EA4`);
580
578
  }
579
+ var config;
581
580
  if (state.flow !== void 0 && state.flow.config !== void 0) {
582
581
  config = state.flow.config;
582
+ } else {
583
+ const configPath = import_node_path.default.join(cwd, ".dsh", "eng.json");
584
+ if (import_node_fs.default.existsSync(configPath)) {
585
+ let parsed;
586
+ try {
587
+ parsed = JSON.parse(import_node_fs.default.readFileSync(configPath, "utf8"));
588
+ } catch (error) {
589
+ refuse("invalid JSON in .dsh/eng.json: " + (error instanceof Error ? error.message : String(error)));
590
+ }
591
+ config = loadWorkflow(parsed);
592
+ } else config = loadWorkflow(void 0);
583
593
  }
584
594
  var verdict = validateCommitMessage(message, config);
585
595
  if (!verdict.ok) {
@@ -589,6 +599,13 @@ var checkpoint = commitCheckpoint(state, config);
589
599
  if (!checkpoint.allowed) {
590
600
  refuse((checkpoint.reason ?? "commit checkpoint rejected") + "\uFF08\u5F53\u524D\u9636\u6BB5: " + state.stage + "\uFF09");
591
601
  }
602
+ if (state.sonar_policy?.enabled && ["\u4EE3\u7801\u5BA1\u6838", "\u5B8C\u6210"].includes(state.stage)) {
603
+ const audit = state.sonar_audit;
604
+ const lastCommit = state.commits.findLast((entry) => entry.hash !== void 0)?.hash;
605
+ if (!audit || audit.gate !== "OK" || audit.blocking.length > 0 || audit.scope_hash !== scopeHash(state, cwd) || !lastCommit || audit.commit_hash !== lastCommit) {
606
+ refuse("SonarQube \u5BA1\u6838\u672A\u901A\u8FC7\u6216\u5DF2\u8FC7\u671F\u2014\u2014\u5728\u4EE3\u7801\u5BA1\u6838\u9636\u6BB5\u5B8C\u6210\u65B0\u4E00\u6B21 CI \u626B\u63CF\u5E76\u8C03\u7528 dev_task operation=sonar_check");
607
+ }
608
+ }
592
609
  var entries = stagedEntries();
593
610
  var scope = checkFileScope(state, entries.map((entry) => entry.path), config);
594
611
  if (!scope.ok) {
@@ -0,0 +1,15 @@
1
+ /** Task-scoped engineering flows. The grade selects gates; risk remains separate. */
2
+ import type { WorkflowConfig } from './engine.ts';
3
+ export type Complexity = 'low' | 'medium' | 'high' | 'ultra';
4
+ export type MetaSkill = 'requirements-analysis' | 'architecture-design' | 'task-orchestration' | 'code-development' | 'test-validation' | 'code-review';
5
+ export declare const COMPLEXITY_OPTIONS: readonly {
6
+ id: Complexity;
7
+ label: string;
8
+ guidance: string;
9
+ }[];
10
+ export declare const META_STAGES: Readonly<Record<MetaSkill, string>>;
11
+ export declare const ADAPTIVE_VERSION = 1;
12
+ /** A grade is a per-task snapshot, never a project-wide forced flow. */
13
+ export declare function adaptiveWorkflow(grade: Complexity): WorkflowConfig;
14
+ export declare function isComplexity(value: unknown): value is Complexity;
15
+ export declare function metaForStage(stage: string): MetaSkill | undefined;
@@ -0,0 +1,54 @@
1
+ export const COMPLEXITY_OPTIONS = [
2
+ { id: 'low', label: '低', guidance: '边界明确的局部修改;一个实施项即可说明改动。' },
3
+ { id: 'medium', label: '中', guidance: '常规功能或缺陷修复;先写清需求与验收条件。' },
4
+ { id: 'high', label: '高', guidance: '跨模块或有先后依赖的需求;按实现顺序编排任务与交接产物。' },
5
+ { id: 'ultra', label: '超高', guidance: '完整新模块或大范围重构;先明确架构边界,再按依赖顺序实施。' },
6
+ ];
7
+ export const META_STAGES = {
8
+ 'requirements-analysis': '需求分析',
9
+ 'architecture-design': '架构设计',
10
+ 'task-orchestration': '任务编排',
11
+ 'code-development': '代码开发',
12
+ 'test-validation': '测试',
13
+ 'code-review': '代码审核',
14
+ };
15
+ export const ADAPTIVE_VERSION = 1;
16
+ const COMMON_ARTIFACTS = [
17
+ { stage: '需求分析', id: 'requirement', name: '需求与验收条件', fields: ['goal', 'scope', 'acceptance'] },
18
+ { stage: '架构设计', id: 'architecture', name: '架构边界', fields: ['approach', 'impact', 'tradeoffs'] },
19
+ { stage: '任务编排', id: 'task-plan', name: '按实现顺序排列的任务', fields: ['steps', 'dependencies', 'handoffs'] },
20
+ ];
21
+ /** A grade is a per-task snapshot, never a project-wide forced flow. */
22
+ export function adaptiveWorkflow(grade) {
23
+ const prefix = grade === 'low' ? []
24
+ : grade === 'medium' ? ['需求分析']
25
+ : grade === 'high' ? ['需求分析', '任务编排']
26
+ : ['需求分析', '架构设计', '任务编排'];
27
+ const stages = [...prefix, '代码开发', '测试', '代码审核', '完成'];
28
+ const transitions = stages.slice(0, -1).map((from, index) => {
29
+ const to = stages[index + 1];
30
+ const requires = from === '需求分析' || from === '架构设计' || from === '任务编排'
31
+ ? ['artifacts_present']
32
+ : from === '代码开发' ? ['todos_done']
33
+ : from === '测试' ? ['verified']
34
+ : from === '代码审核' ? ['review_passed'] : [];
35
+ return { from, to, requires };
36
+ });
37
+ return {
38
+ stages,
39
+ start_stage: stages[0],
40
+ transitions,
41
+ artifacts: COMMON_ARTIFACTS.filter(artifact => stages.includes(artifact.stage)),
42
+ // The branch must be committed/pushed before its CI Sonar scan can run.
43
+ commit: { policy: 'task', message_pattern: '', message_hint: '无格式要求', checkpoints: ['测试'], file_scope: true },
44
+ high_risk_requires_verification: true,
45
+ review_depth: grade === 'low' ? 'single' : 'two-stage',
46
+ };
47
+ }
48
+ export function isComplexity(value) {
49
+ return value === 'low' || value === 'medium' || value === 'high' || value === 'ultra';
50
+ }
51
+ export function metaForStage(stage) {
52
+ return Object.entries(META_STAGES).find(([, label]) => label === stage)?.[0];
53
+ }
54
+ //# sourceMappingURL=adaptive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adaptive.js","sourceRoot":"","sources":["../src/adaptive.ts"],"names":[],"mappings":"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"}