@sokeai/cli 1.0.76 → 1.0.77

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 (123) hide show
  1. package/README.md +7 -7
  2. package/package.json +1 -1
  3. package/scripts/build-binaries.sh +1 -1
  4. package/scripts/e2e-test.sh +75 -3
  5. package/skills/SKILL.md +18 -1
  6. package/skills/soke-ai-coach-director/CHANGELOG.md +203 -0
  7. package/skills/soke-ai-coach-director/README.md +123 -0
  8. package/skills/soke-ai-coach-director/SKILL.md +221 -0
  9. package/skills/soke-ai-coach-director/coaching/knowledge-packager/knowledge-packager.md +91 -0
  10. package/skills/soke-ai-coach-director/coaching/prompt-engineer/parts/part2-roles.md +97 -0
  11. package/skills/{ai-coach-director → soke-ai-coach-director}/coaching/prompt-engineer/parts/part3-flow.md +3 -3
  12. package/skills/soke-ai-coach-director/coaching/prompt-engineer/prompt-engineer.md +76 -0
  13. package/skills/{ai-coach-director → soke-ai-coach-director}/coaching/prompt-optimizer/prompt-optimizer.md +77 -58
  14. package/skills/{ai-coach-director → soke-ai-coach-director}/platform/adapters/workbuddy.md +2 -3
  15. package/skills/soke-ai-coach-director/platform/interaction.md +103 -0
  16. package/skills/{ai-coach-director → soke-ai-coach-director}/platform/publish-gate.md +3 -3
  17. package/skills/{ai-coach-director → soke-ai-coach-director}/platform/resource-finalizer.md +10 -35
  18. package/skills/{ai-coach-director → soke-ai-coach-director}/platform/soke-ai-training/soke-ai-training.md +33 -3
  19. package/skills/soke-ai-coach-director/platform/sync-engine.md +39 -0
  20. package/skills/{ai-coach-director → soke-ai-coach-director}/references/change-log-partwise-refactor.md +1 -1
  21. package/skills/soke-ai-coach-director/references/env-check.md +146 -0
  22. package/skills/soke-ai-coach-director/references/exec-common.md +126 -0
  23. package/skills/soke-ai-coach-director/references/exec-handbook.md +621 -0
  24. package/skills/soke-ai-coach-director/references/exec-part1.md +86 -0
  25. package/skills/soke-ai-coach-director/references/exec-part2.md +145 -0
  26. package/skills/soke-ai-coach-director/references/exec-part3.md +91 -0
  27. package/skills/soke-ai-coach-director/references/exec-part4.md +187 -0
  28. package/skills/soke-ai-coach-director/references/gate-check-matrix.md +46 -0
  29. package/skills/soke-ai-coach-director/references/micro-tune-labels.md +30 -0
  30. package/skills/soke-ai-coach-director/references/platform-api-pitfalls.md +49 -0
  31. package/skills/soke-ai-coach-director/references/role-resource-matching.md +45 -0
  32. package/skills/{ai-coach-director → soke-ai-coach-director}/references/self-improvement-examples.md +2 -0
  33. package/skills/soke-ai-coach-director/references/self-learning-engine.md +489 -0
  34. package/skills/soke-ai-coach-director/references/subs/part1/SOP.md +17 -0
  35. package/skills/soke-ai-coach-director/references/subs/part2/SOP.md +34 -0
  36. package/skills/soke-ai-coach-director/references/subs/part3/SOP.md +27 -0
  37. package/skills/soke-ai-coach-director/references/subs/part4/SOP.md +31 -0
  38. package/skills/soke-ai-coach-director/references/subs/publish/SOP.md +81 -0
  39. package/skills/soke-ai-coach-director/references/subs/tune/SOP.md +92 -0
  40. package/skills/soke-ai-coach-director/references/verified-cli-cheatsheet.md +56 -0
  41. package/skills/{ai-coach-director → soke-ai-coach-director}/scripts/activator.sh +0 -0
  42. package/skills/{ai-coach-director → soke-ai-coach-director}/scripts/error-detector.sh +0 -0
  43. package/skills/{ai-coach-director → soke-ai-coach-director}/scripts/extract-skill.sh +0 -0
  44. package/skills/soke-ai-coach-director/scripts/gate_check.py +112 -0
  45. package/skills/soke-ai-coach-director/scripts/validate_operations.py +403 -0
  46. package/skills/soke-certificate/SKILL.md +717 -0
  47. package/skills/soke-course/README.md +6 -2
  48. package/skills/soke-course/SKILL.md +3 -3
  49. package/skills/soke-course/references/course-list-courses.md +49 -84
  50. package/skills/soke-course/references/intent-cases.md +2 -2
  51. package/skills/soke-course/references/sop-full-workflow.md +4 -2
  52. package/skills/soke-course/references/subs/publish/SOP.md +21 -3
  53. package/skills/soke-course/references/subs/query/SOP.md +9 -7
  54. package/skills/soke-course/references/subs/settings/SOP.md +2 -1
  55. package/skills/soke-exam-question-pool/SKILL.md +2 -2
  56. package/skills/soke-task/SKILL.md +32 -10
  57. package/skills/soke-training-demand/SKILL.md +2 -2
  58. package/skills/ai-coach-director/SKILL.md +0 -1563
  59. package/skills/ai-coach-director/coaching/prompt-engineer/parts/part2-roles.md +0 -317
  60. package/skills/ai-coach-director/coaching/prompt-engineer/prompt-engineer.md +0 -244
  61. package/skills/ai-coach-director/platform/interaction.md +0 -315
  62. package/skills/ai-coach-director/platform/sync-engine.md +0 -1101
  63. package/skills/ai-coach-director/references/cases/create//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/347/224/265/350/257/235/347/272/246/350/256/277//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/347/224/265/350/257/235/347/272/246/350/256/277_/346/240/207/345/207/206/347/237/245/350/257/206/345/272/223.md +0 -199
  64. package/skills/ai-coach-director/references/cases/create//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/347/224/265/350/257/235/347/272/246/350/256/277//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/347/224/265/350/257/235/347/272/246/350/256/277/347/237/245/350/257/206/345/272/223.md +0 -388
  65. package/skills/ai-coach-director/references/cases/create//346/237/220/345/233/275/351/231/205/346/243/200/346/265/213/346/234/272/346/236/204/tuv-knowledge-base.md +0 -125
  66. package/skills/ai-coach-director/references/cases/create//346/237/220/345/233/275/351/231/205/346/243/200/346/265/213/346/234/272/346/236/204/tuv-p03-first-call-scenario-prompt.md +0 -428
  67. package/skills/ai-coach-director/references/cases/create//346/237/220/345/233/275/351/231/205/346/243/200/346/265/213/346/234/272/346/236/204//346/237/220/345/233/275/351/231/205/346/243/200/346/265/213/346/234/272/346/236/204P03/351/231/252/347/273/203/346/211/247/350/241/214/346/226/271/346/241/210_20260610.md +0 -225
  68. package/skills/ai-coach-director/references/cases/create//346/237/220/345/234/260/346/226/271/351/223/266/350/241/214//346/237/220/345/234/260/346/226/271/351/223/266/350/241/214/345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/347/224/265/350/257/235/347/272/246/350/256/277AI/351/231/252/347/273/203/346/265/213/350/257/225/347/224/250/344/276/213/345/220/210/351/233/206.md +0 -525
  69. package/skills/ai-coach-director/references/cases/create//347/211/251/346/265/201/350/241/214/344/270/232//347/211/251/346/265/201/350/241/214/344/270/232-/345/210/235/346/254/241/346/213/234/350/256/277/351/246/231/347/262/276/351/246/231/346/226/231/345/256/242/346/210/267.md +0 -146
  70. package/skills/ai-coach-director/references/cases/create//351/205/222/345/272/227/351/244/220/351/245/256//351/205/222/345/272/227/351/244/220/351/245/256AI/351/231/252/347/273/203_/346/240/207/346/235/2061_/346/226/260/345/223/201/346/216/250/351/224/200_20260701.md +0 -230
  71. package/skills/ai-coach-director/references/cases/create//351/205/222/345/272/227/351/244/220/351/245/256//351/205/222/345/272/227/351/244/220/351/245/256AI/351/231/252/347/273/203_/346/240/207/346/235/2062_/345/202/254/350/217/234/345/256/211/346/212/232_20260701.md +0 -257
  72. package/skills/ai-coach-director/references/cases/create//351/205/222/345/272/227/351/244/220/351/245/256//351/205/222/345/272/227/351/244/220/351/245/256AI/351/231/252/347/273/203_/346/240/207/346/235/2063_/345/267/256/350/257/204/345/233/236/350/256/277_20260701.md +0 -259
  73. package/skills/ai-coach-director/references/cases/create//351/205/222/345/272/227/351/244/220/351/245/256//351/205/222/345/272/227/351/244/220/351/245/256AI/351/231/252/347/273/203/345/234/272/346/231/257/346/226/271/346/241/210_20260701.md +0 -452
  74. package/skills/ai-coach-director/references/cases/create//351/231/214/346/213/234/344/277/241/346/201/257/346/224/266/351/233/206//351/231/214/346/213/234/344/277/241/346/201/257/346/224/266/351/233/206_/345/256/242/346/210/267/347/241/256/350/256/244/345/217/215/351/246/210/350/241/250.md +0 -133
  75. package/skills/ai-coach-director/references/cases/create//351/231/214/346/213/234/344/277/241/346/201/257/346/224/266/351/233/206//351/231/214/346/213/234/344/277/241/346/201/257/346/224/266/351/233/206_/351/231/252/347/273/203/346/217/220/347/244/272/350/257/215_v1.md +0 -333
  76. package/skills/ai-coach-director/references/cases/create//351/231/214/346/213/234/344/277/241/346/201/257/346/224/266/351/233/206//351/231/214/346/213/234/344/277/241/346/201/257/346/224/266/351/233/206_/351/231/252/347/273/203/346/217/220/347/244/272/350/257/215_v2_Part1-Part5.md +0 -649
  77. package/skills/ai-coach-director/references/env-check.md +0 -167
  78. package/skills/ai-coach-director/references/platform-api-pitfalls.md +0 -232
  79. package/skills/ai-coach-director/references/role-resource-matching.md +0 -349
  80. package/skills/ai-coach-director/references/verified-cli-cheatsheet.md +0 -203
  81. /package/skills/{ai-coach-director → soke-ai-coach-director}/assets/ERRORS-TEMPLATE.md +0 -0
  82. /package/skills/{ai-coach-director → soke-ai-coach-director}/assets/FEATURE_REQUESTS-TEMPLATE.md +0 -0
  83. /package/skills/{ai-coach-director → soke-ai-coach-director}/assets/LEARNINGS-TEMPLATE.md +0 -0
  84. /package/skills/{ai-coach-director → soke-ai-coach-director}/assets/SKILL-TEMPLATE.md +0 -0
  85. /package/skills/{ai-coach-director → soke-ai-coach-director}/coaching/prompt-engineer/parts/part1-basic.md +0 -0
  86. /package/skills/{ai-coach-director → soke-ai-coach-director}/coaching/prompt-engineer/parts/part4-scoring.md +0 -0
  87. /package/skills/{ai-coach-director → soke-ai-coach-director}/coaching/prompt-engineer/parts/part5-constraints.md +0 -0
  88. /package/skills/{ai-coach-director → soke-ai-coach-director}/coaching/role-profiler/role-profiler.md +0 -0
  89. /package/skills/{ai-coach-director → soke-ai-coach-director}/platform/adapters/README.md +0 -0
  90. /package/skills/{ai-coach-director → soke-ai-coach-director}/platform/adapters/qclaw.md +0 -0
  91. /package/skills/{ai-coach-director → soke-ai-coach-director}/platform/adapters/wukong.md +0 -0
  92. /package/skills/{ai-coach-director → soke-ai-coach-director}/platform/adapters/zework.md +0 -0
  93. /package/skills/{ai-coach-director → soke-ai-coach-director}/platform/api-fallback.md +0 -0
  94. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/AI/345/256/242/346/210/267/350/247/222/350/211/262/346/250/241/346/235/277/345/272/223.md" +0 -0
  95. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/AI/351/231/252/347/273/203Bad Case/346/240/267/346/234/254/345/272/223.md" +0 -0
  96. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/AI/351/231/252/347/273/203/345/210/233/345/273/272/351/227/256/351/242/230/345/272/223.md" +0 -0
  97. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/AI/351/231/252/347/273/203/345/234/272/346/231/257/345/210/206/347/261/273/345/272/223.md" +0 -0
  98. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/AI/351/231/252/347/273/203/345/256/242/346/210/267/346/235/220/346/226/231/346/270/205/345/215/225/344/270/216/350/256/277/350/260/210/351/242/230/345/272/223.md" +0 -0
  99. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/AI/351/231/252/347/273/203/345/276/256/350/260/203/351/227/256/351/242/230/345/272/223.md" +0 -0
  100. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/AI/351/231/252/347/273/203/346/212/200/346/234/257/350/276/271/347/225/214/344/270/216/346/216/222/351/232/234/345/272/223.md" +0 -0
  101. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/AI/351/231/252/347/273/203/346/217/220/347/244/272/350/257/215/346/250/241/345/235/227/345/272/223.md" +0 -0
  102. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/AI/351/231/252/347/273/203/346/225/260/346/215/256/346/214/207/346/240/207/344/270/216/347/234/213/346/235/277/345/217/243/345/276/204/345/272/223.md" +0 -0
  103. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/AI/351/231/252/347/273/203/346/265/213/350/257/225/347/224/250/344/276/213/345/272/223.md" +0 -0
  104. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/AI/351/231/252/347/273/203/350/257/204/345/210/206/346/240/207/345/207/206/347/273/204/344/273/266/345/272/223.md" +0 -0
  105. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/AI/351/231/252/347/273/203/351/241/271/347/233/256/346/241/210/344/276/213/345/244/215/347/233/230/345/272/223.md" +0 -0
  106. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/AI/351/241/276/345/256/242/350/247/222/350/211/262/346/250/241/346/213/237_GoodCase_BadCase_20260701.md" +0 -0
  107. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/create//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/347/224/265/350/257/235/347/272/246/350/256/277//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/345/256/242/346/210/267/346/235/220/346/226/231/346/261/207/346/200/273_2026-05-19_1341.md" +0 -0
  108. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/create//346/226/260/350/203/275/346/272/220/350/275/246/344/270/273/350/264/267//346/226/260/350/203/275/346/272/220/350/275/246/344/270/273/350/264/267/347/237/245/350/257/206/345/272/223/347/224/237/346/210/220_20260615.md" +0 -0
  109. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/create//346/226/260/350/203/275/346/272/220/350/275/246/344/270/273/350/264/267//346/226/260/350/203/275/346/272/220/350/275/246/344/270/273/350/264/267/351/231/252/347/273/203/346/217/220/347/244/272/350/257/215/347/224/237/346/210/220_20260615.md" +0 -0
  110. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/create//346/237/220/345/233/275/351/231/205/346/243/200/346/265/213/346/234/272/346/236/204//346/237/220/345/233/275/351/231/205/346/243/200/346/265/213/346/234/272/346/236/204/351/231/252/347/273/203/346/211/247/350/241/214/346/226/271/346/241/210/344/272/244/344/273/230/350/256/260/345/275/225_20260610.md" +0 -0
  111. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/create//351/231/214/346/213/234/344/277/241/346/201/257/346/224/266/351/233/206//351/231/214/346/213/234/344/277/241/346/201/257/346/224/266/351/233/206_/346/217/220/347/244/272/350/257/215/346/220/255/345/273/272_20260622.md" +0 -0
  112. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/micro-tune//344/274/201/344/270/232/345/256/266/347/216/213/346/200/273/347/263/273/345/210/227//344/274/201/344/270/232/345/256/266/347/216/213/346/200/273/346/217/220/347/244/272/350/257/215_/344/274/230/345/214/226/347/211/210_V1.1_20260616.md" +0 -0
  113. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/micro-tune//344/274/201/344/270/232/345/256/266/347/216/213/346/200/273/347/263/273/345/210/227//344/274/201/344/270/232/345/256/266/347/216/213/346/200/273/346/217/220/347/244/272/350/257/215_/344/274/230/345/214/226/347/211/210_V1.2_20260616.md" +0 -0
  114. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/micro-tune//344/274/201/344/270/232/345/256/266/347/216/213/346/200/273/347/263/273/345/210/227//344/274/201/344/270/232/345/256/266/347/216/213/346/200/273/346/217/220/347/244/272/350/257/215_/345/216/213/347/274/251/347/211/210_V2.0_20260616.md" +0 -0
  115. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/micro-tune//344/274/201/344/270/232/345/256/266/347/216/213/346/200/273/347/263/273/345/210/227//344/274/201/344/270/232/345/256/266/347/216/213/346/200/273/346/217/220/347/244/272/350/257/215/344/274/230/345/214/226_20260616.md" +0 -0
  116. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/micro-tune//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/347/263/273/345/210/227//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277AI/351/231/252/347/273/203/347/263/273/347/273/237_/346/265/213/350/257/225/345/217/215/351/246/210/346/261/207/346/200/273_2026-06-01.md" +0 -0
  117. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/micro-tune//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/347/263/273/345/210/227//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277KYC/344/277/241/344/273/273/345/200/274/347/246/201/344/273/244_2026-06-09_0932.md" +0 -0
  118. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/micro-tune//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/347/263/273/345/210/227//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277KYC/346/217/220/347/244/272/350/257/215_/344/274/230/345/214/226/347/211/210_v2_20260608.md" +0 -0
  119. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/micro-tune//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/347/263/273/345/210/227//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/346/217/220/347/244/272/350/257/215_/344/274/230/345/214/226/347/211/210_v1.1.md" +0 -0
  120. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/micro-tune//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/347/263/273/345/210/227//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/346/217/220/347/244/272/350/257/215_/344/274/230/345/214/226/347/211/210_v1.2.md" +0 -0
  121. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases/micro-tune//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/347/263/273/345/210/227//345/206/234/346/210/267/345/274/240/350/200/201/346/235/277/346/217/220/347/244/272/350/257/215/344/274/230/345/214/226_V2_/350/257/212/346/226/255/344/272/244/344/273/230_20260609.md" +0 -0
  122. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases//345/233/233/345/244/247/345/234/272/346/231/257_GoodCase_BadCase_20260701.md" +0 -0
  123. /package/skills/{ai-coach-director → soke-ai-coach-director}/references/cases//346/241/210/344/276/213/345/272/223/350/241/245/345/205/205_2026-06-24.md" +0 -0
@@ -0,0 +1,621 @@
1
+ # 执行手册(Execution Handbook)
2
+
3
+ > 本手册集中定义每个 Part 的**必做操作**、**完整 JSON 模板**、**提交前断言**、**反面案例**。
4
+ > SKILL.md 的每个 Part 行只引用本手册锚点,不重复规则。
5
+ > 所有规则以本手册为准;sync-engine.md / partN/SOP.md 仅作为字段参考手册。
6
+
7
+ ---
8
+
9
+ ## Part1 · 基础信息(创建场景)
10
+
11
+ ### 必做操作清单
12
+
13
+ | # | 操作 | CLI 命令 | 产物 |
14
+ |---|------|---------|------|
15
+ | 1 | 创建场景 | `soke-cli ai-training +create-scenario --request-file ./part1-create.json --pretty` | `scenario_id` |
16
+ | 2 | 回读验证 | `soke-cli ai-training +get-scenario --scenario-id <id> --pretty` | name/description/key_points/tags 一致 |
17
+
18
+ > Part1 走**创建链路**,不是 preview/apply 更新链路。没有 operations 数组。
19
+
20
+ ### 完整 JSON 模板(part1-create.json)
21
+
22
+ ```json
23
+ {
24
+ "name": "<场景名称,1-100 字符>",
25
+ "description": "<场景描述全文,完整搬运不缩略>",
26
+ "tags": ["标签1", "标签2", "标签3"],
27
+ "key_points": "1) 考核点1;2) 考核点2;3) 考核点3",
28
+ "scene_lang": "简体中文",
29
+ "scenario_cover": "https://newsokeeditorcdn.soke.cn/public/ai/cover/lingshou_daogou.png"
30
+ }
31
+ ```
32
+
33
+ **字段硬规则**:
34
+
35
+ | 字段 | 类型 | 固定值/约束 | 高频错误 |
36
+ |------|------|------------|---------|
37
+ | `name` | string | 1-100 字符,≤15 字推荐 | 空字符串 |
38
+ | `description` | string | Part1 场景描述全文,禁缩略 | 只写首句摘要 |
39
+ | `tags` | string[] | 3-5 个数组元素 | ❌ 逗号分隔字符串 |
40
+ | `key_points` | **string** | 多条用分号/编号拼成**单字符串** | ❌ 写成数组(平台会接受但字段为空) |
41
+ | `scene_lang` | string | 固定 `"简体中文"`(永不随场景变) | ❌ `"zh-CN"` / `"中文"` |
42
+ | `scenario_cover` | string | 固定默认图 URL | ❌ 占位/本地路径 |
43
+
44
+ ### 提交前断言(Python 表达式)
45
+
46
+ ```python
47
+ assert isinstance(data["name"], str) and 1 <= len(data["name"]) <= 100
48
+ assert isinstance(data["description"], str) and len(data["description"]) >= 20
49
+ assert isinstance(data["tags"], list) and 3 <= len(data["tags"]) <= 5
50
+ assert isinstance(data["key_points"], str) and len(data["key_points"]) > 0 # 必须是字符串
51
+ assert data["scene_lang"] == "简体中文"
52
+ assert data["scenario_cover"] == "https://newsokeeditorcdn.soke.cn/public/ai/cover/lingshou_daogou.png"
53
+ ```
54
+
55
+ 或运行 `python3 scripts/validate_part1.py ./part1-create.json`。
56
+
57
+ ### 反面案例(真实错误样本)
58
+
59
+ ```json
60
+ ❌ 案例 A:key_points 写成数组(平台接受但字段为空)
61
+ {
62
+ "key_points": ["快速吸引", "精准推介", "展后跟进"]
63
+ }
64
+
65
+ ❌ 案例 B:tags 写成逗号分隔字符串
66
+ {
67
+ "tags": "展会拓客,B2B销售,快速识别"
68
+ }
69
+
70
+ ❌ 案例 C:scene_lang 写成 zh-CN
71
+ {
72
+ "scene_lang": "zh-CN"
73
+ }
74
+
75
+ ❌ 案例 D:封面留空或写占位 URL
76
+ {
77
+ "scenario_cover": ""
78
+ }
79
+ ```
80
+
81
+ ### 创建后回读校验
82
+
83
+ ```python
84
+ # 执行 get-scenario 后断言
85
+ assert result["name"] == part1_create["name"]
86
+ assert result["description"] == part1_create["description"]
87
+ assert result["tags"] == part1_create["tags"]
88
+ assert result["key_points"] == part1_create["key_points"] # 若为空,检查是否提交了数组
89
+ assert result["scenario_id"] not in (None, "")
90
+ ```
91
+
92
+ - `scenario_id` 为空 → 视为创建失败,**禁止进入 Part2**
93
+ - `key_points` 回读为空 → 检查 part1-create.json 是否误写成数组
94
+
95
+ ---
96
+
97
+ ## Part2 · AI 角色设定(双操作同步锁)
98
+
99
+ ### 必做操作清单
100
+
101
+ | # | operation.type | 作用 | 不可省略 |
102
+ |---|---------------|------|---------|
103
+ | 1 | `update_basic` | 写入 OS 整体设定 A1-A7 全文到 `ai_roles_overall_description` | ✅ 遗漏会导致平台无 OS,角色退化为普通对话 |
104
+ | 2 | `replace_ai_roles` | 写入所有角色数据到 `ai_roles[]` | ✅ 遗漏会导致平台有 OS 无角色 |
105
+
106
+ **两操作必须全部 applied=true 才算 Part2 完成**。可在同一批 operations 数组提交(OS 在前、roles 在后),也可分两次 apply。
107
+
108
+ ### 完整 JSON 模板(part2-operations.json)
109
+
110
+ ```json
111
+ [
112
+ {
113
+ "type": "update_basic",
114
+ "data": {
115
+ "ai_roles_overall_description": "<A1-A7 OS 全文,单字符串,≥500 字符,禁摘要/禁'参见 Part2'>"
116
+ }
117
+ },
118
+ {
119
+ "type": "replace_ai_roles",
120
+ "data": {
121
+ "roles": [
122
+ {
123
+ "scenario_role_id": "role_<角色短码>",
124
+ "customization_level": "full",
125
+ "is_custom_role": true,
126
+ "customized_fields": ["name", "description", "communication_style", "background", "personality_type", "personality", "tags", "knowledge_level", "taboos_objections", "avatar", "voice_id", "source_type"],
127
+ "template_id": null,
128
+ "template_name": null,
129
+ "template_version": null,
130
+ "role_data": {
131
+ "name": "<角色名>",
132
+ "description": "<角色描述>",
133
+ "communication_style": "<沟通风格>",
134
+ "background": "<四段深度画像全文:我是谁/我的困扰/我的过往经历/我今天的心态>",
135
+ "personality_type": "<MBTI 单值,如 ISFJ>",
136
+ "personality": "<性格描述>",
137
+ "tags": ["标签1", "标签2"],
138
+ "knowledge_level": ["小白"],
139
+ "taboos_objections": ["禁忌1", "禁忌2"],
140
+ "avatar": "<后台资源匹配的 URL,禁手工预设>",
141
+ "voice_id": "<后台资源匹配的 ID,禁手工预设>",
142
+ "source_type": "custom"
143
+ }
144
+ }
145
+ ]
146
+ }
147
+ }
148
+ ]
149
+ ```
150
+
151
+ ### 字段硬规则
152
+
153
+ | 字段 | 类型 | 约束 |
154
+ |------|------|------|
155
+ | `ai_roles_overall_description` | string | ≥500 字符;A1-A7 全文拼接,不摘要 |
156
+ | `roles[]` | array | 非空,2-5 个角色 |
157
+ | `roles[].role_data.avatar/voice_id` | string | 后台 `+list-role-avatars/+list-role-voices` 匹配;**禁手工预设** |
158
+ | `roles[].role_data.knowledge_level` | string[] | 数组枚举(如 `["小白"]`),禁长句 |
159
+ | `roles[].role_data.tags` | string[] | 2-4 个 |
160
+ | `roles[].role_data.taboos_objections` | string[] | 列表项 |
161
+ | 外壳字段位置 | - | `customization_level/is_custom_role/customized_fields/scenario_role_id/template_id/template_name/template_version` 必须在 `role_data` **外层**;⚠️ `source_type` 例外——必须在 `role_data` **内**(`role_data.source_type="custom"`),外壳写 source_type 会触发"角色数据异常";⚠️ `created_at`/`updated_at` **禁传**——由平台自动生成,写字符串时间戳会触发"角色数据异常"(见 platform-api-pitfalls 陷阱1) |
162
+
163
+ ### 提交前断言
164
+
165
+ ```python
166
+ # 操作 1: update_basic OS
167
+ op_os = next(o for o in operations if o["type"] == "update_basic")
168
+ os_text = op_os["data"]["ai_roles_overall_description"]
169
+ assert isinstance(os_text, str) and len(os_text) >= 500
170
+
171
+ # 操作 2: replace_ai_roles
172
+ op_roles = next(o for o in operations if o["type"] == "replace_ai_roles")
173
+ roles = op_roles["data"]["roles"]
174
+ assert isinstance(roles, list) and len(roles) >= 1
175
+ for r in roles:
176
+ # v3 必检: 外壳字段完整性(created_at/updated_at 由平台自动生成,禁传,不在此列)
177
+ for outer_key in ["scenario_role_id", "customization_level", "is_custom_role",
178
+ "customized_fields",
179
+ "template_id", "template_name", "template_version"]:
180
+ assert outer_key in r, f"缺少外壳字段: {outer_key}"
181
+ assert r["template_id"] is None and r["template_name"] is None and r["template_version"] is None
182
+ # customized_fields 必须是 12 个字段名,不能只写 ["role_data"]
183
+ assert len(r["customized_fields"]) >= 10, f"customized_fields 太少"
184
+ assert "name" in r["customized_fields"], "customized_fields 缺 name"
185
+ # 外壳不能有 source_type
186
+ assert "source_type" not in r, "source_type 不应在外壳"
187
+ # role_data 验证
188
+ rd = r["role_data"]
189
+ assert rd["avatar"] and rd["voice_id"]
190
+ assert isinstance(rd["knowledge_level"], list)
191
+ assert rd.get("source_type") == "custom", "role_data.source_type 必须为 custom"
192
+ # 外壳字段不能在 role_data 内
193
+ for shell_field in ["customization_level", "is_custom_role", "customized_fields",
194
+ "scenario_role_id", "created_at", "updated_at",
195
+ "template_id", "template_name", "template_version"]:
196
+ assert shell_field not in rd, f"{shell_field} 误入 role_data"
197
+ ```
198
+
199
+ ### 反面案例
200
+
201
+ ```json
202
+ ❌ 案例 A:遗漏操作 1(OS)—— 只提交 replace_ai_roles
203
+ → 平台 ai_roles_overall_description=null,角色无 OS 约束,行为退化为普通对话
204
+ → Step 7 闸门第 9 项不通过
205
+
206
+ ❌ 案例 B:外壳字段误放入 role_data
207
+ {
208
+ "role_data": {
209
+ "customization_level": "full", ← 错位
210
+ "name": "李晓琳"
211
+ }
212
+ }
213
+ → 平台报"角色数据异常",avatar/voice_id 均为空
214
+
215
+ ❌ 案例 C:avatar/voice_id 手工预设
216
+ {
217
+ "role_data": {
218
+ "avatar": "https://xxx placeholder.png" ← 禁手工写
219
+ }
220
+ }
221
+ → 应该由后台 +list-role-avatars 匹配
222
+ ```
223
+
224
+ ---
225
+
226
+ ## Part3 · 流程设置
227
+
228
+ ### 必做操作清单
229
+
230
+ | # | operation.type | 作用 |
231
+ |---|---------------|------|
232
+ | 1 | `update_basic` | 写入 `opening_dialogue`(开场语全文)+ `opening_dialogue_type: 1` |
233
+ | 2 | 每环节一个 `add_conversation_step` | 写入对话 SOP 环节 |
234
+
235
+ > 🔒 **原子性约束**:开场语 + 所有环节必须在**同一批 operations 数组的同一次 apply** 中提交,禁止拆分多次 apply。
236
+
237
+ ### 完整 JSON 模板(part3-operations.json)
238
+
239
+ ```json
240
+ [
241
+ {
242
+ "type": "update_basic",
243
+ "data": {
244
+ "opening_dialogue": "<开场语完整原文>",
245
+ "opening_dialogue_type": 1
246
+ }
247
+ },
248
+ {
249
+ "type": "add_conversation_step",
250
+ "data": {
251
+ "step_name": "<环节名>",
252
+ "student_objective": "<学员目标,与 Part1 考核点一一对应>",
253
+ "ai_task": "<AI 任务,含 IF-THEN + 进入条件 + 角色行为 + 退出条件>",
254
+ "max_rounds": 5,
255
+ "sort_order": "1"
256
+ }
257
+ }
258
+ ]
259
+ ```
260
+
261
+ ### 字段硬规则
262
+
263
+ | 字段 | 类型 | 约束 | 高频错误 |
264
+ |------|------|------|---------|
265
+ | `opening_dialogue_type` | **number** | 固定 `1`(整数,非字符串) | ❌ `"AI智能生成"` / `"1"` |
266
+ | `opening_dialogue` | string | 开场语完整原文 | ❌ 缩略 |
267
+ | `add_conversation_step.data.sort_order` | **string** | `"1"`、`"2"`(字符串) | ❌ 数字 1 |
268
+ | `ai_task` | string | 含 IF-THEN + 进入条件 + 角色行为 + 退出条件 | ❌ 缺 IF-THEN / 缺退出条件 |
269
+ | `max_rounds` | number | 整数 3-10 | ❌ 字符串 / 超范围 |
270
+
271
+ ### 提交前断言
272
+
273
+ ```python
274
+ op_open = next(o for o in operations if o["type"] == "update_basic")
275
+ assert op_open["data"]["opening_dialogue_type"] == 1 # 数字,不是字符串
276
+ assert isinstance(op_open["data"]["opening_dialogue"], str) and len(op_open["data"]["opening_dialogue"]) > 20
277
+
278
+ steps = [o for o in operations if o["type"] == "add_conversation_step"]
279
+ assert 3 <= len(steps) <= 7
280
+ for i, s in enumerate(steps):
281
+ d = s["data"]
282
+ for k in ["step_name", "student_objective", "ai_task", "max_rounds", "sort_order"]:
283
+ assert d.get(k) not in (None, "", []), f"step{i} missing {k}"
284
+ assert isinstance(d["sort_order"], str), f"step{i} sort_order 必须是字符串"
285
+ assert isinstance(d["max_rounds"], int) and 3 <= d["max_rounds"] <= 10
286
+ assert "IF" in d["ai_task"].upper() and "退出" in d["ai_task"] # 简单断言 IF-THEN 和退出条件存在
287
+ ```
288
+
289
+ ### 反面案例
290
+
291
+ ```json
292
+ ❌ 案例 A:opening_dialogue_type 写字符串
293
+ { "opening_dialogue_type": "1" }
294
+ → 422 报错:opening_dialogue_type 必须是 1 或 2
295
+
296
+ ❌ 案例 B:sort_order 写数字
297
+ { "sort_order": 1 }
298
+ → 应该是 "1"(字符串)
299
+
300
+ ❌ 案例 C:拆分多次 apply(违反原子性)
301
+ 第 1 次 apply:只提交开场语
302
+ 第 2 次 apply:提交对话环节
303
+ → 违反原子性约束,应同一批 operations
304
+ ```
305
+
306
+ ---
307
+
308
+ ## Part4 · 评分标准(双层包装锁)
309
+
310
+ ### 必做操作清单
311
+
312
+ | # | operation.type | 作用 |
313
+ |---|---------------|------|
314
+ | 1 | `replace_scoring_criteria_config` | 写入评分标准(含 5 维度+权重+一票否决) |
315
+
316
+ ### 完整 JSON 模板(part4-operations.json)
317
+
318
+ ```json
319
+ [
320
+ {
321
+ "type": "replace_scoring_criteria_config",
322
+ "data": {
323
+ "config": {
324
+ "customization_level": "full",
325
+ "is_custom_criteria": true,
326
+ "customized_fields": ["criteria_data"],
327
+ "scenario_criteria_id": "criteria_<场景短码>",
328
+ "criteria_data": {
329
+ "name": "<评分标准名称,8-20 字>",
330
+ "description": "<评分标准描述全文>",
331
+ "source_type": "enterprise",
332
+ "total_weight": 100,
333
+ "tags": ["标签1", "标签2"],
334
+ "dimensions": [
335
+ {
336
+ "id": "dim_<code>",
337
+ "code": "<英文 code>",
338
+ "name": "<维度名>",
339
+ "description": "<维度描述>",
340
+ "weight": 25,
341
+ "scoring_rule": "<评分规则全文,含一票否决嵌入末尾>",
342
+ "criteria": ["评分点1", "评分点2"],
343
+ "sort_order": 1
344
+ }
345
+ ]
346
+ }
347
+ }
348
+ }
349
+ }
350
+ ]
351
+ ```
352
+
353
+ ### 双层包装锁
354
+
355
+ | 层级 | 位置 | 字段 |
356
+ |------|------|------|
357
+ | **第 1 层(config 外壳)** | `data.config` | `customization_level` / `is_custom_criteria` / `customized_fields` / `scenario_criteria_id` / `criteria_data` |
358
+ | **第 2 层(criteria_data 内核)** | `data.config.criteria_data` | `name` / `description` / `source_type` / `total_weight` / `tags` / `dimensions[]` |
359
+
360
+ **双层缺一不可**。常见错误:只包 `config` 漏 `criteria_data`(平台会接受但存储结构错误,后续查询/weight 校验/同步都异常)。
361
+
362
+ ### 🔒 UI 展示硬要求(v2.24.1 新增)
363
+
364
+ **以下字段 API 存储时不强制,但平台 UI 展示时必需——缺失会导致 UI 上看不到 Part4 数据**(2026-08-06 长龙航空中文版事故):
365
+
366
+ | 字段 | 位置 | 必需值示例 |
367
+ |------|------|-----------|
368
+ | `customization_level` | `criteria_data` 顶层 | `"full"` |
369
+ | `is_custom_criteria` | `criteria_data` 顶层 | `true` |
370
+ | `customized_fields` | `criteria_data` 顶层 | `["criteria_data"]` |
371
+ | `scenario_criteria_id` | `criteria_data` 顶层 | `"criteria_<场景短码>_v1"` |
372
+ | `total_weight` | `criteria_data` 顶层 | `100` |
373
+ | `tags` | `criteria_data` 顶层 | 与 Part1 场景标签一致 |
374
+ | `dimensions[].id` | 每个维度 | `"dim_<code>"` |
375
+ | `dimensions[].sort_order` | 每个维度 | 数字 1、2、3... |
376
+
377
+ > ⚠️ **历史教训**:API 接受只包 `criteria_data.dimensions` 的简化结构(存储成功),但平台 UI 会显示"无评分标准"。必须在 `criteria_data` 顶层补全上述 6 个字段,每个维度补 `id` 和 `sort_order`。
378
+
379
+ ### 字段硬规则
380
+
381
+ | 字段 | 类型 | 约束 | 高频错误 |
382
+ |------|------|------|---------|
383
+ | `dimensions[].sort_order` | **number** | 整数 1、2、3 | ❌ 字符串(与 Part3 `sort_order` 相反) |
384
+ | `dimensions[].weight` | number | 整数,所有维度合 = 100 | ❌ 不等于 100 |
385
+ | `dimensions[].criteria` | string[] | 至少 2 个评分点 | ❌ 单条 / 逗号字符串 |
386
+ | `dimensions[].scoring_rule` | string | 一票否决嵌入末尾 | ❌ 全局 one_vote_veto 字段 |
387
+ | `dimensions[].code` | string | 英文语义编码 | ❌ 中文 |
388
+
389
+ ### 提交前断言
390
+
391
+ ```python
392
+ op = operations[0]
393
+ assert op["type"] == "replace_scoring_criteria_config"
394
+
395
+ config = op["data"]["config"]
396
+ assert "criteria_data" in config, "缺第 2 层 criteria_data 包装"
397
+
398
+ cd = config["criteria_data"]
399
+ for k in ["name", "description", "source_type", "total_weight", "tags", "dimensions"]:
400
+ assert cd.get(k) not in (None, "", []), f"criteria_data.{k} 空/缺失"
401
+
402
+ assert cd["source_type"] == "enterprise"
403
+ assert cd["total_weight"] == 100
404
+
405
+ dims = cd["dimensions"]
406
+ assert len(dims) >= 2
407
+ assert sum(d["weight"] for d in dims) == 100, "权重总和不等于 100"
408
+ for i, d in enumerate(dims):
409
+ for k in ["id", "code", "name", "description", "weight", "scoring_rule", "criteria"]:
410
+ assert d.get(k) not in (None, "", []), f"dim{i} missing {k}"
411
+ assert isinstance(d["sort_order"], int), f"dim{i} sort_order 必须是数字"
412
+ assert isinstance(d["criteria"], list) and len(d["criteria"]) >= 2
413
+ assert d["code"].isascii(), f"dim{i} code 必须是英文"
414
+ ```
415
+
416
+ ### 反面案例
417
+
418
+ ```json
419
+ ❌ 案例 A:只包 config 漏 criteria_data(平台会接受但存储错误)
420
+ {
421
+ "type": "replace_scoring_criteria_config",
422
+ "data": {
423
+ "config": {
424
+ "name": "...",
425
+ "dimensions": [...]
426
+ }
427
+ }
428
+ }
429
+ → 平台存为 {name, dimensions} 散在根,与正确结构不一致
430
+ → Step 7 闸门第 10.5 项不通过
431
+
432
+ ❌ 案例 B:dimensions.sort_order 写字符串
433
+ { "sort_order": "1" }
434
+ → 应该是数字 1(注意 Part3 是字符串,Part4 是数字)
435
+
436
+ ❌ 案例 C:一票否决写在全局
437
+ {
438
+ "one_vote_veto": [...]
439
+ }
440
+ → 应该嵌入各维度 scoring_rule 末尾
441
+ ```
442
+
443
+ ---
444
+
445
+ ## Part5 · 教练设置(固定模板)
446
+
447
+ ### 必做操作清单
448
+
449
+ | # | operation.type | 作用 |
450
+ |---|---------------|------|
451
+ | 1 | `update_basic` | 写入 6 项固定配置 |
452
+
453
+ ### 完整 JSON 模板(part5-operations.json)
454
+
455
+ ```json
456
+ [
457
+ {
458
+ "type": "update_basic",
459
+ "data": {
460
+ "min_practice_duration": 0,
461
+ "max_practice_duration": 0,
462
+ "max_practice_attempts": 10,
463
+ "passing_score": 60,
464
+ "completion_rule": "all_steps",
465
+ "ai_assistance_enabled": true,
466
+ "pass_difficulty": 2
467
+ }
468
+ }
469
+ ]
470
+ ```
471
+
472
+ > ⚠️ **6 项固定配置禁按场景调整**。字段名以实际成功发布的版本为准。Part5 不再同步 `closing_dialogue` / `golden_dialogue_description` / `key_points`(这些已在 Part1/Part3 同步)。
473
+
474
+ ### 提交前断言
475
+
476
+ ```python
477
+ op = operations[0]
478
+ assert op["type"] == "update_basic"
479
+ d = op["data"]
480
+ assert d["min_practice_duration"] == 0
481
+ assert d["max_practice_duration"] == 0
482
+ assert d["max_practice_attempts"] == 10
483
+ assert d["passing_score"] == 60
484
+ assert d["completion_rule"] == "all_steps"
485
+ assert d["ai_assistance_enabled"] is True
486
+ assert d["pass_difficulty"] == 2
487
+ ```
488
+
489
+ ---
490
+
491
+ ## 通用约束
492
+
493
+ ### CLI 参数固定值
494
+
495
+ - `--scenario-id <id>`(不是 `--scenario <id>`)
496
+ - apply 需要 `--idempotency-key <unique>`
497
+ - 每次 apply 后必须重新获取 `updated_at` 作为下次 `--base-updated-at`
498
+ - **v2.37:所有 CLI 输出一律 `> /tmp/xxx.json 2>/dev/null` 重定向**,禁止 `--pretty` 直出到对话。Python 从重定向文件提取字段,不回显 JSON 原文。
499
+ - **v2.37:apply 禁止用于验证**。验证数据用 `+get-scenario`,apply 后只从返回值提取 `updated_at`(`tail -1` 或 Python 提取),不回显 operations/snapshot_id。用 apply 回读环节会导致 `add_conversation_step` 重复添加。
500
+
501
+ ### 材料预处理铁律(v2.37 强化:一次成型)
502
+
503
+ 非结构化材料(PDF/DOCX/PPT)经 pdftotext 提取后:
504
+ 1. **一次成型写提炼稿**:pdftotext 提取到 `/tmp/` → **一次性** grep 定位 + sed 读取关键段落 → Write 落盘提炼稿到 `/tmp/xxx_refined.md`。**禁止分多轮 sed 回看**(每轮 sed 回看消耗 1-2 积分)。
505
+ 2. **原始材料全文不再进入后续 Part 上下文**——Part1-5 生成只读提炼稿
506
+ 3. 提炼稿只保留 Part1-5 所需结构化要素(业务背景/训练对象/话术/画像线索/异议/红线/评分线索)
507
+ 4. 提炼稿删除无关段落(目录/版权页/附录/重复章节)
508
+ 5. 提炼稿 ≤1500 字(硬上限),超了二次压缩只保留核心要素
509
+ 6. **提炼稿落盘后,后续 Part1-5 只 Read 这一个文件**,不再碰原始 PDF/DOCX
510
+
511
+ ### 后台静默规则(G1/G3)
512
+
513
+ 所有 CLI 错误(stderr / 非零退出 / 422 / 409)**禁止对用户展示**。AI 内部分析修正(最多 2 次重试),仍失败仅告知"Part N 同步异常"+ ≤50 字原因。
514
+
515
+ ### 输出过滤规则(v2.35 反压缩强化)
516
+
517
+ 后台 Python 脚本(build_*.py / fix_*.py / validate 等)的 print() 输出、JSON 文件大小、字符数统计、自查断言结果("✅ xxx")→ 🔇 后台静默,**禁止出现在对话消息中**。
518
+
519
+ **CLI 输出强制静默(v2.37 三次强化)**:
520
+ - **所有 soke-cli 命令**输出一律 `> /tmp/xxx.json 2>/dev/null` 重定向(create-scenario / list-role-avatars / list-role-voices / apply / get / publish / sync 全部重定向),**禁止 `--pretty` 直出到对话**
521
+ - preview/apply 命令一律 `2>/dev/null | tail -3`,只看结尾 3 行状态
522
+ - `+get-scenario` 回读一律 `> /tmp/xxx.json` 重定向,Python 只打印 `True/False` 布尔判断
523
+ - snapshot_id / updated_at / warnings / operations 回显**一律吞掉**
524
+ - **apply 禁止用于验证**(v2.37):apply 是写入操作,不是读取操作。用 apply 回读环节会导致 `add_conversation_step` 重复添加 → 需快照回滚 → 浪费 3-5 积分。验证用 `+get-scenario`。
525
+ - 仅失败时输出 ≤50 字原因
526
+
527
+ 替代方案:
528
+ - 成功 → 不展示任何细节,直接进入下一步
529
+ - 失败 → 仅展示"Part N 同步失败:≤50 字原因"
530
+ - 需要核对 → 仅展示差异摘要,不展示完整 JSON 或 CLI 原始输出
531
+
532
+ ### 发布确认弹窗(v2.27 新增,v2.37 知识包复用提炼稿)
533
+
534
+ Part5 同步后不直接发布。管线:Part5 apply → Step 6-8 后台验证 → Step 8.5 模板 8 弹窗"确认发布?" → 用户确认后执行 `+publish-scenario`。
535
+ 发布成功后展示完成摘要 → Step 10 模板 7 知识包弹窗(必须触发)。
536
+
537
+ > **v2.37 知识包复用规则**:知识包 Markdown source 直接复用材料提炼稿(`/tmp/xxx_refined.md`),**禁止从零重写**(内容已在上下文中,重写浪费 3-5 积分)。只需按知识包 entries 格式拆条目(entry_id / entry_type / source_id / title / content / source_refs / tags)。
538
+
539
+ ### 确认弹窗优先(G2)+ 聊天正文承载完整内容(v2.38)
540
+
541
+ 所有用户确认环节优先使用 `render_ui` QuestionForm;不可用时降级为文本编号。
542
+
543
+ **弹窗即时触发(v2.30)+ 聊天正文承载完整内容(v2.38)**:Part 完整内容在聊天正文中展示(编号列表组织,禁用 Markdown 表格),展示后紧接 AskUserQuestion 弹窗。弹窗仅做确认/调整选择——`question` 字段只写 ≤2 行引导语,`options` 只放「确认」「需要调整」等选择项。**禁止把 Part 完整内容塞进弹窗 question 字段**。
544
+
545
+ ### 沙箱绕过(G4)
546
+
547
+ WorkBuddy Bash 调用 soke-cli 必须设 `dangerouslyDisableSandbox: true`。
548
+
549
+ ---
550
+
551
+ ## 平台头像库
552
+
553
+ 正确路径前缀:`https://newsokeeditorcdn.soke.cn/public/ai/roles_avatars/`(❌ 错误:`/public/ai/avatar/`,存进去 UI 空白)。
554
+ 头像 URL 一律通过 `soke-cli ai-training +list-role-avatars` **重定向到 /tmp/avatars.json 后 Python 按性别/年龄关键词过滤 title 字段提取 url**(v2.37:禁止 `--pretty` 直出,禁止 `--gender`/`--age-group` 参数——CLI 不支持)。声音同理重定向到 `/tmp/voices.json` 后 Python 提取 `id`。
555
+
556
+ ---
557
+
558
+ ## JSON 字段类型硬规则(平台同步必读)
559
+
560
+ > 来源:`platform/sync-engine.md`(字段参考手册)。原则:**文档是什么类型,就严格按什么类型生成。**
561
+
562
+ ### string 字段:必须生成字符串
563
+
564
+ 多条内容用顿号、分号、编号或 `\n` 拼接为一个字符串,禁止写成数组。
565
+
566
+ 关键 string 字段:`name`、`description`、`key_points`、`role_data.name`、`role_data.description`、`role_data.avatar`、`role_data.communication_style`、`role_data.background`、`role_data.personality_type`、`role_data.personality`、`role_data.voice_id`、`ai_roles_overall_description`、`opening_dialogue`、`conversation_steps[].step_name`、`conversation_steps[].student_objective`、`conversation_steps[].ai_task`、`criteria_data.name`、`criteria_data.description`、`dimensions[].code`、`dimensions[].name`、`dimensions[].description`、`dimensions[].scoring_rule`
567
+
568
+ ### string[] 字段:只有明确数组字段才生成数组
569
+
570
+ 每条一个元素:`tags`、`conversation_knowledge_base_ids`、`scoring_knowledge_base_ids`、`role_data.tags`、`role_data.knowledge_level`、`role_data.taboos_objections`、`dimensions[].criteria`
571
+
572
+ ### number / boolean / null 字段
573
+
574
+ - number 不加引号:`weight`、`total_weight`、`max_rounds`、`max_practice_attempts`、`passing_score`、`pass_difficulty`、`dimensions[].sort_order`
575
+ - boolean 不加引号:`is_custom_role`、`is_custom_criteria`、`ai_assistance_enabled`
576
+ - null 写 `null`,不写空字符串或 `"null"`
577
+
578
+ ### 创建/更新差异
579
+
580
+ - 创建 `conversation_steps` 用 `ai_objective`;更新用 `ai_task`。
581
+ - 创建 `conversation_steps[].sort_order` 写字符串(`"1"`);评分维度 `sort_order` 写数字(`1`)。
582
+
583
+ ### 生成前自检
584
+
585
+ ```text
586
+ ☐ string 字段没有被写成数组或对象
587
+ ☐ string[] 字段没有被写成逗号分隔字符串
588
+ ☐ number 字段没有加引号
589
+ ☐ boolean 字段没有加引号
590
+ ☐ null 字段没有写成 "" 或 "null"
591
+ ☐ 创建/更新 sort_order 类型符合对应接口要求
592
+ ```
593
+
594
+ ---
595
+
596
+ ## 状态快照与缓存规则
597
+
598
+ > 来源:`platform/sync-engine.md`。创建型内部使用,不在聊天中输出。
599
+
600
+ ### state-snapshot.json 结构
601
+
602
+ ```json
603
+ {
604
+ "mode": "partwise",
605
+ "scenario_id": "scn_xxx",
606
+ "scenario_short": "b7730195",
607
+ "updated_at": "2026-07-10T01:40:58.216028Z",
608
+ "current_part": "part3",
609
+ "confirmed_data": { "part1": {}, "part2": {}, "part3": {}, "part4": {}, "part5": {} },
610
+ "applied": { "part1": true, "part2": true, "part3": false, "part4": false, "part5": false },
611
+ "cached": { "role_profile": {}, "scenario_type": "" }
612
+ }
613
+ ```
614
+
615
+ ### 依赖与回滚规则
616
+
617
+ - Part1 修改 → Part2-Part5 全部待复核
618
+ - Part2 修改 → 至少重检 Part3 与 Part5
619
+ - Part3 修改 → 至少重检 Part4 与 Part5
620
+ - Part4 修改 → 重检 Part5
621
+ - Part5 修改通常不反推前序 Part,但若改动通关分数/难度,需检查与 Part4 评分体系一致