scrum-skills 0.2.3 → 0.2.4

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 (70) hide show
  1. package/.agents/skills/scrum-planning/references/schema.md +3 -2
  2. package/README.md +15 -6
  3. package/assets/board/200.html +1 -1
  4. package/assets/board/404.html +1 -1
  5. package/assets/board/_nuxt/{BannxgAO.js → 0VBLkWnu.js} +1 -1
  6. package/assets/board/_nuxt/{C9Eg7sGC.js → BNKWWG8o.js} +1 -1
  7. package/assets/board/_nuxt/{BQSM1Ln0.js → BPTrRhcw.js} +1 -1
  8. package/assets/board/_nuxt/{B7foC6AH.js → BSov4ehT.js} +1 -1
  9. package/assets/board/_nuxt/BTxVIV74.js +1 -0
  10. package/assets/board/_nuxt/{D8NAsEfE.js → Bb3Limos.js} +1 -1
  11. package/assets/board/_nuxt/{CPfeOlrH.js → Bh7eUS6e.js} +1 -1
  12. package/assets/board/_nuxt/{DA0S9GHd.js → Bu60uYgs.js} +1 -1
  13. package/assets/board/_nuxt/{DiYBussm.js → BuuAjxsV.js} +1 -1
  14. package/assets/board/_nuxt/{BvaAl29K.js → C-GYjxwr.js} +3 -3
  15. package/assets/board/_nuxt/{DEBhVwtl.js → C9StZL3D.js} +1 -1
  16. package/assets/board/_nuxt/{ADHYAojV.js → CD0uJuyA.js} +1 -1
  17. package/assets/board/_nuxt/{C3ssq3NT.js → CHZ_IHOa.js} +1 -1
  18. package/assets/board/_nuxt/{C9lP5soO.js → CNbS93H9.js} +1 -1
  19. package/assets/board/_nuxt/{DVC07Kf9.js → CUnX_QKi.js} +1 -1
  20. package/assets/board/_nuxt/CeiBZIn1.js +95 -0
  21. package/assets/board/_nuxt/{Dpzighda.js → Cfk_R787.js} +1 -1
  22. package/assets/board/_nuxt/{DhkiugsE.js → ChJuu-Ky.js} +1 -1
  23. package/assets/board/_nuxt/{DwNOEVN_.js → CjRYYbsC.js} +1 -1
  24. package/assets/board/_nuxt/CuJUHLl8.js +1 -0
  25. package/assets/board/_nuxt/{BKgQBiDB.js → CvFE1CeN.js} +1 -1
  26. package/assets/board/_nuxt/{CAJYxF-h.js → CyAQx5wv.js} +1 -1
  27. package/assets/board/_nuxt/{BJ0EVa07.js → D1Yxjnz9.js} +1 -1
  28. package/assets/board/_nuxt/{CviJuCa4.js → D3YCAmfu.js} +1 -1
  29. package/assets/board/_nuxt/{joIhBaO-.js → D8Bpf7sE.js} +1 -1
  30. package/assets/board/_nuxt/{GzmVZqnA.js → DJUwhJ8T.js} +1 -1
  31. package/assets/board/_nuxt/{BXQZAVYz.js → DLkAKotw.js} +1 -1
  32. package/assets/board/_nuxt/{DQRn5Z3H.js → DaqxYsbV.js} +1 -1
  33. package/assets/board/_nuxt/{jCMbKsJ3.js → DhhR1iR4.js} +1 -1
  34. package/assets/board/_nuxt/{CL3OrPP7.js → DmKZi-Wo.js} +1 -1
  35. package/assets/board/_nuxt/{4FVXNzN-.js → DrbU50Zd.js} +1 -1
  36. package/assets/board/_nuxt/{DcWIG384.js → DsNkyZPc.js} +1 -1
  37. package/assets/board/_nuxt/{BCXs9rBJ.js → DwcwzwSx.js} +1 -1
  38. package/assets/board/_nuxt/{BuVRe79A.js → HrhQecsY.js} +1 -1
  39. package/assets/board/_nuxt/{Db4IStii.js → KhBLkIKl.js} +1 -1
  40. package/assets/board/_nuxt/{bXQUY80V.js → MTucdeiW.js} +1 -1
  41. package/assets/board/_nuxt/{CZPwmwA5.js → RJtjdZeG.js} +1 -1
  42. package/assets/board/_nuxt/{CTOFhZkc.js → RM4VQc4e.js} +1 -1
  43. package/assets/board/_nuxt/Vo4wMbnS.js +1 -0
  44. package/assets/board/_nuxt/builds/latest.json +1 -1
  45. package/assets/board/_nuxt/builds/meta/ecbff4a6-6538-49b0-9844-64f03ebd103a.json +1 -0
  46. package/assets/board/_nuxt/{entry.ChOvfapw.css → entry.nk2xQ-sa.css} +1 -1
  47. package/assets/board/_nuxt/{Cw7Z2eHM.js → fFGyRlCx.js} +1 -1
  48. package/assets/board/_nuxt/{-_kK9OzO.js → l05SqxhY.js} +1 -1
  49. package/assets/board/_nuxt/milestones.z-UuT44X.css +1 -0
  50. package/assets/board/_nuxt/{B5u1XkK4.js → obNw9aRV.js} +1 -1
  51. package/assets/board/_nuxt/pages.Bi6nErnd.css +1 -0
  52. package/assets/board/_nuxt/uGmbQYdY.js +1 -0
  53. package/assets/board/burndown/index.html +1 -1
  54. package/assets/board/epics/index.html +1 -1
  55. package/assets/board/gantt/index.html +1 -1
  56. package/assets/board/index.html +1 -1
  57. package/assets/board/milestones/index.html +1 -1
  58. package/bin/scrum-skills.mjs +34 -11
  59. package/package.json +40 -41
  60. package/templates/AGENTS.md +1 -1
  61. package/tools/ai.mjs +24 -2
  62. package/tools/validate.mjs +21 -7
  63. package/assets/board/_nuxt/BpR5gMZX.js +0 -95
  64. package/assets/board/_nuxt/CZc2Mypg.js +0 -1
  65. package/assets/board/_nuxt/DWxQkuvT.js +0 -1
  66. package/assets/board/_nuxt/DttMo5b5.js +0 -1
  67. package/assets/board/_nuxt/FCuSfyjP.js +0 -1
  68. package/assets/board/_nuxt/builds/meta/24603984-d514-4dff-badc-898a1fd5e770.json +0 -1
  69. package/assets/board/_nuxt/milestones.CVvAMKg4.css +0 -1
  70. package/assets/board/_nuxt/pages.DSSttn9g.css +0 -1
@@ -1 +1 @@
1
- <!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/BpR5gMZX.js"}}</script><link rel="stylesheet" href="/_nuxt/entry.ChOvfapw.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BpR5gMZX.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DK3Fl9T5.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/u88eXCXy.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DZo3dYLJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/51OWHj8c.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CsyY7ot8.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Baq-Hrpf.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DSaWoFHS.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/oXSDGTSr.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuBpFHLu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DsF2J4jZ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BJW3UkS7.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuVRe79A.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BXQZAVYz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CZc2Mypg.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/FCuSfyjP.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CK9_veoz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D8NAsEfE.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B43-KCi6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuOKDFiJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CviJuCa4.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B_SlFcWp.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DEBhVwtl.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BQSM1Ln0.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DwNOEVN_.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DhkiugsE.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/joIhBaO-.js"><script type="module" src="/_nuxt/BpR5gMZX.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/BvaAl29K.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DHihWhf5.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.BFmXOnCT.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/CoPhTDCT.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.BZ-DdjQ6.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/3G_ZLrk2.js"></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"24603984-d514-4dff-badc-898a1fd5e770",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1792961158551,false]</script></body></html>
1
+ <!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/CeiBZIn1.js"}}</script><link rel="stylesheet" href="/_nuxt/entry.nk2xQ-sa.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CeiBZIn1.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DK3Fl9T5.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/u88eXCXy.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DZo3dYLJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/51OWHj8c.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CsyY7ot8.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Baq-Hrpf.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DSaWoFHS.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/oXSDGTSr.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuBpFHLu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DsF2J4jZ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BJW3UkS7.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/HrhQecsY.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DLkAKotw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Vo4wMbnS.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CuJUHLl8.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CK9_veoz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Bb3Limos.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B43-KCi6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuOKDFiJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D3YCAmfu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B_SlFcWp.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/C9StZL3D.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BPTrRhcw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CjRYYbsC.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/ChJuu-Ky.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D8Bpf7sE.js"><script type="module" src="/_nuxt/CeiBZIn1.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/C-GYjxwr.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DHihWhf5.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.BFmXOnCT.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/CoPhTDCT.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.BZ-DdjQ6.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/3G_ZLrk2.js"></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"ecbff4a6-6538-49b0-9844-64f03ebd103a",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1792999430299,false]</script></body></html>
@@ -1 +1 @@
1
- <!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/BpR5gMZX.js"}}</script><link rel="stylesheet" href="/_nuxt/entry.ChOvfapw.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BpR5gMZX.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DK3Fl9T5.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/u88eXCXy.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DZo3dYLJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/51OWHj8c.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CsyY7ot8.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Baq-Hrpf.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DSaWoFHS.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/oXSDGTSr.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuBpFHLu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DsF2J4jZ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BJW3UkS7.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuVRe79A.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BXQZAVYz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CZc2Mypg.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/FCuSfyjP.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CK9_veoz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D8NAsEfE.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B43-KCi6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuOKDFiJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CviJuCa4.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B_SlFcWp.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DEBhVwtl.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BQSM1Ln0.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DwNOEVN_.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DhkiugsE.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/joIhBaO-.js"><script type="module" src="/_nuxt/BpR5gMZX.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/BvaAl29K.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DHihWhf5.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.BFmXOnCT.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/CoPhTDCT.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.BZ-DdjQ6.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/3G_ZLrk2.js"></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"24603984-d514-4dff-badc-898a1fd5e770",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1792961158552,false]</script></body></html>
1
+ <!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/CeiBZIn1.js"}}</script><link rel="stylesheet" href="/_nuxt/entry.nk2xQ-sa.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CeiBZIn1.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DK3Fl9T5.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/u88eXCXy.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DZo3dYLJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/51OWHj8c.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CsyY7ot8.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Baq-Hrpf.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DSaWoFHS.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/oXSDGTSr.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuBpFHLu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DsF2J4jZ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BJW3UkS7.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/HrhQecsY.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DLkAKotw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Vo4wMbnS.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CuJUHLl8.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CK9_veoz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Bb3Limos.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B43-KCi6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuOKDFiJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D3YCAmfu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B_SlFcWp.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/C9StZL3D.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BPTrRhcw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CjRYYbsC.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/ChJuu-Ky.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D8Bpf7sE.js"><script type="module" src="/_nuxt/CeiBZIn1.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/C-GYjxwr.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DHihWhf5.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.BFmXOnCT.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/CoPhTDCT.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.BZ-DdjQ6.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/3G_ZLrk2.js"></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"ecbff4a6-6538-49b0-9844-64f03ebd103a",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1792999430300,false]</script></body></html>
@@ -1 +1 @@
1
- <!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/BpR5gMZX.js"}}</script><link rel="stylesheet" href="/_nuxt/entry.ChOvfapw.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BpR5gMZX.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DK3Fl9T5.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/u88eXCXy.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DZo3dYLJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/51OWHj8c.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CsyY7ot8.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Baq-Hrpf.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DSaWoFHS.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/oXSDGTSr.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuBpFHLu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DsF2J4jZ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BJW3UkS7.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuVRe79A.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BXQZAVYz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CZc2Mypg.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/FCuSfyjP.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CK9_veoz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D8NAsEfE.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B43-KCi6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuOKDFiJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CviJuCa4.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B_SlFcWp.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DEBhVwtl.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BQSM1Ln0.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DwNOEVN_.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DhkiugsE.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/joIhBaO-.js"><script type="module" src="/_nuxt/BpR5gMZX.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/BvaAl29K.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DHihWhf5.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.BFmXOnCT.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/CoPhTDCT.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.BZ-DdjQ6.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/3G_ZLrk2.js"></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"24603984-d514-4dff-badc-898a1fd5e770",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1792961158552,false]</script></body></html>
1
+ <!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/CeiBZIn1.js"}}</script><link rel="stylesheet" href="/_nuxt/entry.nk2xQ-sa.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CeiBZIn1.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DK3Fl9T5.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/u88eXCXy.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DZo3dYLJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/51OWHj8c.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CsyY7ot8.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Baq-Hrpf.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DSaWoFHS.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/oXSDGTSr.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuBpFHLu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DsF2J4jZ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BJW3UkS7.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/HrhQecsY.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DLkAKotw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Vo4wMbnS.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CuJUHLl8.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CK9_veoz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Bb3Limos.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B43-KCi6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuOKDFiJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D3YCAmfu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B_SlFcWp.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/C9StZL3D.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BPTrRhcw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CjRYYbsC.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/ChJuu-Ky.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D8Bpf7sE.js"><script type="module" src="/_nuxt/CeiBZIn1.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/C-GYjxwr.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DHihWhf5.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.BFmXOnCT.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/CoPhTDCT.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.BZ-DdjQ6.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/3G_ZLrk2.js"></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"ecbff4a6-6538-49b0-9844-64f03ebd103a",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1792999430300,false]</script></body></html>
@@ -1 +1 @@
1
- <!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/BpR5gMZX.js"}}</script><link rel="stylesheet" href="/_nuxt/entry.ChOvfapw.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BpR5gMZX.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DK3Fl9T5.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/u88eXCXy.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DZo3dYLJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/51OWHj8c.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CsyY7ot8.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Baq-Hrpf.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DSaWoFHS.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/oXSDGTSr.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuBpFHLu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DsF2J4jZ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BJW3UkS7.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuVRe79A.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BXQZAVYz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CZc2Mypg.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/FCuSfyjP.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CK9_veoz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D8NAsEfE.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B43-KCi6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuOKDFiJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CviJuCa4.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B_SlFcWp.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DEBhVwtl.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BQSM1Ln0.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DwNOEVN_.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DhkiugsE.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/joIhBaO-.js"><script type="module" src="/_nuxt/BpR5gMZX.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/BvaAl29K.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DHihWhf5.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.BFmXOnCT.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/CoPhTDCT.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.BZ-DdjQ6.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/3G_ZLrk2.js"></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"24603984-d514-4dff-badc-898a1fd5e770",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1792961158553,false]</script></body></html>
1
+ <!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/CeiBZIn1.js"}}</script><link rel="stylesheet" href="/_nuxt/entry.nk2xQ-sa.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CeiBZIn1.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DK3Fl9T5.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/u88eXCXy.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DZo3dYLJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/51OWHj8c.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CsyY7ot8.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Baq-Hrpf.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DSaWoFHS.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/oXSDGTSr.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuBpFHLu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DsF2J4jZ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BJW3UkS7.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/HrhQecsY.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DLkAKotw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Vo4wMbnS.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CuJUHLl8.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CK9_veoz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Bb3Limos.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B43-KCi6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuOKDFiJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D3YCAmfu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B_SlFcWp.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/C9StZL3D.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BPTrRhcw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CjRYYbsC.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/ChJuu-Ky.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D8Bpf7sE.js"><script type="module" src="/_nuxt/CeiBZIn1.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/C-GYjxwr.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DHihWhf5.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.BFmXOnCT.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/CoPhTDCT.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.BZ-DdjQ6.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/3G_ZLrk2.js"></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"ecbff4a6-6538-49b0-9844-64f03ebd103a",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1792999430301,false]</script></body></html>
@@ -1 +1 @@
1
- <!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/BpR5gMZX.js"}}</script><link rel="stylesheet" href="/_nuxt/entry.ChOvfapw.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BpR5gMZX.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DK3Fl9T5.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/u88eXCXy.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DZo3dYLJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/51OWHj8c.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CsyY7ot8.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Baq-Hrpf.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DSaWoFHS.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/oXSDGTSr.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuBpFHLu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DsF2J4jZ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BJW3UkS7.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuVRe79A.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BXQZAVYz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CZc2Mypg.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/FCuSfyjP.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CK9_veoz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D8NAsEfE.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B43-KCi6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuOKDFiJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CviJuCa4.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B_SlFcWp.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DEBhVwtl.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BQSM1Ln0.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DwNOEVN_.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DhkiugsE.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/joIhBaO-.js"><script type="module" src="/_nuxt/BpR5gMZX.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/BvaAl29K.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DHihWhf5.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.BFmXOnCT.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/CoPhTDCT.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.BZ-DdjQ6.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/3G_ZLrk2.js"></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"24603984-d514-4dff-badc-898a1fd5e770",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1792961158552,false]</script></body></html>
1
+ <!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>敏捷看板</title><script type="importmap">{"imports":{"#entry":"/_nuxt/CeiBZIn1.js"}}</script><link rel="stylesheet" href="/_nuxt/entry.nk2xQ-sa.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CeiBZIn1.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DK3Fl9T5.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/u88eXCXy.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DZo3dYLJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/51OWHj8c.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CsyY7ot8.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Baq-Hrpf.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DSaWoFHS.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/oXSDGTSr.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuBpFHLu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DsF2J4jZ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BJW3UkS7.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/HrhQecsY.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/DLkAKotw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Vo4wMbnS.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CuJUHLl8.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CK9_veoz.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/Bb3Limos.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B43-KCi6.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BuOKDFiJ.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D3YCAmfu.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/B_SlFcWp.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/C9StZL3D.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/BPTrRhcw.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/CjRYYbsC.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/ChJuu-Ky.js"><link rel="modulepreload" as="script" crossorigin href="/_nuxt/D8Bpf7sE.js"><script type="module" src="/_nuxt/CeiBZIn1.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/_nuxt/C-GYjxwr.js"><link rel="prefetch" as="script" crossorigin href="/_nuxt/DHihWhf5.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-404.BFmXOnCT.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/CoPhTDCT.js"><link rel="prefetch" as="style" crossorigin href="/_nuxt/error-500.BZ-DdjQ6.css"><link rel="prefetch" as="script" crossorigin href="/_nuxt/3G_ZLrk2.js"></head><body><div id="__nuxt" class="isolate"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/",buildId:"ecbff4a6-6538-49b0-9844-64f03ebd103a",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1792999430300,false]</script></body></html>
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  /**
3
3
  * scrum-skills CLI(零依赖,node >= 18)
4
4
  * 命令:
@@ -12,7 +12,7 @@
12
12
  * scrum-skills validate [dir] 校验敏捷数据(默认当前目录)
13
13
  */
14
14
  import { cpSync, mkdirSync, existsSync, writeFileSync, readFileSync, readdirSync, statSync } from 'node:fs';
15
- import { join, resolve, dirname } from 'node:path';
15
+ import { join, resolve, dirname, basename } from 'node:path';
16
16
  import { spawnSync } from 'node:child_process';
17
17
  import { fileURLToPath } from 'node:url';
18
18
 
@@ -31,6 +31,20 @@ scsk 是 scrum-skills 的等价简写,如: scsk serve`;
31
31
  const [cmd, ...args] = process.argv.slice(2);
32
32
  const fail = msg => { console.error(`✘ ${msg}`); process.exit(1); };
33
33
 
34
+ /**
35
+ * 备份一个即将被覆盖的文件,返回备份路径。
36
+ * 名字带时间戳:老做法固定叫 `*.bak`,第二次 update 就把上一次的备份顶掉了,
37
+ * 而 AGENTS.md 几乎一定会被本地改过,备份互相覆盖等于没备份。
38
+ */
39
+ function backupFile(file) {
40
+ const d = new Date();
41
+ const pad = n => String(n).padStart(2, '0');
42
+ const stamp = `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
43
+ let target = `${file}.${stamp}.bak`;
44
+ for (let i = 2; existsSync(target); i += 1) target = `${file}.${stamp}-${i}.bak`;
45
+ cpSync(file, target);
46
+ return target;
47
+ }
34
48
  function init() {
35
49
  const force = args.includes('--force');
36
50
  const dir = resolve(args.find(a => !a.startsWith('--')) || process.cwd());
@@ -38,9 +52,9 @@ function init() {
38
52
 
39
53
  const agentsMd = join(dir, 'AGENTS.md');
40
54
  if (existsSync(agentsMd) && !force)
41
- fail(`目标目录已有 AGENTS.md。确认覆盖请加 --force(旧文件会备份为 AGENTS.md.bak)`);
42
- const backed = existsSync(agentsMd);
43
- if (backed) cpSync(agentsMd, `${agentsMd}.bak`);
55
+ fail(`目标目录已有 AGENTS.md。确认覆盖请加 --force(旧文件会先备份成 AGENTS.md.<时间戳>.bak)`);
56
+ const backed = existsSync(agentsMd) ? backupFile(agentsMd) : null;
57
+ if (backed) console.log(`· 已把现有 AGENTS.md 备份为 ${basename(backed)}`);
44
58
 
45
59
  cpSync(join(PKG_ROOT, '.agents'), join(dir, '.agents'), { recursive: true, force: true });
46
60
  writeFileSync(agentsMd, readFileSync(join(PKG_ROOT, 'templates/AGENTS.md'), 'utf8'));
@@ -65,7 +79,7 @@ function init() {
65
79
 
66
80
  console.log(`✔ 已初始化到 ${dir}
67
81
  - .agents/skills/ 四个敏捷 skill(planning / sprint / tdd / report)
68
- - AGENTS.md agent 入口纪律文件${backed ? '(旧文件已备份为 AGENTS.md.bak)' : ''}
82
+ - AGENTS.md agent 入口纪律文件${backed ? `(旧文件已备份为 ${basename(backed)})` : ''}
69
83
  - tools/validate.mjs 数据校验脚本
70
84
  - agile/ 三文件结构${created.length ? `(新建 ${created.join('、')})` : '(已存在,未覆盖)'}
71
85
 
@@ -104,6 +118,8 @@ function update() {
104
118
  fail(`${dir} 未初始化(找不到 .agents/ 与 AGENTS.md)。请先运行: scrum-skills init`);
105
119
 
106
120
  const added = [], changed = [], same = [];
121
+ // 相对路径 → 备份文件名,覆盖完统一提示怎么把本地改动捞回来
122
+ const backups = [];
107
123
  for (const { rel, src } of frameworkFiles()) {
108
124
  const dest = join(dir, rel);
109
125
  const srcText = readFileSync(src, 'utf8');
@@ -114,19 +130,26 @@ function update() {
114
130
  if (readFileSync(dest, 'utf8') === srcText) { same.push(rel); continue; }
115
131
  changed.push(rel);
116
132
  if (!dryRun) {
117
- cpSync(dest, `${dest}.bak`); // 覆盖前备份,本地自定义不丢
133
+ const bak = backupFile(dest); // 覆盖前备份,本地自定义不丢
134
+ backups.push({ rel, bak: basename(bak) });
118
135
  writeFileSync(dest, srcText);
119
136
  }
120
137
  }
121
138
 
122
139
  const verb = dryRun ? '(dry-run,未写入)' : '';
140
+ const bakLines = backups.map(b => ` - ${b.rel} 的旧版本 → ${b.bak}`).join('\n');
123
141
  console.log(`✔ skill 框架文件更新完成${verb} — ${dir}
124
142
  - 新增 ${added.length} 个${added.length ? `: ${added.join(', ')}` : ''}
125
- - 更新 ${changed.length} 个(旧文件备份为 *.bak)${changed.length ? `: ${changed.join(', ')}` : ''}
143
+ - 更新 ${changed.length} 个${changed.length ? `: ${changed.join(', ')}` : ''}
126
144
  - 未变 ${same.length} 个
127
- - agile/ 数据目录未做任何改动
128
-
129
- ${changed.length ? '提示: 更新会覆盖目标项目里对框架文件的本地修改(已备份 *.bak)。若目标项目自定义过 skill,请 diff 对比后手动合并。' : '已是最新,无需操作。'}`);
145
+ - agile/ 数据目录未做任何改动${bakLines ? `\n - 覆盖前已备份${bakLines.replace(/^ {2}/gm, '\n ')}` : ''}
146
+
147
+ ${backups.length
148
+ ? `提示: 框架文件是整篇覆盖的,你在这几个文件里的本地改动都在上面的备份里。
149
+ 让 agent 助手(CodeBuddy / Claude Code 等)合并回来即可,直接说:
150
+ 「对比 ${backups[0].rel} 与 ${backups[0].bak},把我的本地改动合并回来」${backups.length > 1 ? `\n (其余 ${backups.length - 1} 个文件同理,备份文件名见上方)` : ''}
151
+ 确认合并无误后再删掉备份。AGENTS.md 是 agent 的入口纪律文件,先合并它、再让它去改别的文件最稳。`
152
+ : '已是最新,无需操作。'}`);
130
153
  }
131
154
 
132
155
  function runTool(script, needPort) {
package/package.json CHANGED
@@ -1,41 +1,40 @@
1
- {
2
- "name": "scrum-skills",
3
- "version": "0.2.3",
4
- "description": "结构化敏捷开发管理 skills + CLI:AI 对话产出结构化敏捷数据,TDD 驱动实施,Nuxt 看板可视化",
5
- "type": "module",
6
- "keywords": [
7
- "agile",
8
- "scrum",
9
- "sprint",
10
- "tdd",
11
- "kanban",
12
- "gantt",
13
- "burndown",
14
- "skills",
15
- "cli"
16
- ],
17
- "bin": {
18
- "scrum-skills": "./bin/scrum-skills.mjs",
19
- "scsk": "./bin/scrum-skills.mjs"
20
- },
21
- "scripts": {
22
- "validate": "node tools/validate.mjs",
23
- "serve": "node tools/serve.mjs",
24
- "test": "node --test",
25
- "dev": "pnpm --dir apps/board run dev",
26
- "build": "node scripts/build-board.mjs",
27
- "prepublishOnly": "node scripts/build-board.mjs"
28
- },
29
- "files": [
30
- "bin/",
31
- "tools/",
32
- "templates/",
33
- ".agents/",
34
- "assets/",
35
- "docs/"
36
- ],
37
- "engines": {
38
- "node": ">=18"
39
- },
40
- "license": "MIT"
41
- }
1
+ {
2
+ "name": "scrum-skills",
3
+ "version": "0.2.4",
4
+ "description": "结构化敏捷开发管理 skills + CLI:AI 对话产出结构化敏捷数据,TDD 驱动实施,Nuxt 看板可视化",
5
+ "type": "module",
6
+ "keywords": [
7
+ "agile",
8
+ "scrum",
9
+ "sprint",
10
+ "tdd",
11
+ "kanban",
12
+ "gantt",
13
+ "burndown",
14
+ "skills",
15
+ "cli"
16
+ ],
17
+ "bin": {
18
+ "scrum-skills": "./bin/scrum-skills.mjs",
19
+ "scsk": "./bin/scrum-skills.mjs"
20
+ },
21
+ "files": [
22
+ "bin/",
23
+ "tools/",
24
+ "templates/",
25
+ ".agents/",
26
+ "assets/",
27
+ "docs/"
28
+ ],
29
+ "engines": {
30
+ "node": ">=18"
31
+ },
32
+ "license": "MIT",
33
+ "scripts": {
34
+ "validate": "node tools/validate.mjs",
35
+ "serve": "node tools/serve.mjs",
36
+ "test": "node --test",
37
+ "dev": "pnpm --dir apps/board run dev",
38
+ "build": "node scripts/build-board.mjs"
39
+ }
40
+ }
@@ -32,7 +32,7 @@
32
32
 
33
33
  ## 状态机(摘要)
34
34
 
35
- - story: `draft → ready → in-progress → review → done`
35
+ - story: `draft → ready → in-progress → review → done`;不做就走 `cancelled`(已取消,终态,不要求验收与任务全 done)
36
36
  - task: `todo → red → green → refactored → done`(只能前进;task 状态编码了 TDD 阶段)
37
37
  - 详细规则与硬约束见 `.agents/skills/scrum-planning/references/schema.md`。
38
38
 
package/tools/ai.mjs CHANGED
@@ -8,6 +8,8 @@
8
8
  * 边收 SSE 边把 text / reasoning / tool 事件吐给前端,浏览器不必碰 Key 也不受 CORS 限制。
9
9
  * 3. 工具循环:模型要 search_agile / update_agile 就执行,结果回灌再来一轮;
10
10
  * 到轮数上限强制收口(最后一轮不带工具),否则模型会一直调下去。
11
+ * 4. 多模态:前端可以把图片按 OpenAI 的 image_url 一起塞进 user content 数组,
12
+ * 这里原样透传;图片没有文字可估,按 IMAGE_TOKEN_ESTIMATE 计入上下文预算。
11
13
  *
12
14
  * 审核策略(reviewMode)在这里落地:manual 只调 tools.propose 产待审变更,
13
15
  * auto 直接 tools.patch 落盘(写入方自己带校验与回滚)。
@@ -42,6 +44,8 @@ export const BASE_SYSTEM = [
42
44
  '2. 不要凭空编 id、状态、日期、人名,也不要造测试数据。',
43
45
  '3. 改数据前用一句话说明要改什么,改完说明改了哪几条。',
44
46
  '4. 用简体中文,直接给结论:不复述问题、不做自我介绍、不寒暄。',
47
+ '5. 故事状态只有 draft / ready / in-progress / review / done / cancelled(已取消)这六种:'
48
+ + 'cancelled 是终态,表示这事不做了,要在回答里说清为什么取消;不做了的故事就标 cancelled,不要塞进 done 充数。',
45
49
  ].join('\n');
46
50
 
47
51
  export const DEFAULT_CONFIG = {
@@ -123,7 +127,21 @@ export function estimateTokens(text) {
123
127
  return cjk * 0.7 + rest / 4;
124
128
  }
125
129
 
126
- const costOf = messages => messages.reduce((sum, m) => sum + estimateTokens(m.content) + 8, 0);
130
+ /**
131
+ * 一张图在请求里没有文字可估,按固定额度算。
132
+ * 不估(当成 0)会让「塞一堆截图」的对话永远不触发裁剪,请求体越滚越大直到接口 413;
133
+ * 估得偏高则是安全的:多裁几轮老对话,总比请求发不出去强。
134
+ */
135
+ export const IMAGE_TOKEN_ESTIMATE = 800;
136
+
137
+ const contentCost = content => (Array.isArray(content)
138
+ ? content.reduce(
139
+ (sum, part) => sum + (part?.type === 'image_url' ? IMAGE_TOKEN_ESTIMATE : estimateTokens(part?.text ?? '')),
140
+ 0,
141
+ )
142
+ : estimateTokens(content));
143
+
144
+ const costOf = messages => messages.reduce((sum, m) => sum + contentCost(m.content) + 8, 0);
127
145
 
128
146
  /**
129
147
  * 上下文预算:保留系统提示词与最后一块(当前提问),从最早处整块丢弃。
@@ -328,7 +346,11 @@ export function createAiService({ root, store = defaultStore, token = '', tools,
328
346
  });
329
347
  if (!response.ok) {
330
348
  const detail = await response.text().catch(() => '');
331
- yield { type: 'error', message: `模型接口返回 ${response.status}:${detail.slice(0, 300) || response.statusText}` };
349
+ // 带图被拒最常见的原因是模型不是多模态:DeepSeek 的 chat / reasoner 都不收 image_url。
350
+ // 不点破的话用户只看到一行 400,会以为是 Key 或网络问题。
351
+ const withImages = convo.some(m => Array.isArray(m.content) && m.content.some(p => p?.type === 'image_url'));
352
+ const hint = withImages ? '(这一轮带了图片:当前模型可能不支持图片输入,请在设置里换成支持视觉模型的接口,或去掉图片再发)' : '';
353
+ yield { type: 'error', message: `模型接口返回 ${response.status}:${detail.slice(0, 300) || response.statusText}${hint}` };
332
354
  return;
333
355
  }
334
356
 
@@ -50,7 +50,9 @@ const sprints = Array.isArray(sprintsFile.sprints) ? sprintsFile.sprints : [];
50
50
  const milestones = Array.isArray(sprintsFile.milestones) ? sprintsFile.milestones : [];
51
51
  const journals = Array.isArray(journalFile.journals) ? journalFile.journals : [];
52
52
 
53
- const STORY_FLOW = ['draft', 'ready', 'in-progress', 'review', 'done'];
53
+ const STORY_FLOW = ['draft', 'ready', 'in-progress', 'review', 'done', 'cancelled'];
54
+ // 终态:done 与 cancelled 都不再往前走,也不再要求验收 / 任务全部做完
55
+ const STORY_TERMINAL = ['done', 'cancelled'];
54
56
  const TASK_FLOW = ['todo', 'red', 'green', 'refactored', 'done'];
55
57
  const EPIC_FLOW = ['draft', 'active', 'done', 'cancelled'];
56
58
  const MILESTONE_FLOW = ['planned', 'at-risk', 'reached', 'missed'];
@@ -136,7 +138,8 @@ for (const s of stories) {
136
138
  else if (!(epicById.get(epicId).stories ?? []).includes(id))
137
139
  err(`story ${id}: 挂在 ${epicId} 上,但该 epic 的 stories 里没有它(双向引用不一致)`);
138
140
 
139
- if (!STORY_FLOW.includes(status) && status !== 'cancelled') err(`story ${id}: 非法状态 ${status}`);
141
+ if (!STORY_FLOW.includes(status))
142
+ err(`story ${id}: 非法状态 ${status}(合法:${STORY_FLOW.join('/')})`);
140
143
  if (!Number.isFinite(points)) err(`story ${id}: points 必须是数字`);
141
144
  else if (![1, 2, 3, 5, 8, 13].includes(points)) warn(`story ${id}: points ${points} 不在斐波那契序列`);
142
145
 
@@ -153,7 +156,8 @@ for (const s of stories) {
153
156
  }
154
157
  }
155
158
 
156
- if ((status === 'ready' || STORY_FLOW.indexOf(status) > 1) && (!acceptance || acceptance.length === 0))
159
+ // 取消掉的故事不会再交付,别逼着为它补验收标准
160
+ if (['ready', 'in-progress', 'review', 'done'].includes(status) && (!acceptance || acceptance.length === 0))
157
161
  err(`story ${id}: 状态 ${status} 但验收标准为空`);
158
162
  for (const [i, a] of (acceptance ?? []).entries()) {
159
163
  if (!a.given || !a.when || !a.then) err(`story ${id}: 第 ${i + 1} 条验收标准缺 given/when/then`);
@@ -163,7 +167,8 @@ for (const s of stories) {
163
167
  if (!hit) err(`story ${id}: 第 ${i + 1} 条验收的 verifyBy ${tid} 不存在`);
164
168
  else if (hit.story.id !== id) err(`story ${id}: 第 ${i + 1} 条验收的 verifyBy ${tid} 属于 ${hit.story.id}`);
165
169
  }
166
- if (!(a.verifyBy ?? []).length && status !== 'draft') warn(`story ${id}: 第 ${i + 1} 条验收没有 verifyBy(没绑定验证任务)`);
170
+ if (!(a.verifyBy ?? []).length && !['draft', 'cancelled'].includes(status))
171
+ warn(`story ${id}: 第 ${i + 1} 条验收没有 verifyBy(没绑定验证任务)`);
167
172
  }
168
173
 
169
174
  // 阻塞 / 依赖
@@ -175,7 +180,9 @@ for (const s of stories) {
175
180
  if (!s.blocked.reason) err(`story ${id}: blocked 缺少 reason(堵在哪要说清)`);
176
181
  if (!DATE_RE.test(s.blocked.since ?? '')) err(`story ${id}: blocked.since 格式应为 YYYY-MM-DD`);
177
182
  if (status === 'done') err(`story ${id}: 已 done 却还标着 blocked`);
178
- if (sprintId) warn(`story ${id}: 处于 ${sprintId} 但被阻塞(${s.blocked.reason}),站会必须处理`);
183
+ if (status === 'cancelled') err(`story ${id}: 已取消却还标着 blocked(不做了就别再挂着阻塞)`);
184
+ if (sprintId && !STORY_TERMINAL.includes(status))
185
+ warn(`story ${id}: 处于 ${sprintId} 但被阻塞(${s.blocked.reason}),站会必须处理`);
179
186
  }
180
187
 
181
188
  // 范围变更标记
@@ -191,7 +198,8 @@ for (const s of stories) {
191
198
  if (!sp) err(`story ${id}: sprintId ${sprintId} 不存在`);
192
199
  else if (!(sp.stories ?? []).includes(id))
193
200
  err(`story ${id}: 指向 ${sprintId},但该 sprint 的 stories 里没有它(双向引用不一致)`);
194
- if (!acceptance || acceptance.length === 0) err(`story ${id}: 已进 sprint 但无验收标准(不满足 ready)`);
201
+ if (status !== 'cancelled' && (!acceptance || acceptance.length === 0))
202
+ err(`story ${id}: 已进 sprint 但无验收标准(不满足 ready)`);
195
203
  }
196
204
 
197
205
  if (s.schedule) {
@@ -230,8 +238,14 @@ for (const sp of sprints) {
230
238
  const st = storyById.get(sid);
231
239
  if (!st) { err(`sprint ${sp.id}: 引用 story ${sid} 不存在`); continue; }
232
240
  if (st.sprintId !== sp.id) err(`sprint ${sp.id}: story ${sid} 的 sprintId 是 ${st.sprintId},双向引用不一致`);
241
+ if (st.status === 'cancelled')
242
+ warn(`story ${sid}: 已取消但仍排在 ${sp.id} 里,建议从迭代移出(点数已不计入承诺)`);
233
243
  }
234
- const committed = (sp.stories ?? []).reduce((a, sid) => a + (storyById.get(sid)?.points ?? 0), 0);
244
+ // 已取消的故事不再占迭代容量:承诺点数只算还可能交付的
245
+ const committed = (sp.stories ?? []).reduce((a, sid) => {
246
+ const st = storyById.get(sid);
247
+ return st && st.status !== 'cancelled' ? a + (st.points ?? 0) : a;
248
+ }, 0);
235
249
  if (Number.isFinite(sp.capacity) && committed > sp.capacity)
236
250
  warn(`sprint ${sp.id}: 承诺 ${committed} 点超过容量 ${sp.capacity} 点`);
237
251
  if (sp.start <= today && sp.end >= today) active++;