dsh-sa-workbench 0.1.27 → 0.1.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # SA 工作台 · dsh-sa-workbench
2
2
 
3
- 在 DeepSeek Harness 桌面版插件页输入 `dsh-sa-workbench` 安装。已安装后通过同一插件页检查、选择并更新版本,无须安装 EXE。安装名在首次公开发布后可用;测试构建与正式发布记录以仓库交付说明为准。
3
+ 在 DeepSeek Harness 桌面版插件页输入 `dsh-sa-workbench` 安装。已安装后通过同一插件页检查、选择并更新版本,无须安装 EXE。公开 npm 安装名已可用;正式版本与验收记录以仓库交付说明为准。
4
4
 
5
5
  需求总览、版本计划、业务资料上传、需求/高阶方案/PRD/原型、节点 Skill、文档历史和交付归档在一个包里同步更新。复用 DSH 的模型、会话、权限和工具,不包含模型凭据或业务资料。
6
6
 
7
- 首次打开 SA 工作台会进入目录设置。选择资料工作目录,保存后按提示完整重启 DSH。默认提供的目录也可以直接确认。插件更新、回退和卸载保留工作目录及配置。
7
+ 首次打开 SA 工作台会进入目录设置。确认默认目录后直接进入需求总览;选择其他工作目录后,按提示完整退出并重新打开 DSH。新用户默认亮色,用户主动选择的暗色偏好保留。插件更新、回退和卸载保留工作目录及配置。
8
+
9
+ 工作台统一提供需求、知识库、归档库与工作方法导航。需求总览支持表格和看板;详情页以阶段图标和分段连线导航,未生成时展示交付预览及开始操作。助手按需展开,复用原需求会话。文档尚未保存时切换顶部页面,会提示继续编辑或放弃修改后离开。
8
10
 
9
11
  需要 Node 24.9+ 运行时与 DSH 0.2.2-rc.1 系列;当前实机验证版本以发布验收文档为准,版本范围不代表所有未来宿主均已测试。
10
12
 
package/client.js CHANGED
@@ -27,7 +27,7 @@ window.__ModuleLoader__.load({
27
27
 
28
28
  var PANEL_KEY = 'pm'
29
29
  var API = '/pm/api'
30
- function saAppearance(){try{return localStorage.getItem('sa-workbench-appearance')==='light'?'light':'dark'}catch(err){return 'dark'}}
30
+ function saAppearance(){try{return localStorage.getItem('sa-workbench-appearance')==='dark'?'dark':'light'}catch(err){return 'light'}}
31
31
  function setSaAppearance(next){try{localStorage.setItem('sa-workbench-appearance',next)}catch(err){}pmBus.set({appearance:next})}
32
32
  function bindSaShell(appearance){
33
33
  if(typeof document==='undefined')return function(){};
@@ -36,7 +36,7 @@ window.__ModuleLoader__.load({
36
36
  return function(){if(previousShell===undefined)delete root.dataset.saShell;else root.dataset.saShell=previousShell;if(previousAppearance===undefined)delete root.dataset.saAppearance;else root.dataset.saAppearance=previousAppearance}
37
37
  }
38
38
  function toggleSaAppearance(){var next=(pmBus.state.appearance || saAppearance())==='dark'?'light':'dark';try{localStorage.setItem('sa-workbench-appearance',next)}catch(err){}pmBus.set({appearance:next})}
39
- var CLIENT_VERSION = '0.1.27'
39
+ var CLIENT_VERSION = '0.1.29'
40
40
 
41
41
  // A session may disappear or fail to open after selection. Keep failures
42
42
  // inside the conversation pane, and release even a rejected/pending ref.
@@ -1788,6 +1788,7 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
1788
1788
  edit: 'M12 20H4V12M9 15l3-.5L21 6l-3-3-8.5 9z', list: 'M8 5h13M8 12h13M8 19h13M3 5h.01M3 12h.01M3 19h.01',
1789
1789
  chat: 'M4 4h16v12H9l-5 4z', expand: 'M8 3H3v5M16 3h5v5M21 16v5h-5M3 16v5h5', focus: 'M4 4h16v16H4zM15 4v16', history: 'M3 10a9 9 0 1 1 2 9M3 3v7h7M12 7v5l3 2',
1790
1790
  check: 'M5 12l4 4L19 6', link: 'M10 13a5 5 0 0 0 7 0l4-4a5 5 0 0 0-7-7l-2 2M14 11a5 5 0 0 0-7 0l-4 4a5 5 0 0 0 7 7l2-2',
1791
+ users: 'M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75',
1791
1792
  settings: 'M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8M10 3h4l1 3 3 1 3 3v4l-3 1-1 3-3 3h-4l-1-3-3-1-3-3v-4l3-1 1-3z',
1792
1793
  folder: 'M3 7V5a2 2 0 0 1 2-2h5l2 3h7a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z',
1793
1794
  route: 'M4 5h16M4 12h16M4 19h16M7 3v4M12 10v4M17 17v4',
@@ -1967,8 +1968,10 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
1967
1968
  var progressGradientId=useState(function(){return 'pmw-progress-blue-'+(++overviewGradientSequence)})[0]
1968
1969
  var planServiceReady=!!(props.releases && Array.isArray(props.releases.plans))
1969
1970
  var rs=useState(props.releases || {currentVersion:null,plans:[],fingerprint:null}),releases=rs[0],setReleases=rs[1]
1970
- var versionSt=useState(function(){return props.releases && props.releases.currentVersion || '*'}),version=versionSt[0],setVersion=versionSt[1]
1971
- var statusSt=useState('all'),status=statusSt[0],setStatus=statusSt[1],querySt=useState(''),query=querySt[0],setQuery=querySt[1]
1971
+ var versionSt=useState(function(){return pmBus.overviewContext ? pmBus.overviewContext.version : props.releases && props.releases.currentVersion || '*'}),version=versionSt[0],setVersion=versionSt[1]
1972
+ var statusSt=useState(pmBus.overviewContext && pmBus.overviewContext.status || 'all'),status=statusSt[0],setStatus=statusSt[1],querySt=useState(pmBus.overviewContext && pmBus.overviewContext.query || ''),query=querySt[0],setQuery=querySt[1]
1973
+ var presentationSt=useState(pmBus.overviewContext && pmBus.overviewContext.presentation || 'table'),presentation=presentationSt[0],setPresentation=presentationSt[1]
1974
+ useEffect(function(){pmBus.overviewContext={version:version,status:status,query:query,presentation:presentation}},[version,status,query,presentation])
1972
1975
  var sortSt=useState('updated'),sort=sortSt[0],setSort=sortSt[1],choiceSt=useState(false),choice=choiceSt[0],setChoice=choiceSt[1]
1973
1976
  var infoSt=useState(null),info=infoSt[0],setInfo=infoSt[1],pickerRef=React.useRef(null),pickerButton=React.useRef(null)
1974
1977
  var hs=useState(null),help=hs[0],setHelp=hs[1],helpRef=React.useRef(null),ims=useState(false),importOpen=ims[0],setImportOpen=ims[1]
@@ -2020,10 +2023,10 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
2020
2023
  e('section',{className:'pmw-summary','aria-label':'本版需求统计'},e('div',{className:'pmw-summary__metrics'},statistic('total','需求总数',model.total),statistic('done','已完成',model.completed),statistic('running','进行中',model.running),statistic('waiting','待启动',model.waiting))),
2021
2024
  e('div',{className:'pmw-overview__panels'},train),
2022
2025
  e('section',{className:'pmw-overview__tablepanel','aria-label':'需求列表'},
2023
- e('div',{className:'pmw-overview__boardhead'},e('span',{className:'pmw-panel-icon'},e(UiIcon,{name:'list'})),e('h2',null,'需求地图'),e('span',{role:'status'},model.rows.length)),
2026
+ e('div',{className:'pmw-overview__boardhead'},e('span',{className:'pmw-panel-icon'},e(UiIcon,{name:'list'})),e('h2',null,'需求地图'),e('span',{role:'status'},model.rows.length),e('div',{className:'sa-presentation',role:'group','aria-label':'需求展示方式'},[['table','表格'],['board','看板']].map(function(p){return e('button',{key:p[0],'aria-pressed':presentation===p[0],onClick:function(){setPresentation(p[0])}},p[1])}))),
2024
2027
  e('div',{className:'pmw-overview__tools'},e('div',{className:'pmw-overview__views',role:'group','aria-label':'按需求状态筛选'},tabs.map(function(t){return e('button',{key:t.id,'aria-pressed':status===t.id,onClick:function(){setStatus(t.id)}},t.title,e('span',null,t.count))})),e('label',{className:'pmw-overview__search'},e(UiIcon,{name:'search'}),e('input',{'aria-label':'搜索需求、编码、负责人或应用',placeholder:'搜索需求、负责人或应用',value:query,onChange:function(ev){setQuery(ev.target.value)}}),query && e('button',{'aria-label':'清除总览搜索',onClick:function(){setQuery('')}},e(UiIcon,{name:'close'})))),
2025
2028
  props.requirements.length===0?e('div',{className:'pmw-overview__empty'},e(UiIcon,{name:'grid'}),e('h2',null,'新建第一条需求'),e('button',{className:'pmw-btn pmw-btn--primary',onClick:props.onCreate},'新建需求')):model.rows.length===0?e('div',{className:'pmw-overview__empty'},e(UiIcon,{name:'search'}),e('h2',null,'当前范围没有需求'),e('button',{className:'pmw-btn',onClick:function(){setStatus('all');setQuery('')}},'清除状态与搜索筛选')):
2026
- e('div',{className:'pmw-requirements-scroll'},e('table',{className:'pmw-requirements'},e('thead',null,e('tr',null,['需求','状态','业务方','SA','前端开发','后端开发','测试','外部应用','操作'].map(function(label){return e('th',{key:label,scope:'col'},label)}))),e('tbody',null,model.rows.map(card))))),
2029
+ presentation==='board'?e(RequirementKanban,{requirements:model.rows,onOpen:function(req){setInfo({requirement:req,editing:false})}}):e('div',{className:'pmw-requirements-scroll'},e('table',{className:'pmw-requirements'},e('thead',null,e('tr',null,['需求','状态','业务方','SA','前端开发','后端开发','测试','外部应用','操作'].map(function(label){return e('th',{key:label,scope:'col'},label)}))),e('tbody',null,model.rows.map(card))))),
2027
2030
  help && e('div',{className:'pmw-overview__help',ref:helpRef,role:'dialog','aria-label':help.title,style:{left:help.left,top:help.top}},e('h3',null,help.title),e('p',null,help.text)),
2028
2031
  importOpen && e(ReleaseImportDialog,{onClose:function(){setImportOpen(false)},onSaved:function(value){setReleases(value);props.onRefresh()}}),
2029
2032
  info && e(RequirementInfoDialog,{requirement:info.requirement,startEditing:info.editing,onOpen:props.onOpen,onClose:function(){setInfo(null)},onSaved:props.onRefresh}))
@@ -2338,7 +2341,7 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
2338
2341
  // 全局选择总线:左轨(常驻)与 SA 总览页(main 面板)共享选中态
2339
2342
  // -----------------------------------------------------------------------
2340
2343
  var pmBus = {
2341
- state: { selectedId: null, activeSessionId: null, nav: null, selectedVersion: null, tabs: {}, scrolls: {}, files: {}, focus: false },
2344
+ state: { selectedId: null, activeSessionId: null, nav: 'home', selectedVersion: null, tabs: {}, scrolls: {}, files: {}, focus: true },
2342
2345
  listeners: [],
2343
2346
  set: function (patch) {
2344
2347
  var changed = false
@@ -2642,9 +2645,9 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
2642
2645
  )
2643
2646
  }
2644
2647
 
2645
- return e('div', { className: 'pmw-nav', 'data-sa-appearance':bus.appearance || saAppearance() },
2648
+ return e('div', { className: 'pmw-nav', 'data-sa-appearance':bus.appearance || saAppearance(), 'data-sa-setup':data.data && (data.data.setupRequired || data.data.restartRequired)?'true':'false' },
2646
2649
  e('div',{className:'glass-workspace'},e('span',{className:'glass-workspace-icon'},e(UiIcon,{name:'grid'})),e('span',null,e('strong',{className:'glass-workspace-title'},data.data && data.data.workspace && data.data.workspace.title || '项目工作空间'),e('small',null,'SA 项目工作空间'))),
2647
- e('div', { className: 'pmw-nav__top' },
2650
+ e('style',null,'.pmw-nav[data-sa-setup="true"] .pmw-nav__top,.pmw-nav[data-sa-setup="true"] .pmw-nav__scroll{display:none}.pmw-nav[data-sa-setup="true"]:after{content:"完成目录设置后,即可开始使用工作台";padding:20px;font-size:13px;line-height:1.7;opacity:.7}'),e('div', { className: 'pmw-nav__top' },
2648
2651
  e('button', {
2649
2652
  className: 'pmw-btn pmw-btn--primary pmw-nav__new',
2650
2653
  onClick: function () {
@@ -2867,11 +2870,11 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
2867
2870
  e('div',{className:'pmw-dialog__foot'},e('button',{className:'pmw-btn',onClick:props.onCancel},'取消'),e('button',{className:'pmw-btn pmw-btn--primary',disabled:loading || !value || !value.current,onClick:function(){props.onSelect(value.current)}},'选择此目录'))))
2868
2871
  }
2869
2872
 
2870
- function SettingsPanel() {
2873
+ function SettingsPanel(props) {
2871
2874
  var route=usePmBus()
2872
2875
  var ds=useState(null), data=ds[0], setData=ds[1]
2873
2876
  var fs=useState(null), draft=fs[0], setDraft=fs[1]
2874
- var ts=useState(pmBus.state.settingsTab || 'directories'), tab=ts[0], setTab=ts[1]
2877
+ var ts=useState(props && props.onboarding ? 'directories' : pmBus.state.settingsTab || 'directories'), tab=ts[0], setTab=ts[1]
2875
2878
  var ns=useState(pmBus.state.settingsNode || 'intake'), node=ns[0], setNode=ns[1]
2876
2879
  var ss=useState(null), skill=ss[0], setSkill=ss[1]
2877
2880
  var cs=useState(''), content=cs[0], setContent=cs[1]
@@ -2897,26 +2900,26 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
2897
2900
  finally {if(mounted.current)setPicking(null)}
2898
2901
  }
2899
2902
  useEffect(function(){load()},[])
2900
- useEffect(function(){setTab(route.settingsTab || 'directories');setNode(route.settingsNode || 'intake')},[route.settingsTab,route.settingsNode])
2903
+ useEffect(function(){setTab(props && props.onboarding ? 'directories' : route.settingsTab || 'directories');setNode(route.settingsNode || 'intake')},[route.settingsTab,route.settingsNode])
2901
2904
  function openSkill(name){var id=++request.current;setSkill(null);setError(null);apiGet('/skill?name='+encodeURIComponent(name)).then(function(body){if(id!==request.current)return;var cached=pmBus.skillEdits[name];setSkill(cached?Object.assign({},body.skill,{fingerprint:cached.fingerprint}):body.skill);setContent(cached?cached.content:body.skill.content);setCopyName('user-'+body.skill.name);if(cached && cached.fingerprint!==body.skill.fingerprint)setError('这份 Skill 已在其他位置修改,请先重新加载,再合并你的修改。')}).catch(function(err){if(id===request.current)setError(err.message)})}
2902
2905
  useEffect(function(){if(draft && tab==='skills')openSkill(draft.nodeSkills[node])},[tab,node,draft && draft.nodeSkills[node]])
2903
2906
  function changeField(key,value){setDraft(function(prev){var next=Object.assign({},prev);if(key==='workspaceRoot' && data && data.settings.setupRequired){var sep=value.indexOf('\\')>=0?'\\':'/',base=String(value).replace(/[\\/]+$/,'');['knowledgeDir','prdArchiveDir','skillsDir'].forEach(function(k){var child={knowledgeDir:'knowledge',prdArchiveDir:'prd-archive',skillsDir:'skills'}[k];if(prev[k]===String(prev.workspaceRoot).replace(/[\\/]+$/,'')+sep+child)next[k]=base+sep+child})}next[key]=value;return next});setMessage(null)}
2904
2907
  function changeBinding(name){setDraft(function(prev){var next=Object.assign({},prev,{nodeSkills:Object.assign({},prev.nodeSkills)});next.nodeSkills[node]=name;return next});setMessage(null)}
2905
- function save(){setBusy(true);setError(null);apiSend('POST','/settings',Object.assign({},draft,{expectedFingerprint:data.settings.fingerprint})).then(function(body){setData(function(prev){return Object.assign({},prev,{settings:body.settings})});setDraft(body.settings);setMessage(body.settings.restartRequired?'已保存。工作目录在下次启动 DSH 时切换,其余配置已生效。':'已保存,下次推进节点时使用当前配置。')}).catch(function(err){setError(err.message)}).finally(function(){setBusy(false)})}
2908
+ function save(){setBusy(true);setError(null);apiSend('POST','/settings',Object.assign({},draft,{expectedFingerprint:data.settings.fingerprint})).then(function(body){setData(function(prev){return Object.assign({},prev,{settings:body.settings})});setDraft(body.settings);if(props && props.onboarding && !body.settings.restartRequired){props.onComplete();return}setMessage(body.settings.restartRequired?'目录已保存。请完整退出 DSH(包括托盘),再重新打开,即可进入需求总览。':'已保存,下次推进节点时使用当前配置。')}).catch(function(err){setError(err.message)}).finally(function(){setBusy(false)})}
2906
2909
  function editSkill(stamp){setBusy(true);setError(null);apiSend('POST','/skill',{name:skill.name,content:content,stamp:stamp,expectedFingerprint:skill.fingerprint}).then(function(body){delete pmBus.skillEdits[skill.name];setSkill(body.skill);setContent(body.skill.content);setMessage(stamp?'已恢复历史版本,原内容已保留为快照。':'Skill 已保存,下次加载使用新版。');return apiGet('/settings').then(function(latest){setData(latest)})}).catch(function(err){setError(err.message)}).finally(function(){setBusy(false)})}
2907
2910
  function copySkill(){setBusy(true);setError(null);apiSend('POST','/skill',{operation:'copy',name:skill.name,newName:copyName}).then(function(body){var copied=body.skill;return apiSend('POST','/settings',{expectedFingerprint:data.settings.fingerprint,nodeSkills:(function(){var bindings={};bindings[node]=copied.name;return bindings})()}).then(function(saved){return apiGet('/settings').then(function(latest){setData(latest);setDraft(function(prev){return Object.assign({},prev,{fingerprint:saved.settings.fingerprint,nodeSkills:Object.assign({},prev.nodeSkills,saved.settings.nodeSkills)})});setSkill(copied);setContent(copied.content);setMessage('已复制并绑定到'+(data.settings.nodes.find(function(n){return n.id===node}) || {}).title+'节点,可以开始编辑。')})})}).catch(function(err){setError(err.message)}).finally(function(){setBusy(false)})}
2908
2911
  if(!data || !draft)return e('section',{className:'pmw-settings'},e('h1',null,'SA 设置'),error ? e('div',{className:'pmw-settings__message is-error'},error,e('button',{className:'pmw-btn',onClick:load},'重新加载')) : e('p',{className:'pmw-settings__intro'},'正在读取配置…'))
2909
2912
  var dirty=JSON.stringify([draft.workspaceRoot,draft.knowledgeDir,draft.prdArchiveDir,draft.skillsDir,draft.nodeSkills])!==JSON.stringify([data.settings.workspaceRoot,data.settings.knowledgeDir,data.settings.prdArchiveDir,data.settings.skillsDir,data.settings.nodeSkills])
2910
2913
  return e('section',{className:'pmw-settings','aria-label':'SA 设置'},
2911
- route.settingsReturn && e('button',{className:'pmw-btn pmw-btn--ghost pmw-settings-back',onClick:function(){var target=route.settingsReturn,tabs=Object.assign({},route.tabs);tabs[target.id]=target.stage;pmBus.set({selectedId:target.id,activeSessionId:target.sessionId,nav:'home',tabs:tabs,settingsReturn:null})}},'← 返回「'+route.settingsReturn.title+'」'),
2912
- e('p',{className:'pmw-settings__eyebrow'},'SA WORKBENCH'),e('h1',null,data.settings.setupRequired?'设置你的 SA 工作台':'SA 设置'),e('p',{className:'pmw-settings__intro'},data.settings.setupRequired?'首次使用请选择资料目录;已有资料请选择原目录。保存后完整重启 DSH,即可进入工作台。':'配置资料位置和节点工作方法,让工作台适配你的流程。'),
2913
- e('div',{className:'pmw-settings__tabs',role:'tablist'},['directories','skills'].map(function(id){return e('button',{key:id,role:'tab','aria-selected':tab===id,onClick:function(){setTab(id);setError(null);setMessage(null)}},id==='directories'?'目录与资料':'节点 Skill')})),
2914
+ !(props && props.onboarding) && route.settingsReturn && e('button',{className:'pmw-btn pmw-btn--ghost pmw-settings-back',onClick:function(){var target=route.settingsReturn,tabs=Object.assign({},route.tabs);tabs[target.id]=target.stage;pmBus.set({selectedId:target.id,activeSessionId:target.sessionId,nav:'home',tabs:tabs,settingsReturn:null})}},'← 返回「'+route.settingsReturn.title+'」'),
2915
+ e('p',{className:'pmw-settings__eyebrow'},'SA WORKBENCH'),e('h1',null,data.settings.setupRequired?'设置你的 SA 工作台':'SA 设置'),e('p',{className:'pmw-settings__intro'},data.settings.setupRequired?'首次使用可直接确认默认目录,或选择已有资料目录。保存后进入需求总览;更改工作目录后需完整退出并重开 DSH。':'配置资料位置和节点工作方法,让工作台适配你的流程。'),
2916
+ !(props && props.onboarding) && e('div',{className:'pmw-settings__tabs',role:'tablist'},['directories','skills'].map(function(id){return e('button',{key:id,role:'tab','aria-selected':tab===id,onClick:function(){setTab(id);setError(null);setMessage(null)}},id==='directories'?'目录与资料':'节点 Skill')})),
2914
2917
  error && e('div',{role:'alert',className:'pmw-settings__message is-error'},error,e('button',{className:'pmw-btn pmw-btn--ghost',onClick:function(){load();if(skill){delete pmBus.skillEdits[skill.name];openSkill(skill.name)}}},'重新加载')),
2915
2918
  message && e('div',{role:'status',className:'pmw-settings__message'},message),
2916
2919
  tab==='directories' ? e('div',null,
2917
2920
  [['workspaceRoot','工作目录','存放需求记录、方案、PRD 和原型;切换在下次启动生效。'],['knowledgeDir','知识库目录','业务资料、术语、规范和 PRD 模板;保存后生效。'],['prdArchiveDir','归档库目录','按交付版本整理的定稿 PRD;保存后生效。'],['skillsDir','我的 Skill 目录','用户副本与配套资源保存在这里,插件升级会保留它们。']].map(function(field){return e('div',{key:field[0],className:'pmw-settings__field'},e('label',{htmlFor:'pmw-dir-'+field[0]},e('strong',null,field[1])),e('p',{id:'pmw-dir-'+field[0]+'-hint'},field[2]),e('div',{className:'pmw-settings__directory'},e('input',{id:'pmw-dir-'+field[0],'aria-label':field[1],'aria-describedby':'pmw-dir-'+field[0]+'-hint',value:draft[field[0]],onChange:function(ev){changeField(field[0],ev.target.value)}}),e('button',{type:'button',className:'pmw-btn','aria-label':'浏览'+field[1],disabled:busy || !!picking,onClick:function(){browseDirectory(field)}},e(UiIcon,{name:'folder'}),picking===field[0]?'选择中…':'浏览目录')))}),
2918
2921
  e('div',{className:'pmw-settings__message'},'当前工作目录:'+data.settings.activeWorkspaceRoot,data.settings.restartRequired && e('div',null,'下次启动切换到:'+data.settings.workspaceRoot),e('div',null,'完整需求归档:'+data.settings.requirementArchiveDir),e('div',null,'切换目录不会迁移原有资料。')),
2919
- e('div',{className:'pmw-settings__actions'},e('button',{className:'pmw-btn pmw-btn--primary',disabled:busy || !!picking || (!dirty && !data.settings.setupRequired),onClick:save},busy?'保存中…':'保存目录配置'),dirty && e('span',{className:'pmw-settings__caption'},'有未保存的修改')),
2922
+ e('div',{className:'pmw-settings__actions'},e('button',{className:'pmw-btn pmw-btn--primary',disabled:busy || !!picking || (!dirty && !data.settings.setupRequired),onClick:save},busy?'保存中…':data.settings.setupRequired?(draft.workspaceRoot===data.settings.activeWorkspaceRoot?'使用默认目录,进入工作台':'保存目录,完成设置'):'保存目录配置'),dirty && e('span',{className:'pmw-settings__caption'},'有未保存的修改')),
2920
2923
  e('p',{className:'pmw-settings__path'},'配置文件:'+data.settings.settingsFile)) :
2921
2924
  e('div',null,e('div',{className:'pmw-settings__actions'},e('p',{className:'pmw-settings__caption'},'每个节点绑定一份主 Skill。将 Skill 文件夹放入“我的 Skill 目录”,展开选择框即可发现。'),e('button',{type:'button',className:'pmw-btn pmw-btn--ghost',disabled:refreshing,onClick:refreshCatalog},refreshing?'刷新中…':'刷新列表')),
2922
2925
  e('div',{className:'pmw-settings__split'},
@@ -2937,6 +2940,57 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
2937
2940
  directoryBrowser && e(DirectoryBrowser,{key:directoryBrowser.key,title:directoryBrowser.title,start:directoryBrowser.start,onCancel:function(){setDirectoryBrowser(null)},onSelect:function(location){changeField(directoryBrowser.key,location);setDirectoryBrowser(null)}}))
2938
2941
  }
2939
2942
 
2943
+ var WORKSPACE_PREVIEW_CSS = "/* Task navigation is distinct from document controls. Preview is opt-in. */\r\nhtml:has(.sa-workspace-shell) .pmw-nav__group:last-child{display:none}\r\nhtml:root .pmw-root.sa-workspace-shell{--sa-preview-ink:var(--glass-ink,var(--dsw-alias-text-primary));--sa-preview-muted:var(--glass-muted,var(--dsw-alias-text-secondary));--sa-preview-card:var(--glass-card,var(--dsw-alias-background-container));--sa-preview-line:var(--glass-input,var(--dsw-alias-border-l2));}\r\n.sa-workspace-toolbar{display:flex;align-items:center;gap:16px;flex:none;padding:14px 22px 12px;min-height:66px;border-bottom:1px solid color-mix(in srgb,var(--sa-preview-line) 35%,transparent);}\r\n.sa-workspace-tabs{display:flex;gap:3px;padding:4px;border-radius:18px;background:var(--sa-preview-card);box-shadow:0 1px 0 color-mix(in srgb,var(--sa-preview-line) 30%,transparent);backdrop-filter:blur(16px);}\r\n.sa-workspace-tabs button{border:0;background:none;color:var(--sa-preview-muted);font:inherit;font-size:13px;border-radius:14px;padding:9px 16px;white-space:nowrap;cursor:pointer;}\r\n.sa-workspace-tabs button[aria-current=page]{background:var(--sa-preview-ink);color:var(--glass-bg,#fff);}\r\n.sa-workspace-tabs button:focus-visible,.sa-presentation button:focus-visible,.sa-board-card:focus-visible{outline:2px solid var(--glass-primary,#7663db);outline-offset:3px;}\r\n.sa-workspace-label{margin-left:auto;font-size:12px;color:var(--sa-preview-muted);}\r\n.sa-mobile-create{display:none;}\r\n.sa-workspace-toolbar .sa-theme-switch{flex:none;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-overview__head>.sa-theme-switch{display:none}\r\n.sa-settings-scroll{overflow:auto;min-height:0;flex:1;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-detail__head{padding:18px 24px 14px;gap:12px;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-detail__head .sa-assistant-toggle{width:auto;margin-left:8px;gap:7px;border:1px solid var(--sa-preview-line);border-radius:16px;padding:7px 12px;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-detail__head .sa-assistant-toggle[aria-expanded=true]{background:var(--glass-tint);}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-ai{border-left:1px solid var(--sa-preview-line);background:var(--sa-preview-card);}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-ai__context{gap:8px;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-ai__context>span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-ai__context>button{margin-left:auto;padding:4px;flex:none;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-doc--empty{padding:28px 24px;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state{max-width:920px;display:grid;grid-template-columns:minmax(0,1fr) minmax(240px,.85fr);column-gap:32px;row-gap:16px;margin:0 auto;align-content:start;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state__heading,html:root .pmw-root.sa-workspace-shell .pmw-empty-state__description{grid-column:1;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state__heading{align-self:end;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state__description{margin:0;max-width:460px;line-height:1.8;}\r\n.sa-deliverable{grid-column:2;grid-row:1 / span 6;align-self:start;padding:24px;border:1px solid color-mix(in srgb,var(--sa-preview-line) 65%,transparent);border-radius:24px;background:var(--sa-preview-card);box-shadow:0 10px 30px -24px var(--sa-preview-ink);}\r\n.sa-deliverable__eyebrow{font-size:11px;letter-spacing:.12em;color:var(--sa-preview-muted);}\r\n.sa-deliverable h4{font-size:18px;line-height:1.55;margin:10px 0 18px;font-weight:600;color:var(--sa-preview-ink);}\r\n.sa-deliverable ul{padding:0;margin:0;list-style:none;display:grid;gap:14px;}\r\n.sa-deliverable li{display:flex;gap:10px;align-items:flex-start;font-size:13px;line-height:1.65;}\r\n.sa-deliverable li>span{flex:none;font-size:10px;width:24px;height:24px;display:grid;place-items:center;border-radius:50%;background:var(--glass-tint);color:var(--sa-preview-muted);}\r\n.sa-deliverable__hint,.sa-deliverable__missing{font-size:12px;line-height:1.8;color:var(--sa-preview-muted);margin:18px 0 0;}\r\n.sa-deliverable__missing{border-top:1px solid var(--sa-preview-line);padding-top:14px;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state>.pmw-sources{grid-column:1;max-width:100%;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state>.pmw-empty-state__file,html:root .pmw-root.sa-workspace-shell .pmw-empty-state>.pmw-btn,html:root .pmw-root.sa-workspace-shell .pmw-empty-state>.pmw-empty-state__note{grid-column:1;justify-self:start;margin:0;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state>.pmw-btn{border-radius:16px;padding:11px 18px;}\r\n.sa-presentation{display:flex;margin-left:auto;padding:3px;border:1px solid var(--sa-preview-line);border-radius:14px;gap:2px;}\r\n.sa-presentation button{font:inherit;font-size:12px;padding:6px 11px;cursor:pointer;color:var(--sa-preview-muted);border:0;border-radius:10px;background:none;}\r\n.sa-presentation button[aria-pressed=true]{background:var(--sa-preview-card);box-shadow:0 1px 4px #0001;color:var(--sa-preview-ink);}\r\n.sa-requirement-board{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;padding:8px 0 20px;}\r\n.sa-board-column{background:color-mix(in srgb,var(--sa-preview-ink) 3%,transparent);border-radius:22px;padding:12px;min-height:240px;}\r\n.sa-board-column>header{display:flex;align-items:center;justify-content:space-between;margin:2px 4px 14px;font-size:12px;color:var(--sa-preview-muted);}\r\n.sa-board-card{display:flex;text-align:left;flex-direction:column;gap:10px;cursor:pointer;padding:18px;margin:0 0 12px;width:100%;font:inherit;color:var(--sa-preview-ink);border:1px solid color-mix(in srgb,var(--sa-preview-line) 65%,transparent);border-radius:18px;background:var(--sa-preview-card);transition:transform .15s;}\r\n.sa-board-card:hover{transform:translateY(-2px);}\r\n.sa-board-card code{font-size:11px;color:var(--sa-preview-muted);}\r\n.sa-board-card strong{font-size:15px;line-height:1.6;overflow-wrap:anywhere;}\r\n.sa-board-card__stage,.sa-board-card footer{font-size:11px;line-height:1.6;color:var(--sa-preview-muted);}\r\n.sa-board-card footer{display:flex;justify-content:space-between;gap:8px;padding-top:10px;border-top:1px solid var(--sa-preview-line);flex-wrap:wrap;}\r\n.sa-board-empty{font-size:12px;color:var(--sa-preview-muted);padding:20px 6px;}\r\n@media(max-width:1100px){html:root .pmw-root.sa-workspace-shell:has(.pmw-ai) .pmw-empty-state{grid-template-columns:minmax(0,1fr)}html:root .pmw-root.sa-workspace-shell:has(.pmw-ai) .sa-deliverable{grid-column:1;grid-row:auto;}}\r\n@media(max-width:760px){.sa-workspace-toolbar{padding:10px 14px;gap:8px;}.sa-workspace-tabs button{padding:8px 12px;}.sa-workspace-label{display:none}.sa-workspace-toolbar .sa-theme-switch{margin-left:auto;}html:root .pmw-root.sa-workspace-shell .pmw-empty-state{grid-template-columns:minmax(0,1fr);}.sa-deliverable{grid-column:1;grid-row:auto;}.sa-requirement-board{grid-template-columns:minmax(0,1fr)}html:root .pmw-root.sa-workspace-shell .pmw-doc--empty{padding:20px 16px;}html:root .pmw-root.sa-workspace-shell .pmw-detail__head{padding:14px 16px;}html:root .pmw-root.sa-workspace-shell .pmw-ai{position:absolute;right:0;top:0;bottom:0;z-index:20;width:min(420px,100%);box-shadow:-12px 0 40px #0002;}html:root .pmw-root.sa-workspace-shell .pmw-body{position:relative;}}\r\n@media(prefers-reduced-motion:reduce){.sa-board-card{transition:none}}\r\n\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-detail__title{font-size:20px;font-weight:600;line-height:1.45}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state{max-width:980px;width:100%}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-deliverable li>span{border-radius:50%!important;corner-shape:round!important}\r\n@media(max-width:760px){html:has(.sa-workspace-shell) .pmw-nav{display:none!important}html:root .pmw-root.sa-workspace-shell .pmw-empty-state{max-width:100%}.sa-workspace-toolbar{gap:6px}.sa-workspace-tabs{min-width:0;overflow-x:auto}.sa-workspace-tabs button{font-size:12px;padding:7px 8px}.sa-workspace-toolbar .sa-theme-switch{margin-left:0!important}}\r\n@media(max-width:760px){.sa-mobile-create{display:inline-flex;align-items:center;justify-content:center;flex:none;width:32px;height:32px;border:1px solid var(--sa-preview-line);border-radius:50%;color:var(--sa-preview-ink);background:var(--sa-preview-card);cursor:pointer}.sa-workspace-tabs{flex:1}.sa-workspace-toolbar{padding:10px}}\r\n\r\n/* Annotation revision: segmented stage route and composed start panel. */\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-stages{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:0;padding:18px 24px 20px;overflow:visible}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:8px;padding:0;overflow:visible;background:none;border:0;min-width:0}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step::before,html:root .pmw-root.sa-workspace-shell .pmw-step::after{display:none}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step__number{position:relative;z-index:2;display:flex;align-items:center;justify-content:center;width:40px;height:40px;min-width:40px;padding:0;border-radius:50%!important;corner-shape:round!important;border:1.5px solid var(--sa-preview-line);background:var(--glass-popover,var(--glass-bg));color:var(--sa-preview-muted);box-shadow:none;outline:0}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step__number>svg{width:19px;height:19px}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step.is-current .pmw-step__number{background:var(--sa-preview-ink);border-color:var(--sa-preview-ink);color:var(--glass-bg)}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step.is-active:not(.is-current) .pmw-step__number{border-color:var(--glass-primary);color:var(--glass-primary);background:var(--glass-bg);box-shadow:0 0 0 4px var(--glass-tint)}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-connector{position:absolute;z-index:1;top:19px;left:calc(-50% + 24px);width:calc(100% - 48px);height:0;border-top:2px solid var(--sa-preview-line);pointer-events:none}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-connector.is-reached{border-color:var(--sa-preview-ink)}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-connector.is-optional{border-top-style:dashed}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-done{position:absolute;right:-3px;bottom:-2px;width:16px;height:16px;border-radius:50%;display:grid;place-items:center;background:var(--sa-preview-ink);color:var(--glass-bg);border:2px solid var(--glass-bg)}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-done .pmw-icon{width:10px;height:10px}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step__label{font-size:13px;line-height:20px}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step small{margin:0;font-size:11px;line-height:16px}\r\n.sa-empty-workspace{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.9fr);gap:28px;max-width:1060px;margin:10px auto 0;width:100%;align-items:stretch}\r\n.sa-empty-workspace>.sa-deliverable{grid-column:auto;grid-row:auto;align-self:stretch;box-shadow:none}\r\n.sa-stage-start{display:flex;flex-direction:column;gap:0;padding:28px;border:1px solid color-mix(in srgb,var(--sa-preview-line) 60%,transparent);border-radius:24px;background:var(--sa-preview-card);min-width:0}\r\n.sa-stage-start__header{display:flex;gap:10px;align-items:center;font-size:12px;color:var(--sa-preview-muted)}\r\n.sa-stage-start__glyph{display:grid;place-items:center;width:36px;height:36px;border-radius:12px;color:var(--glass-primary);background:var(--glass-tint)}\r\n.sa-stage-start__state{margin-left:auto;font-size:11px;padding:4px 9px;border-radius:999px;background:var(--glass-secondary)}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-start h3{font-size:24px;line-height:1.4;font-weight:600;margin:22px 0 12px;color:var(--sa-preview-ink)}\r\n.sa-stage-start__intro{font-size:13px;line-height:1.85;margin:0 0 24px;color:var(--sa-preview-muted)}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-start>.pmw-sources{max-width:100%;width:100%;margin:0 0 18px}\r\n.sa-stage-output{display:flex;align-items:center;gap:12px;background:var(--glass-secondary);border:1px solid color-mix(in srgb,var(--sa-preview-line) 45%,transparent);border-radius:16px;padding:15px 16px;margin-top:auto}\r\n.sa-stage-output__icon{display:grid;place-items:center;width:36px;height:40px;border-radius:9px;background:var(--glass-card);color:var(--sa-preview-muted)}\r\n.sa-stage-output small{display:block;font-size:11px;color:var(--sa-preview-muted);margin-bottom:4px}\r\n.sa-stage-output code{display:block;font-size:13px;color:var(--sa-preview-ink);overflow-wrap:anywhere}\r\n.sa-stage-start__actions{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:22px}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-start__actions .pmw-btn{display:inline-flex;align-items:center;gap:18px;padding:11px 18px;border-radius:14px}\r\n.sa-stage-start__actions>span{font-size:11px;color:var(--sa-preview-muted)}\r\n@media(max-width:1100px){html:root .pmw-root.sa-workspace-shell:has(.pmw-ai) .sa-empty-workspace{grid-template-columns:minmax(0,1fr)}}\r\n@media(max-width:760px){.sa-empty-workspace{grid-template-columns:minmax(0,1fr);gap:18px;margin-top:0}.sa-stage-start{padding:22px}.sa-empty-workspace>.sa-deliverable{grid-column:auto;grid-row:auto}html:root .pmw-root.sa-workspace-shell .pmw-stages{padding:16px 12px 18px}html:root .pmw-root.sa-workspace-shell .pmw-step__number{width:34px;height:34px;min-width:34px}html:root .pmw-root.sa-workspace-shell .sa-stage-connector{top:16px;left:calc(-50% + 21px);width:calc(100% - 42px)}html:root .pmw-root.sa-workspace-shell .pmw-step__label{font-size:11px}}\r\n";
2944
+ function StageGlyph(props){
2945
+ var paths={intake:['M4 5h16v11H9l-5 4V5','M8 9h8M8 12h5'],solution:['M4 4h6v6H4zM14 14h6v6h-6z','M10 7h7v7M7 10v7h7'],prd:['M14 3H6a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V8l-5-5z','M14 3v5h5M8 14l2 2 5-5'],prototype:['M3 4h18v16H3z','M3 9h18M9 9v11']};
2946
+ return e('svg',{width:20,height:20,viewBox:'0 0 24 24',fill:'none',stroke:'currentColor',strokeWidth:1.65,strokeLinecap:'round',strokeLinejoin:'round','aria-hidden':true},(paths[props.stage] || paths.prd).map(function(d,i){return e('path',{key:i,d:d})}))
2947
+ }
2948
+ function StageStartCard(props){
2949
+ var action={intake:'开始梳理',solution:'开始设计',prd:'开始编写',prototype:'开始制作'}[props.stage];
2950
+ return e('section',{className:'sa-stage-start','aria-label':props.title},
2951
+ e('header',{className:'sa-stage-start__header'},e('span',{className:'sa-stage-start__glyph'},e(StageGlyph,{stage:props.stage})),e('span',null,props.archived?'归档记录':'准备开始'),e('span',{className:'sa-stage-start__state'},props.archived?'未包含':'尚未生成')),
2952
+ e('h3',null,props.title),e('p',{className:'sa-stage-start__intro'},props.description),
2953
+ props.sources,
2954
+ props.artifact && e('div',{className:'sa-stage-output'},e('span',{className:'sa-stage-output__icon'},e(StageGlyph,{stage:props.stage})),e('div',null,e('small',null,props.archived?'未包含文件':'交付文件'),e('code',null,props.artifact.path))),
2955
+ !props.archived && props.artifact && e('footer',{className:'sa-stage-start__actions'},e('button',{className:'pmw-btn pmw-btn--primary',disabled:props.busy,onClick:props.onStart},props.busy?'正在准备…':action,e('svg',{width:16,height:16,viewBox:'0 0 24 24',fill:'none',stroke:'currentColor',strokeWidth:1.8,'aria-hidden':true},e('path',{d:'M5 12h14M13 6l6 6-6 6',strokeLinecap:'round',strokeLinejoin:'round'}))),e('span',null,'使用当前工作方法')))
2956
+ }
2957
+ function WorkspaceNavigation(props){
2958
+ var active=props.current==='create'?'home':props.current;
2959
+ return e('header',{className:'sa-workspace-toolbar'},
2960
+ e('nav',{'aria-label':'SA 工作台导航',className:'sa-workspace-tabs'},[['home','需求'],['kb','知识库'],['plib','归档库'],['settings','工作方法']].map(function(t){return e('button',{key:t[0],type:'button','aria-current':active===t[0]?'page':undefined,onClick:function(){props.onNavigate(t[0])}},t[1])})),
2961
+ e('span',{className:'sa-workspace-label'},'SA 工作台'),
2962
+ e('button',{className:'sa-mobile-create',type:'button','aria-label':'新建需求',onClick:function(){props.onNavigate('create')}},e(UiIcon,{name:'plus'})),
2963
+ e('div',{className:'sa-theme-switch','aria-label':'工作台外观'},['light','dark'].map(function(a){return e('button',{key:a,type:'button','aria-label':a==='light'?'浅色模式':'暗色模式','aria-pressed':(pmBus.state.appearance || saAppearance())===a,onClick:function(){setSaAppearance(a)}},a==='light'?'☀':'☾')})))
2964
+ }
2965
+ function stageDeliverableModel(stage,requirement,artifact){
2966
+ var definitions={
2967
+ intake:{title:'一份可继续设计的业务需求',items:['业务目标与使用场景','范围、现状与资料依据','需要进一步确认的问题']},
2968
+ solution:{title:'一份可讨论的高阶方案',items:['关键设计点与系统职责','业务流程、依赖及改造范围','方案依据与待决策事项']},
2969
+ prd:{title:'一份可评审、可验证的 PRD',items:['用户故事与完整业务规则','Given / When / Then 验收条件','相关流程与交互说明']},
2970
+ prototype:{title:'一份可操作的交互原型',items:['主要页面与关键任务路径','适用的正常、异常与空状态','供讨论与迭代的页面交互']}
2971
+ };
2972
+ var model=definitions[stage] || definitions.intake;
2973
+ var prior=stage==='solution'?['intake']:stage==='prd'?['intake','solution']:stage==='prototype'?['prd']:[];
2974
+ var missing=prior.filter(function(id){var s=(requirement.stages || []).find(function(s){return s.id===id});return !s || !(s.artifacts || []).some(function(a){return a.exists})});
2975
+ return {title:model.title,items:model.items,missing:missing.map(function(id){return {intake:'业务需求',solution:'高阶方案',prd:'PRD'}[id]}),file:artifact && artifact.path,archived:!!requirement.archived};
2976
+ }
2977
+ function StageDeliverablePreview(props){
2978
+ var model=stageDeliverableModel(props.stage,props.requirement,props.artifact);
2979
+ if(model.archived)return null;
2980
+ return e('aside',{className:'sa-deliverable','aria-label':'本阶段交付预览'},
2981
+ e('div',{className:'sa-deliverable__eyebrow'},'本阶段交付'),e('h4',null,model.title),
2982
+ e('ul',null,model.items.map(function(text,i){return e('li',{key:text},e('span',{'aria-hidden':true},String(i+1).padStart(2,'0')),text)})),
2983
+ model.missing.length>0 && e('p',{className:'sa-deliverable__missing'},'尚未发现'+model.missing.join('、')+'文档。助手会先核对依据,必要时补充澄清。'),
2984
+ e('p',{className:'sa-deliverable__hint'},'以上为预期内容,当前尚未生成;生成后仍需评审。'))
2985
+ }
2986
+ function RequirementKanban(props){
2987
+ return e('div',{className:'sa-requirement-board','aria-label':'需求状态看板'},[['waiting','待启动'],['running','进行中'],['done','已完成']].map(function(group){
2988
+ var rows=props.requirements.filter(function(r){return overviewStatus(r)===group[0]});
2989
+ return e('section',{key:group[0],className:'sa-board-column'},e('header',null,e('span',{className:'pmw-stage-pill is-'+group[0]},e('i',{'aria-hidden':true}),group[1]),e('span',null,rows.length)),
2990
+ rows.length?rows.map(function(req){var c=collaborationValue(req),stages=req.stages || [],existing=stages.filter(function(s){return (s.artifacts || []).some(function(a){return a.exists})}).length;return e('button',{key:req.id,className:'sa-board-card',onClick:function(){props.onOpen(req)},'aria-label':'查看 '+req.code+' '+req.title},e('code',null,req.code),e('strong',null,req.title),e('span',{className:'sa-board-card__stage'},stageTitle(req)),e('footer',null,e('span',null,c.pmOwner || 'SA 待填写'),e('span',null,existing?existing+' 个阶段已有稿':'尚无阶段稿')))}):e('p',{className:'sa-board-empty'},'当前筛选下暂无需求'))
2991
+ }))
2992
+ }
2993
+
2940
2994
  function Panel(props) {
2941
2995
  var layout = props.layout
2942
2996
  var pm = props.pm
@@ -2949,6 +3003,7 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
2949
3003
  var form = useState('home')
2950
3004
  var view = form[0]
2951
3005
  var setView = form[1]
3006
+ var pendingNavigationSt=useState(null),pendingNavigation=pendingNavigationSt[0],setPendingNavigation=pendingNavigationSt[1]
2952
3007
  var ft = useState('')
2953
3008
  var formTitle = ft[0]
2954
3009
  var setFormTitle = ft[1]
@@ -3348,7 +3403,7 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3348
3403
  return pm.sendToReq(selected, dir, body.prompt).then(function (res) {
3349
3404
  setBusy(false)
3350
3405
  if (!res || !res.ok) setOpErr((res && res.error) || '发送失败')
3351
- else {setNotice('已发送到对话 · 使用 '+body.skill.name+';请在会话中查看进展。');if(stageId==='intake')return apiSend('POST','/requirement-start',{id:selected.id}).then(reload)}
3406
+ else {pmBus.set({focus:false});setNotice('已发送到对话 · 使用 '+body.skill.name+';请在会话中查看进展。');if(stageId==='intake')return apiSend('POST','/requirement-start',{id:selected.id}).then(reload)}
3352
3407
  })
3353
3408
  }).catch(function (err) {
3354
3409
  setBusy(false)
@@ -3517,10 +3572,16 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3517
3572
  }).catch(function(err) { if (pmBus.state.selectedId === owner.id) setOpErr(String(err.message || err)) }).finally(function(){setBusy(false)})
3518
3573
  }
3519
3574
 
3575
+ function navigateWorkspace(target){
3576
+ if(editor){setPendingNavigation(target);return}
3577
+ completeNavigation(target)
3578
+ }
3579
+ function completeNavigation(target){setPendingNavigation(null);setEditor(null);pmBus.set({nav:target,selectedId:null,activeSessionId:null,settingsReturn:null});setView(target)}
3580
+ var workspaceNav=e(WorkspaceNavigation,{current:view,onNavigate:navigateWorkspace})
3520
3581
  var children = []
3521
3582
 
3522
- if (data.data && (data.data.setupRequired || data.data.restartRequired)) return e('div',{className:'pmw-root','data-sa-appearance':bus.appearance || saAppearance()},e(SettingsPanel))
3523
- if (view === 'settings') return e('div', { className: 'pmw-root', 'data-sa-appearance':bus.appearance || saAppearance() }, e(SettingsPanel))
3583
+ if (data.data && (data.data.setupRequired || data.data.restartRequired)) return e('div',{className:'pmw-root','data-sa-appearance':bus.appearance || saAppearance()},e(SettingsPanel,{onboarding:true,onComplete:function(){pmBus.set({nav:'home',selectedId:null,activeSessionId:null,settingsReturn:null});setView('home');reload()}}))
3584
+ if (view === 'settings') return e('div', { className: 'pmw-root sa-workspace-shell', 'data-sa-appearance':bus.appearance || saAppearance() },e('style',null,WORKSPACE_PREVIEW_CSS),workspaceNav,e('div',{className:'sa-settings-scroll'},e(SettingsPanel)))
3524
3585
 
3525
3586
  // header(纯标题,动作全部收进各自语境:Tab 空态/地铁图归档站/右栏线程条)
3526
3587
  if (!selected && (view !== 'home' || !data.data)) children.push(e('div', { className: 'pmw-header', key: 'header' },
@@ -3541,7 +3602,7 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3541
3602
  e('div',{className:'pmw-dialog__body'},e('label',{className:'pmw-field'},e('span',{className:'pmw-field__label'},'文件名称'),e('input',{className:'pmw-input',autoFocus:true,'aria-label':'文件名称',value:newFile.name,maxLength:110,onChange:function(ev){setNewFile(Object.assign({},newFile,{name:ev.target.value}))},placeholder:'例如:接口说明'})),
3542
3603
  e('label',{className:'pmw-field'},e('span',{className:'pmw-field__label'},'文档内容'),e('textarea',{className:'pmw-textarea','aria-label':'新增文档内容',value:newFile.content,onChange:function(ev){setNewFile(Object.assign({},newFile,{content:ev.target.value}))},placeholder:'支持 Markdown'})),opErr && e('p',{role:'alert'},opErr)),
3543
3604
  e('div',{className:'pmw-dialog__foot'},e('button',{type:'button',className:'pmw-btn',disabled:isBusy,onClick:function(){setNewFile(null)}},'取消'),e('button',{type:'submit',className:'pmw-btn pmw-btn--primary',disabled:isBusy || !newFile.name.trim() || !newFile.content.trim()},isBusy?'正在添加…':'添加文档')))))
3544
- return e('div', { ref:rootRef, className: 'pmw-root' + (expanded ? ' is-expanded' : ''), 'data-sa-appearance':bus.appearance || saAppearance() }, children)
3605
+ return e('div', { ref:rootRef, className: 'pmw-root sa-workspace-shell' + (expanded ? ' is-expanded' : ''), 'data-sa-appearance':bus.appearance || saAppearance() },e('style',null,WORKSPACE_PREVIEW_CSS),!expanded && workspaceNav,pendingNavigation && e(DetailDialog,{title:'离开未保存的文档?',onClose:function(){setPendingNavigation(null)},footer:e(React.Fragment,null,e('button',{className:'pmw-btn',onClick:function(){setPendingNavigation(null)}},'继续编辑'),e('button',{className:'pmw-btn pmw-btn--primary',onClick:function(){completeNavigation(pendingNavigation)}},'放弃修改并离开'))},e('p',null,'当前修改尚未保存。继续编辑可保留草稿;离开将放弃这些修改,原文件不变。')),children)
3545
3606
  }
3546
3607
 
3547
3608
  // body: main + chat
@@ -3676,13 +3737,10 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3676
3737
  return e('button', { key: stage.id, className: 'pmw-step' + (stage.id === curTab ? ' is-active' : '') + (exists ? ' is-complete' : '') + (current ? ' is-current' : '') + (optional ? ' is-optional' : ''),
3677
3738
  'aria-pressed': stage.id === curTab, 'aria-current': current ? 'step' : undefined, title: stage.title + ' · ' + (exists ? '已有文档' : '尚未生成') + (stage.id === curTab ? ' · 正在查看' : ''),
3678
3739
  onClick: function () { if (stage.id === curTab) return; if (editor && !confirm('有未保存的修改,确定放弃并切换文档?')) return; setEditor(null); setTabSt(stage.id) },
3679
- }, e('span', { className: 'pmw-step__number', 'aria-hidden': true }, exists ? e(UiIcon,{name:'check'}) : String(index + 1)),
3740
+ },index>0 && e('span',{className:'sa-stage-connector'+(optional?' is-optional':'')+((exists || current) && selected.stages[index-1].artifacts[0].exists?' is-reached':''),'aria-hidden':true}),e('span',{className:'pmw-step__number','aria-hidden':true},e(StageGlyph,{stage:stage.id}),exists && e('span',{className:'sa-stage-done'},e(UiIcon,{name:'check'}))),
3680
3741
  e('span', {className:'pmw-step__label'}, label), e('small', null, status))
3681
3742
  })
3682
- metroNodes.unshift(e('svg',{key:'route',className:'pmw-metro__track',viewBox:'0 0 1000 64',preserveAspectRatio:'none','aria-hidden':true},
3683
- e('path',{className:'pmw-metro__line',d:'M125 20 H625',vectorEffect:'non-scaling-stroke'}),
3684
- progressX > 125 && e('path',{className:'pmw-metro__line is-travelled',d:'M125 20 H'+progressX,vectorEffect:'non-scaling-stroke'}),
3685
- e('path',{className:'pmw-metro__line pmw-metro__branch'+(prototypeExists ? ' is-travelled' : ''),d:'M625 20 H875',vectorEffect:'non-scaling-stroke'})))
3743
+
3686
3744
 
3687
3745
  var currentDocReady = doc && curArt && doc.path === curArt.path && !doc.loading && !doc.error
3688
3746
  var cloudReceipt = currentDocReady && doc.receipt
@@ -3713,20 +3771,9 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3713
3771
  var sourcesNode = curTab === 'intake' && e(SourceInputs,{key:'sources-'+selected.id,id:selected.id,readOnly:!!selected.archived,hasDoc:!!(curArt && curArt.exists),stageBusy:isBusy,onBusy:setSourceBusy,onStart:function(){handStage('intake')}})
3714
3772
  if (!curArt || !curArt.exists) {
3715
3773
  var emptyCopy={intake:['梳理业务需求','从你的诉求和业务资料开始,澄清目标、使用场景与范围,保留待确认的问题。','梳理需求'],solution:['形成高阶方案','结合业务需求与现状,明确系统职责、改造方向、依赖与未决事项。','设计高阶方案'],prd:['编写 PRD','基于需求与高阶方案,展开可验证的功能、业务规则和验收条件。','编写 PRD'],prototype:['制作交互原型','用可操作的页面检验 PRD 中的流程与交互。原型按需交付,不阻止归档。','制作原型']}[curTab]
3716
- contentNode = e('div', { className: 'pmw-doc pmw-doc--empty', key: 'empty' },e('section',{className:'pmw-empty-state'},
3717
- e('div',{className:'pmw-empty-state__heading'},
3718
- e('div',{className:'pmw-empty-state__icon','aria-hidden':true},e(UiIcon,{name:curTab==='prototype'?'select':'doc'})),
3719
- e('h3',null,selected.archived ? '本次归档未包含'+documentName : emptyCopy[0])),
3720
- e('p',{className:'pmw-empty-state__description'},selected.archived ? '此归档保留了当时已有的交付文件,未生成的文档不会自动补齐。' : emptyCopy[1]),
3721
- sourcesNode,
3722
- curArt && e('div',{className:'pmw-empty-state__file'},e(UiIcon,{name:'doc'}),selected.archived?'未包含文件':'交付文件',e('code',null,curArt.path)),
3723
- !selected.archived && curArt && e('button', {
3724
- className: 'pmw-btn pmw-btn--primary',
3725
- disabled: isBusy || sourceBusy,
3726
- onClick: function () { handStage(curTab) },
3727
- }, isBusy ? '正在准备…' : '开始动手吧'),
3728
- !selected.archived && e('p',{className:'pmw-empty-state__note'},'使用当前绑定的工作方法发送到当前对话;信息不足时先澄清。'),
3729
- ))
3774
+ contentNode=e('div',{className:'pmw-doc pmw-doc--empty',key:'empty'},e('div',{className:'sa-empty-workspace'},
3775
+ e(StageStartCard,{stage:curTab,title:selected.archived?'本次归档未包含'+documentName:emptyCopy[0],description:selected.archived?'此归档保留了当时已有的交付文件,未生成的文档不会自动补齐。':emptyCopy[1],artifact:curArt,archived:!!selected.archived,sources:sourcesNode,busy:isBusy || sourceBusy,onStart:function(){handStage(curTab)}}),
3776
+ e(StageDeliverablePreview,{stage:curTab,requirement:selected,artifact:curArt})))
3730
3777
  } else if (doc && doc.path === curArt.path) {
3731
3778
  var isHtml = /\.html?$/i.test(doc.path)
3732
3779
  // UX 标注工具条:原型 Tab、当前版本即出现;已归档降级为只读(可看 pin,不可新增/改稿)
@@ -3785,10 +3832,10 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3785
3832
  mainChildren.push(e('div', { className: 'pmw-detail', key: 'detail' },
3786
3833
  !expanded && e('div', { className: 'pmw-detail__head' },
3787
3834
  e('h2', { className: 'pmw-detail__title' }, selected.title),
3788
- e('button',{className:'pmw-btn pmw-btn--ghost',onClick:function(){setRequirementInfo(selected)}},e(UiIcon,{name:'settings'}),'协作信息'),
3835
+ e('button',{className:'pmw-btn pmw-btn--ghost',onClick:function(){setRequirementInfo(selected)}},e(UiIcon,{name:'users'}),'协作信息'),
3789
3836
  selected.code ? e('span', { className: 'pmw-tag pmw-tag--code' }, selected.code) : null,
3790
3837
  e('span', { className: 'pmw-detail__version' }, selected.version || '未排期'),
3791
- e('button', { className: 'pmw-btn pmw-btn--ghost pmw-btn--icon', 'aria-label': bus.focus ? '显示会话' : '专注阅读', 'aria-pressed': bus.focus, onClick: function () { pmBus.set({ focus: !bus.focus }) } }, e(UiIcon, { name: 'focus' })),
3838
+ e('button', { className: 'pmw-btn pmw-btn--ghost sa-assistant-toggle', 'aria-label':bus.focus?'打开需求助手':'收起需求助手','aria-expanded':!bus.focus,onClick:function(){pmBus.set({focus:!bus.focus})} },e(UiIcon,{name:'chat'}),bus.focus?'助手':'收起助手'),
3792
3839
  ),
3793
3840
  !expanded && e('nav', { className: 'pmw-stages', 'aria-label': '需求交付阶段' }, metroNodes),
3794
3841
  tabBar,
@@ -3842,7 +3889,7 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3842
3889
  var chatError = bus.sessionError || (convRef && convRef.id === activeSessionId && convRef.error)
3843
3890
  chatNode = e('div', { className: 'pmw-ai', key: 'ai' },
3844
3891
  barNode,
3845
- e('div', { className: 'pmw-ai__context' }, e(UiIcon, { name: 'link' }), e('span', null, selected.code + ' · ' + selected.title)),
3892
+ e('div', { className: 'pmw-ai__context' }, e(UiIcon, { name: 'link' }), e('span', null, selected.code + ' · ' + selected.title),e('button',{className:'pmw-btn pmw-btn--ghost','aria-label':'收起需求助手',onClick:function(){pmBus.set({focus:true})}},e(UiIcon,{name:'close'}))),
3846
3893
  canChat
3847
3894
  ? e('div', { className: 'pmw-ai__conv', key: 'conv' },
3848
3895
  e(props.SessionProvider, { session: convRef.ref }, props.renderSlot('pm.conv', {})))
@@ -3881,7 +3928,7 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3881
3928
  e('div',{className:'pmw-dialog__body'},e('label',{className:'pmw-field'},e('span',{className:'pmw-field__label'},'文件名称'),e('input',{className:'pmw-input',autoFocus:true,'aria-label':'文件名称',value:newFile.name,maxLength:110,onChange:function(ev){setNewFile(Object.assign({},newFile,{name:ev.target.value}))},placeholder:'例如:接口说明'})),
3882
3929
  e('label',{className:'pmw-field'},e('span',{className:'pmw-field__label'},'文档内容'),e('textarea',{className:'pmw-textarea','aria-label':'新增文档内容',value:newFile.content,onChange:function(ev){setNewFile(Object.assign({},newFile,{content:ev.target.value}))},placeholder:'支持 Markdown'})),opErr && e('p',{role:'alert'},opErr)),
3883
3930
  e('div',{className:'pmw-dialog__foot'},e('button',{type:'button',className:'pmw-btn',disabled:isBusy,onClick:function(){setNewFile(null)}},'取消'),e('button',{type:'submit',className:'pmw-btn pmw-btn--primary',disabled:isBusy || !newFile.name.trim() || !newFile.content.trim()},isBusy?'正在添加…':'添加文档')))))
3884
- return e('div', { ref:rootRef, className: 'pmw-root' + (expanded ? ' is-expanded' : ''), 'data-sa-appearance':bus.appearance || saAppearance() }, children)
3931
+ return e('div', { ref:rootRef, className: 'pmw-root sa-workspace-shell' + (expanded ? ' is-expanded' : ''), 'data-sa-appearance':bus.appearance || saAppearance() },e('style',null,WORKSPACE_PREVIEW_CSS),!expanded && workspaceNav,pendingNavigation && e(DetailDialog,{title:'离开未保存的文档?',onClose:function(){setPendingNavigation(null)},footer:e(React.Fragment,null,e('button',{className:'pmw-btn',onClick:function(){setPendingNavigation(null)}},'继续编辑'),e('button',{className:'pmw-btn pmw-btn--primary',onClick:function(){completeNavigation(pendingNavigation)}},'放弃修改并离开'))},e('p',null,'当前修改尚未保存。继续编辑可保留草稿;离开将放弃这些修改,原文件不变。')),children)
3885
3932
  }
3886
3933
 
3887
3934
  // -----------------------------------------------------------------------
@@ -27,7 +27,7 @@ window.__ModuleLoader__.load({
27
27
 
28
28
  var PANEL_KEY = 'pm'
29
29
  var API = '/pm/api'
30
- function saAppearance(){try{return localStorage.getItem('sa-workbench-appearance')==='light'?'light':'dark'}catch(err){return 'dark'}}
30
+ function saAppearance(){try{return localStorage.getItem('sa-workbench-appearance')==='dark'?'dark':'light'}catch(err){return 'light'}}
31
31
  function setSaAppearance(next){try{localStorage.setItem('sa-workbench-appearance',next)}catch(err){}pmBus.set({appearance:next})}
32
32
  function bindSaShell(appearance){
33
33
  if(typeof document==='undefined')return function(){};
@@ -36,7 +36,7 @@ window.__ModuleLoader__.load({
36
36
  return function(){if(previousShell===undefined)delete root.dataset.saShell;else root.dataset.saShell=previousShell;if(previousAppearance===undefined)delete root.dataset.saAppearance;else root.dataset.saAppearance=previousAppearance}
37
37
  }
38
38
  function toggleSaAppearance(){var next=(pmBus.state.appearance || saAppearance())==='dark'?'light':'dark';try{localStorage.setItem('sa-workbench-appearance',next)}catch(err){}pmBus.set({appearance:next})}
39
- var CLIENT_VERSION = '0.1.27'
39
+ var CLIENT_VERSION = '0.1.29'
40
40
 
41
41
  // A session may disappear or fail to open after selection. Keep failures
42
42
  // inside the conversation pane, and release even a rejected/pending ref.
@@ -1788,6 +1788,7 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
1788
1788
  edit: 'M12 20H4V12M9 15l3-.5L21 6l-3-3-8.5 9z', list: 'M8 5h13M8 12h13M8 19h13M3 5h.01M3 12h.01M3 19h.01',
1789
1789
  chat: 'M4 4h16v12H9l-5 4z', expand: 'M8 3H3v5M16 3h5v5M21 16v5h-5M3 16v5h5', focus: 'M4 4h16v16H4zM15 4v16', history: 'M3 10a9 9 0 1 1 2 9M3 3v7h7M12 7v5l3 2',
1790
1790
  check: 'M5 12l4 4L19 6', link: 'M10 13a5 5 0 0 0 7 0l4-4a5 5 0 0 0-7-7l-2 2M14 11a5 5 0 0 0-7 0l-4 4a5 5 0 0 0 7 7l2-2',
1791
+ users: 'M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75',
1791
1792
  settings: 'M12 8a4 4 0 1 0 0 8 4 4 0 0 0 0-8M10 3h4l1 3 3 1 3 3v4l-3 1-1 3-3 3h-4l-1-3-3-1-3-3v-4l3-1 1-3z',
1792
1793
  folder: 'M3 7V5a2 2 0 0 1 2-2h5l2 3h7a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z',
1793
1794
  route: 'M4 5h16M4 12h16M4 19h16M7 3v4M12 10v4M17 17v4',
@@ -1967,8 +1968,10 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
1967
1968
  var progressGradientId=useState(function(){return 'pmw-progress-blue-'+(++overviewGradientSequence)})[0]
1968
1969
  var planServiceReady=!!(props.releases && Array.isArray(props.releases.plans))
1969
1970
  var rs=useState(props.releases || {currentVersion:null,plans:[],fingerprint:null}),releases=rs[0],setReleases=rs[1]
1970
- var versionSt=useState(function(){return props.releases && props.releases.currentVersion || '*'}),version=versionSt[0],setVersion=versionSt[1]
1971
- var statusSt=useState('all'),status=statusSt[0],setStatus=statusSt[1],querySt=useState(''),query=querySt[0],setQuery=querySt[1]
1971
+ var versionSt=useState(function(){return pmBus.overviewContext ? pmBus.overviewContext.version : props.releases && props.releases.currentVersion || '*'}),version=versionSt[0],setVersion=versionSt[1]
1972
+ var statusSt=useState(pmBus.overviewContext && pmBus.overviewContext.status || 'all'),status=statusSt[0],setStatus=statusSt[1],querySt=useState(pmBus.overviewContext && pmBus.overviewContext.query || ''),query=querySt[0],setQuery=querySt[1]
1973
+ var presentationSt=useState(pmBus.overviewContext && pmBus.overviewContext.presentation || 'table'),presentation=presentationSt[0],setPresentation=presentationSt[1]
1974
+ useEffect(function(){pmBus.overviewContext={version:version,status:status,query:query,presentation:presentation}},[version,status,query,presentation])
1972
1975
  var sortSt=useState('updated'),sort=sortSt[0],setSort=sortSt[1],choiceSt=useState(false),choice=choiceSt[0],setChoice=choiceSt[1]
1973
1976
  var infoSt=useState(null),info=infoSt[0],setInfo=infoSt[1],pickerRef=React.useRef(null),pickerButton=React.useRef(null)
1974
1977
  var hs=useState(null),help=hs[0],setHelp=hs[1],helpRef=React.useRef(null),ims=useState(false),importOpen=ims[0],setImportOpen=ims[1]
@@ -2020,10 +2023,10 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
2020
2023
  e('section',{className:'pmw-summary','aria-label':'本版需求统计'},e('div',{className:'pmw-summary__metrics'},statistic('total','需求总数',model.total),statistic('done','已完成',model.completed),statistic('running','进行中',model.running),statistic('waiting','待启动',model.waiting))),
2021
2024
  e('div',{className:'pmw-overview__panels'},train),
2022
2025
  e('section',{className:'pmw-overview__tablepanel','aria-label':'需求列表'},
2023
- e('div',{className:'pmw-overview__boardhead'},e('span',{className:'pmw-panel-icon'},e(UiIcon,{name:'list'})),e('h2',null,'需求地图'),e('span',{role:'status'},model.rows.length)),
2026
+ e('div',{className:'pmw-overview__boardhead'},e('span',{className:'pmw-panel-icon'},e(UiIcon,{name:'list'})),e('h2',null,'需求地图'),e('span',{role:'status'},model.rows.length),e('div',{className:'sa-presentation',role:'group','aria-label':'需求展示方式'},[['table','表格'],['board','看板']].map(function(p){return e('button',{key:p[0],'aria-pressed':presentation===p[0],onClick:function(){setPresentation(p[0])}},p[1])}))),
2024
2027
  e('div',{className:'pmw-overview__tools'},e('div',{className:'pmw-overview__views',role:'group','aria-label':'按需求状态筛选'},tabs.map(function(t){return e('button',{key:t.id,'aria-pressed':status===t.id,onClick:function(){setStatus(t.id)}},t.title,e('span',null,t.count))})),e('label',{className:'pmw-overview__search'},e(UiIcon,{name:'search'}),e('input',{'aria-label':'搜索需求、编码、负责人或应用',placeholder:'搜索需求、负责人或应用',value:query,onChange:function(ev){setQuery(ev.target.value)}}),query && e('button',{'aria-label':'清除总览搜索',onClick:function(){setQuery('')}},e(UiIcon,{name:'close'})))),
2025
2028
  props.requirements.length===0?e('div',{className:'pmw-overview__empty'},e(UiIcon,{name:'grid'}),e('h2',null,'新建第一条需求'),e('button',{className:'pmw-btn pmw-btn--primary',onClick:props.onCreate},'新建需求')):model.rows.length===0?e('div',{className:'pmw-overview__empty'},e(UiIcon,{name:'search'}),e('h2',null,'当前范围没有需求'),e('button',{className:'pmw-btn',onClick:function(){setStatus('all');setQuery('')}},'清除状态与搜索筛选')):
2026
- e('div',{className:'pmw-requirements-scroll'},e('table',{className:'pmw-requirements'},e('thead',null,e('tr',null,['需求','状态','业务方','SA','前端开发','后端开发','测试','外部应用','操作'].map(function(label){return e('th',{key:label,scope:'col'},label)}))),e('tbody',null,model.rows.map(card))))),
2029
+ presentation==='board'?e(RequirementKanban,{requirements:model.rows,onOpen:function(req){setInfo({requirement:req,editing:false})}}):e('div',{className:'pmw-requirements-scroll'},e('table',{className:'pmw-requirements'},e('thead',null,e('tr',null,['需求','状态','业务方','SA','前端开发','后端开发','测试','外部应用','操作'].map(function(label){return e('th',{key:label,scope:'col'},label)}))),e('tbody',null,model.rows.map(card))))),
2027
2030
  help && e('div',{className:'pmw-overview__help',ref:helpRef,role:'dialog','aria-label':help.title,style:{left:help.left,top:help.top}},e('h3',null,help.title),e('p',null,help.text)),
2028
2031
  importOpen && e(ReleaseImportDialog,{onClose:function(){setImportOpen(false)},onSaved:function(value){setReleases(value);props.onRefresh()}}),
2029
2032
  info && e(RequirementInfoDialog,{requirement:info.requirement,startEditing:info.editing,onOpen:props.onOpen,onClose:function(){setInfo(null)},onSaved:props.onRefresh}))
@@ -2338,7 +2341,7 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
2338
2341
  // 全局选择总线:左轨(常驻)与 SA 总览页(main 面板)共享选中态
2339
2342
  // -----------------------------------------------------------------------
2340
2343
  var pmBus = {
2341
- state: { selectedId: null, activeSessionId: null, nav: null, selectedVersion: null, tabs: {}, scrolls: {}, files: {}, focus: false },
2344
+ state: { selectedId: null, activeSessionId: null, nav: 'home', selectedVersion: null, tabs: {}, scrolls: {}, files: {}, focus: true },
2342
2345
  listeners: [],
2343
2346
  set: function (patch) {
2344
2347
  var changed = false
@@ -2642,9 +2645,9 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
2642
2645
  )
2643
2646
  }
2644
2647
 
2645
- return e('div', { className: 'pmw-nav', 'data-sa-appearance':bus.appearance || saAppearance() },
2648
+ return e('div', { className: 'pmw-nav', 'data-sa-appearance':bus.appearance || saAppearance(), 'data-sa-setup':data.data && (data.data.setupRequired || data.data.restartRequired)?'true':'false' },
2646
2649
  e('div',{className:'glass-workspace'},e('span',{className:'glass-workspace-icon'},e(UiIcon,{name:'grid'})),e('span',null,e('strong',{className:'glass-workspace-title'},data.data && data.data.workspace && data.data.workspace.title || '项目工作空间'),e('small',null,'SA 项目工作空间'))),
2647
- e('div', { className: 'pmw-nav__top' },
2650
+ e('style',null,'.pmw-nav[data-sa-setup="true"] .pmw-nav__top,.pmw-nav[data-sa-setup="true"] .pmw-nav__scroll{display:none}.pmw-nav[data-sa-setup="true"]:after{content:"完成目录设置后,即可开始使用工作台";padding:20px;font-size:13px;line-height:1.7;opacity:.7}'),e('div', { className: 'pmw-nav__top' },
2648
2651
  e('button', {
2649
2652
  className: 'pmw-btn pmw-btn--primary pmw-nav__new',
2650
2653
  onClick: function () {
@@ -2867,11 +2870,11 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
2867
2870
  e('div',{className:'pmw-dialog__foot'},e('button',{className:'pmw-btn',onClick:props.onCancel},'取消'),e('button',{className:'pmw-btn pmw-btn--primary',disabled:loading || !value || !value.current,onClick:function(){props.onSelect(value.current)}},'选择此目录'))))
2868
2871
  }
2869
2872
 
2870
- function SettingsPanel() {
2873
+ function SettingsPanel(props) {
2871
2874
  var route=usePmBus()
2872
2875
  var ds=useState(null), data=ds[0], setData=ds[1]
2873
2876
  var fs=useState(null), draft=fs[0], setDraft=fs[1]
2874
- var ts=useState(pmBus.state.settingsTab || 'directories'), tab=ts[0], setTab=ts[1]
2877
+ var ts=useState(props && props.onboarding ? 'directories' : pmBus.state.settingsTab || 'directories'), tab=ts[0], setTab=ts[1]
2875
2878
  var ns=useState(pmBus.state.settingsNode || 'intake'), node=ns[0], setNode=ns[1]
2876
2879
  var ss=useState(null), skill=ss[0], setSkill=ss[1]
2877
2880
  var cs=useState(''), content=cs[0], setContent=cs[1]
@@ -2897,26 +2900,26 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
2897
2900
  finally {if(mounted.current)setPicking(null)}
2898
2901
  }
2899
2902
  useEffect(function(){load()},[])
2900
- useEffect(function(){setTab(route.settingsTab || 'directories');setNode(route.settingsNode || 'intake')},[route.settingsTab,route.settingsNode])
2903
+ useEffect(function(){setTab(props && props.onboarding ? 'directories' : route.settingsTab || 'directories');setNode(route.settingsNode || 'intake')},[route.settingsTab,route.settingsNode])
2901
2904
  function openSkill(name){var id=++request.current;setSkill(null);setError(null);apiGet('/skill?name='+encodeURIComponent(name)).then(function(body){if(id!==request.current)return;var cached=pmBus.skillEdits[name];setSkill(cached?Object.assign({},body.skill,{fingerprint:cached.fingerprint}):body.skill);setContent(cached?cached.content:body.skill.content);setCopyName('user-'+body.skill.name);if(cached && cached.fingerprint!==body.skill.fingerprint)setError('这份 Skill 已在其他位置修改,请先重新加载,再合并你的修改。')}).catch(function(err){if(id===request.current)setError(err.message)})}
2902
2905
  useEffect(function(){if(draft && tab==='skills')openSkill(draft.nodeSkills[node])},[tab,node,draft && draft.nodeSkills[node]])
2903
2906
  function changeField(key,value){setDraft(function(prev){var next=Object.assign({},prev);if(key==='workspaceRoot' && data && data.settings.setupRequired){var sep=value.indexOf('\\')>=0?'\\':'/',base=String(value).replace(/[\\/]+$/,'');['knowledgeDir','prdArchiveDir','skillsDir'].forEach(function(k){var child={knowledgeDir:'knowledge',prdArchiveDir:'prd-archive',skillsDir:'skills'}[k];if(prev[k]===String(prev.workspaceRoot).replace(/[\\/]+$/,'')+sep+child)next[k]=base+sep+child})}next[key]=value;return next});setMessage(null)}
2904
2907
  function changeBinding(name){setDraft(function(prev){var next=Object.assign({},prev,{nodeSkills:Object.assign({},prev.nodeSkills)});next.nodeSkills[node]=name;return next});setMessage(null)}
2905
- function save(){setBusy(true);setError(null);apiSend('POST','/settings',Object.assign({},draft,{expectedFingerprint:data.settings.fingerprint})).then(function(body){setData(function(prev){return Object.assign({},prev,{settings:body.settings})});setDraft(body.settings);setMessage(body.settings.restartRequired?'已保存。工作目录在下次启动 DSH 时切换,其余配置已生效。':'已保存,下次推进节点时使用当前配置。')}).catch(function(err){setError(err.message)}).finally(function(){setBusy(false)})}
2908
+ function save(){setBusy(true);setError(null);apiSend('POST','/settings',Object.assign({},draft,{expectedFingerprint:data.settings.fingerprint})).then(function(body){setData(function(prev){return Object.assign({},prev,{settings:body.settings})});setDraft(body.settings);if(props && props.onboarding && !body.settings.restartRequired){props.onComplete();return}setMessage(body.settings.restartRequired?'目录已保存。请完整退出 DSH(包括托盘),再重新打开,即可进入需求总览。':'已保存,下次推进节点时使用当前配置。')}).catch(function(err){setError(err.message)}).finally(function(){setBusy(false)})}
2906
2909
  function editSkill(stamp){setBusy(true);setError(null);apiSend('POST','/skill',{name:skill.name,content:content,stamp:stamp,expectedFingerprint:skill.fingerprint}).then(function(body){delete pmBus.skillEdits[skill.name];setSkill(body.skill);setContent(body.skill.content);setMessage(stamp?'已恢复历史版本,原内容已保留为快照。':'Skill 已保存,下次加载使用新版。');return apiGet('/settings').then(function(latest){setData(latest)})}).catch(function(err){setError(err.message)}).finally(function(){setBusy(false)})}
2907
2910
  function copySkill(){setBusy(true);setError(null);apiSend('POST','/skill',{operation:'copy',name:skill.name,newName:copyName}).then(function(body){var copied=body.skill;return apiSend('POST','/settings',{expectedFingerprint:data.settings.fingerprint,nodeSkills:(function(){var bindings={};bindings[node]=copied.name;return bindings})()}).then(function(saved){return apiGet('/settings').then(function(latest){setData(latest);setDraft(function(prev){return Object.assign({},prev,{fingerprint:saved.settings.fingerprint,nodeSkills:Object.assign({},prev.nodeSkills,saved.settings.nodeSkills)})});setSkill(copied);setContent(copied.content);setMessage('已复制并绑定到'+(data.settings.nodes.find(function(n){return n.id===node}) || {}).title+'节点,可以开始编辑。')})})}).catch(function(err){setError(err.message)}).finally(function(){setBusy(false)})}
2908
2911
  if(!data || !draft)return e('section',{className:'pmw-settings'},e('h1',null,'SA 设置'),error ? e('div',{className:'pmw-settings__message is-error'},error,e('button',{className:'pmw-btn',onClick:load},'重新加载')) : e('p',{className:'pmw-settings__intro'},'正在读取配置…'))
2909
2912
  var dirty=JSON.stringify([draft.workspaceRoot,draft.knowledgeDir,draft.prdArchiveDir,draft.skillsDir,draft.nodeSkills])!==JSON.stringify([data.settings.workspaceRoot,data.settings.knowledgeDir,data.settings.prdArchiveDir,data.settings.skillsDir,data.settings.nodeSkills])
2910
2913
  return e('section',{className:'pmw-settings','aria-label':'SA 设置'},
2911
- route.settingsReturn && e('button',{className:'pmw-btn pmw-btn--ghost pmw-settings-back',onClick:function(){var target=route.settingsReturn,tabs=Object.assign({},route.tabs);tabs[target.id]=target.stage;pmBus.set({selectedId:target.id,activeSessionId:target.sessionId,nav:'home',tabs:tabs,settingsReturn:null})}},'← 返回「'+route.settingsReturn.title+'」'),
2912
- e('p',{className:'pmw-settings__eyebrow'},'SA WORKBENCH'),e('h1',null,data.settings.setupRequired?'设置你的 SA 工作台':'SA 设置'),e('p',{className:'pmw-settings__intro'},data.settings.setupRequired?'首次使用请选择资料目录;已有资料请选择原目录。保存后完整重启 DSH,即可进入工作台。':'配置资料位置和节点工作方法,让工作台适配你的流程。'),
2913
- e('div',{className:'pmw-settings__tabs',role:'tablist'},['directories','skills'].map(function(id){return e('button',{key:id,role:'tab','aria-selected':tab===id,onClick:function(){setTab(id);setError(null);setMessage(null)}},id==='directories'?'目录与资料':'节点 Skill')})),
2914
+ !(props && props.onboarding) && route.settingsReturn && e('button',{className:'pmw-btn pmw-btn--ghost pmw-settings-back',onClick:function(){var target=route.settingsReturn,tabs=Object.assign({},route.tabs);tabs[target.id]=target.stage;pmBus.set({selectedId:target.id,activeSessionId:target.sessionId,nav:'home',tabs:tabs,settingsReturn:null})}},'← 返回「'+route.settingsReturn.title+'」'),
2915
+ e('p',{className:'pmw-settings__eyebrow'},'SA WORKBENCH'),e('h1',null,data.settings.setupRequired?'设置你的 SA 工作台':'SA 设置'),e('p',{className:'pmw-settings__intro'},data.settings.setupRequired?'首次使用可直接确认默认目录,或选择已有资料目录。保存后进入需求总览;更改工作目录后需完整退出并重开 DSH。':'配置资料位置和节点工作方法,让工作台适配你的流程。'),
2916
+ !(props && props.onboarding) && e('div',{className:'pmw-settings__tabs',role:'tablist'},['directories','skills'].map(function(id){return e('button',{key:id,role:'tab','aria-selected':tab===id,onClick:function(){setTab(id);setError(null);setMessage(null)}},id==='directories'?'目录与资料':'节点 Skill')})),
2914
2917
  error && e('div',{role:'alert',className:'pmw-settings__message is-error'},error,e('button',{className:'pmw-btn pmw-btn--ghost',onClick:function(){load();if(skill){delete pmBus.skillEdits[skill.name];openSkill(skill.name)}}},'重新加载')),
2915
2918
  message && e('div',{role:'status',className:'pmw-settings__message'},message),
2916
2919
  tab==='directories' ? e('div',null,
2917
2920
  [['workspaceRoot','工作目录','存放需求记录、方案、PRD 和原型;切换在下次启动生效。'],['knowledgeDir','知识库目录','业务资料、术语、规范和 PRD 模板;保存后生效。'],['prdArchiveDir','归档库目录','按交付版本整理的定稿 PRD;保存后生效。'],['skillsDir','我的 Skill 目录','用户副本与配套资源保存在这里,插件升级会保留它们。']].map(function(field){return e('div',{key:field[0],className:'pmw-settings__field'},e('label',{htmlFor:'pmw-dir-'+field[0]},e('strong',null,field[1])),e('p',{id:'pmw-dir-'+field[0]+'-hint'},field[2]),e('div',{className:'pmw-settings__directory'},e('input',{id:'pmw-dir-'+field[0],'aria-label':field[1],'aria-describedby':'pmw-dir-'+field[0]+'-hint',value:draft[field[0]],onChange:function(ev){changeField(field[0],ev.target.value)}}),e('button',{type:'button',className:'pmw-btn','aria-label':'浏览'+field[1],disabled:busy || !!picking,onClick:function(){browseDirectory(field)}},e(UiIcon,{name:'folder'}),picking===field[0]?'选择中…':'浏览目录')))}),
2918
2921
  e('div',{className:'pmw-settings__message'},'当前工作目录:'+data.settings.activeWorkspaceRoot,data.settings.restartRequired && e('div',null,'下次启动切换到:'+data.settings.workspaceRoot),e('div',null,'完整需求归档:'+data.settings.requirementArchiveDir),e('div',null,'切换目录不会迁移原有资料。')),
2919
- e('div',{className:'pmw-settings__actions'},e('button',{className:'pmw-btn pmw-btn--primary',disabled:busy || !!picking || (!dirty && !data.settings.setupRequired),onClick:save},busy?'保存中…':'保存目录配置'),dirty && e('span',{className:'pmw-settings__caption'},'有未保存的修改')),
2922
+ e('div',{className:'pmw-settings__actions'},e('button',{className:'pmw-btn pmw-btn--primary',disabled:busy || !!picking || (!dirty && !data.settings.setupRequired),onClick:save},busy?'保存中…':data.settings.setupRequired?(draft.workspaceRoot===data.settings.activeWorkspaceRoot?'使用默认目录,进入工作台':'保存目录,完成设置'):'保存目录配置'),dirty && e('span',{className:'pmw-settings__caption'},'有未保存的修改')),
2920
2923
  e('p',{className:'pmw-settings__path'},'配置文件:'+data.settings.settingsFile)) :
2921
2924
  e('div',null,e('div',{className:'pmw-settings__actions'},e('p',{className:'pmw-settings__caption'},'每个节点绑定一份主 Skill。将 Skill 文件夹放入“我的 Skill 目录”,展开选择框即可发现。'),e('button',{type:'button',className:'pmw-btn pmw-btn--ghost',disabled:refreshing,onClick:refreshCatalog},refreshing?'刷新中…':'刷新列表')),
2922
2925
  e('div',{className:'pmw-settings__split'},
@@ -2937,6 +2940,57 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
2937
2940
  directoryBrowser && e(DirectoryBrowser,{key:directoryBrowser.key,title:directoryBrowser.title,start:directoryBrowser.start,onCancel:function(){setDirectoryBrowser(null)},onSelect:function(location){changeField(directoryBrowser.key,location);setDirectoryBrowser(null)}}))
2938
2941
  }
2939
2942
 
2943
+ var WORKSPACE_PREVIEW_CSS = "/* Task navigation is distinct from document controls. Preview is opt-in. */\r\nhtml:has(.sa-workspace-shell) .pmw-nav__group:last-child{display:none}\r\nhtml:root .pmw-root.sa-workspace-shell{--sa-preview-ink:var(--glass-ink,var(--dsw-alias-text-primary));--sa-preview-muted:var(--glass-muted,var(--dsw-alias-text-secondary));--sa-preview-card:var(--glass-card,var(--dsw-alias-background-container));--sa-preview-line:var(--glass-input,var(--dsw-alias-border-l2));}\r\n.sa-workspace-toolbar{display:flex;align-items:center;gap:16px;flex:none;padding:14px 22px 12px;min-height:66px;border-bottom:1px solid color-mix(in srgb,var(--sa-preview-line) 35%,transparent);}\r\n.sa-workspace-tabs{display:flex;gap:3px;padding:4px;border-radius:18px;background:var(--sa-preview-card);box-shadow:0 1px 0 color-mix(in srgb,var(--sa-preview-line) 30%,transparent);backdrop-filter:blur(16px);}\r\n.sa-workspace-tabs button{border:0;background:none;color:var(--sa-preview-muted);font:inherit;font-size:13px;border-radius:14px;padding:9px 16px;white-space:nowrap;cursor:pointer;}\r\n.sa-workspace-tabs button[aria-current=page]{background:var(--sa-preview-ink);color:var(--glass-bg,#fff);}\r\n.sa-workspace-tabs button:focus-visible,.sa-presentation button:focus-visible,.sa-board-card:focus-visible{outline:2px solid var(--glass-primary,#7663db);outline-offset:3px;}\r\n.sa-workspace-label{margin-left:auto;font-size:12px;color:var(--sa-preview-muted);}\r\n.sa-mobile-create{display:none;}\r\n.sa-workspace-toolbar .sa-theme-switch{flex:none;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-overview__head>.sa-theme-switch{display:none}\r\n.sa-settings-scroll{overflow:auto;min-height:0;flex:1;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-detail__head{padding:18px 24px 14px;gap:12px;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-detail__head .sa-assistant-toggle{width:auto;margin-left:8px;gap:7px;border:1px solid var(--sa-preview-line);border-radius:16px;padding:7px 12px;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-detail__head .sa-assistant-toggle[aria-expanded=true]{background:var(--glass-tint);}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-ai{border-left:1px solid var(--sa-preview-line);background:var(--sa-preview-card);}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-ai__context{gap:8px;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-ai__context>span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-ai__context>button{margin-left:auto;padding:4px;flex:none;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-doc--empty{padding:28px 24px;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state{max-width:920px;display:grid;grid-template-columns:minmax(0,1fr) minmax(240px,.85fr);column-gap:32px;row-gap:16px;margin:0 auto;align-content:start;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state__heading,html:root .pmw-root.sa-workspace-shell .pmw-empty-state__description{grid-column:1;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state__heading{align-self:end;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state__description{margin:0;max-width:460px;line-height:1.8;}\r\n.sa-deliverable{grid-column:2;grid-row:1 / span 6;align-self:start;padding:24px;border:1px solid color-mix(in srgb,var(--sa-preview-line) 65%,transparent);border-radius:24px;background:var(--sa-preview-card);box-shadow:0 10px 30px -24px var(--sa-preview-ink);}\r\n.sa-deliverable__eyebrow{font-size:11px;letter-spacing:.12em;color:var(--sa-preview-muted);}\r\n.sa-deliverable h4{font-size:18px;line-height:1.55;margin:10px 0 18px;font-weight:600;color:var(--sa-preview-ink);}\r\n.sa-deliverable ul{padding:0;margin:0;list-style:none;display:grid;gap:14px;}\r\n.sa-deliverable li{display:flex;gap:10px;align-items:flex-start;font-size:13px;line-height:1.65;}\r\n.sa-deliverable li>span{flex:none;font-size:10px;width:24px;height:24px;display:grid;place-items:center;border-radius:50%;background:var(--glass-tint);color:var(--sa-preview-muted);}\r\n.sa-deliverable__hint,.sa-deliverable__missing{font-size:12px;line-height:1.8;color:var(--sa-preview-muted);margin:18px 0 0;}\r\n.sa-deliverable__missing{border-top:1px solid var(--sa-preview-line);padding-top:14px;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state>.pmw-sources{grid-column:1;max-width:100%;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state>.pmw-empty-state__file,html:root .pmw-root.sa-workspace-shell .pmw-empty-state>.pmw-btn,html:root .pmw-root.sa-workspace-shell .pmw-empty-state>.pmw-empty-state__note{grid-column:1;justify-self:start;margin:0;}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state>.pmw-btn{border-radius:16px;padding:11px 18px;}\r\n.sa-presentation{display:flex;margin-left:auto;padding:3px;border:1px solid var(--sa-preview-line);border-radius:14px;gap:2px;}\r\n.sa-presentation button{font:inherit;font-size:12px;padding:6px 11px;cursor:pointer;color:var(--sa-preview-muted);border:0;border-radius:10px;background:none;}\r\n.sa-presentation button[aria-pressed=true]{background:var(--sa-preview-card);box-shadow:0 1px 4px #0001;color:var(--sa-preview-ink);}\r\n.sa-requirement-board{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;padding:8px 0 20px;}\r\n.sa-board-column{background:color-mix(in srgb,var(--sa-preview-ink) 3%,transparent);border-radius:22px;padding:12px;min-height:240px;}\r\n.sa-board-column>header{display:flex;align-items:center;justify-content:space-between;margin:2px 4px 14px;font-size:12px;color:var(--sa-preview-muted);}\r\n.sa-board-card{display:flex;text-align:left;flex-direction:column;gap:10px;cursor:pointer;padding:18px;margin:0 0 12px;width:100%;font:inherit;color:var(--sa-preview-ink);border:1px solid color-mix(in srgb,var(--sa-preview-line) 65%,transparent);border-radius:18px;background:var(--sa-preview-card);transition:transform .15s;}\r\n.sa-board-card:hover{transform:translateY(-2px);}\r\n.sa-board-card code{font-size:11px;color:var(--sa-preview-muted);}\r\n.sa-board-card strong{font-size:15px;line-height:1.6;overflow-wrap:anywhere;}\r\n.sa-board-card__stage,.sa-board-card footer{font-size:11px;line-height:1.6;color:var(--sa-preview-muted);}\r\n.sa-board-card footer{display:flex;justify-content:space-between;gap:8px;padding-top:10px;border-top:1px solid var(--sa-preview-line);flex-wrap:wrap;}\r\n.sa-board-empty{font-size:12px;color:var(--sa-preview-muted);padding:20px 6px;}\r\n@media(max-width:1100px){html:root .pmw-root.sa-workspace-shell:has(.pmw-ai) .pmw-empty-state{grid-template-columns:minmax(0,1fr)}html:root .pmw-root.sa-workspace-shell:has(.pmw-ai) .sa-deliverable{grid-column:1;grid-row:auto;}}\r\n@media(max-width:760px){.sa-workspace-toolbar{padding:10px 14px;gap:8px;}.sa-workspace-tabs button{padding:8px 12px;}.sa-workspace-label{display:none}.sa-workspace-toolbar .sa-theme-switch{margin-left:auto;}html:root .pmw-root.sa-workspace-shell .pmw-empty-state{grid-template-columns:minmax(0,1fr);}.sa-deliverable{grid-column:1;grid-row:auto;}.sa-requirement-board{grid-template-columns:minmax(0,1fr)}html:root .pmw-root.sa-workspace-shell .pmw-doc--empty{padding:20px 16px;}html:root .pmw-root.sa-workspace-shell .pmw-detail__head{padding:14px 16px;}html:root .pmw-root.sa-workspace-shell .pmw-ai{position:absolute;right:0;top:0;bottom:0;z-index:20;width:min(420px,100%);box-shadow:-12px 0 40px #0002;}html:root .pmw-root.sa-workspace-shell .pmw-body{position:relative;}}\r\n@media(prefers-reduced-motion:reduce){.sa-board-card{transition:none}}\r\n\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-detail__title{font-size:20px;font-weight:600;line-height:1.45}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-empty-state{max-width:980px;width:100%}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-deliverable li>span{border-radius:50%!important;corner-shape:round!important}\r\n@media(max-width:760px){html:has(.sa-workspace-shell) .pmw-nav{display:none!important}html:root .pmw-root.sa-workspace-shell .pmw-empty-state{max-width:100%}.sa-workspace-toolbar{gap:6px}.sa-workspace-tabs{min-width:0;overflow-x:auto}.sa-workspace-tabs button{font-size:12px;padding:7px 8px}.sa-workspace-toolbar .sa-theme-switch{margin-left:0!important}}\r\n@media(max-width:760px){.sa-mobile-create{display:inline-flex;align-items:center;justify-content:center;flex:none;width:32px;height:32px;border:1px solid var(--sa-preview-line);border-radius:50%;color:var(--sa-preview-ink);background:var(--sa-preview-card);cursor:pointer}.sa-workspace-tabs{flex:1}.sa-workspace-toolbar{padding:10px}}\r\n\r\n/* Annotation revision: segmented stage route and composed start panel. */\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-stages{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:0;padding:18px 24px 20px;overflow:visible}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:8px;padding:0;overflow:visible;background:none;border:0;min-width:0}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step::before,html:root .pmw-root.sa-workspace-shell .pmw-step::after{display:none}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step__number{position:relative;z-index:2;display:flex;align-items:center;justify-content:center;width:40px;height:40px;min-width:40px;padding:0;border-radius:50%!important;corner-shape:round!important;border:1.5px solid var(--sa-preview-line);background:var(--glass-popover,var(--glass-bg));color:var(--sa-preview-muted);box-shadow:none;outline:0}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step__number>svg{width:19px;height:19px}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step.is-current .pmw-step__number{background:var(--sa-preview-ink);border-color:var(--sa-preview-ink);color:var(--glass-bg)}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step.is-active:not(.is-current) .pmw-step__number{border-color:var(--glass-primary);color:var(--glass-primary);background:var(--glass-bg);box-shadow:0 0 0 4px var(--glass-tint)}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-connector{position:absolute;z-index:1;top:19px;left:calc(-50% + 24px);width:calc(100% - 48px);height:0;border-top:2px solid var(--sa-preview-line);pointer-events:none}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-connector.is-reached{border-color:var(--sa-preview-ink)}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-connector.is-optional{border-top-style:dashed}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-done{position:absolute;right:-3px;bottom:-2px;width:16px;height:16px;border-radius:50%;display:grid;place-items:center;background:var(--sa-preview-ink);color:var(--glass-bg);border:2px solid var(--glass-bg)}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-done .pmw-icon{width:10px;height:10px}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step__label{font-size:13px;line-height:20px}\r\nhtml:root .pmw-root.sa-workspace-shell .pmw-step small{margin:0;font-size:11px;line-height:16px}\r\n.sa-empty-workspace{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.9fr);gap:28px;max-width:1060px;margin:10px auto 0;width:100%;align-items:stretch}\r\n.sa-empty-workspace>.sa-deliverable{grid-column:auto;grid-row:auto;align-self:stretch;box-shadow:none}\r\n.sa-stage-start{display:flex;flex-direction:column;gap:0;padding:28px;border:1px solid color-mix(in srgb,var(--sa-preview-line) 60%,transparent);border-radius:24px;background:var(--sa-preview-card);min-width:0}\r\n.sa-stage-start__header{display:flex;gap:10px;align-items:center;font-size:12px;color:var(--sa-preview-muted)}\r\n.sa-stage-start__glyph{display:grid;place-items:center;width:36px;height:36px;border-radius:12px;color:var(--glass-primary);background:var(--glass-tint)}\r\n.sa-stage-start__state{margin-left:auto;font-size:11px;padding:4px 9px;border-radius:999px;background:var(--glass-secondary)}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-start h3{font-size:24px;line-height:1.4;font-weight:600;margin:22px 0 12px;color:var(--sa-preview-ink)}\r\n.sa-stage-start__intro{font-size:13px;line-height:1.85;margin:0 0 24px;color:var(--sa-preview-muted)}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-start>.pmw-sources{max-width:100%;width:100%;margin:0 0 18px}\r\n.sa-stage-output{display:flex;align-items:center;gap:12px;background:var(--glass-secondary);border:1px solid color-mix(in srgb,var(--sa-preview-line) 45%,transparent);border-radius:16px;padding:15px 16px;margin-top:auto}\r\n.sa-stage-output__icon{display:grid;place-items:center;width:36px;height:40px;border-radius:9px;background:var(--glass-card);color:var(--sa-preview-muted)}\r\n.sa-stage-output small{display:block;font-size:11px;color:var(--sa-preview-muted);margin-bottom:4px}\r\n.sa-stage-output code{display:block;font-size:13px;color:var(--sa-preview-ink);overflow-wrap:anywhere}\r\n.sa-stage-start__actions{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-top:22px}\r\nhtml:root .pmw-root.sa-workspace-shell .sa-stage-start__actions .pmw-btn{display:inline-flex;align-items:center;gap:18px;padding:11px 18px;border-radius:14px}\r\n.sa-stage-start__actions>span{font-size:11px;color:var(--sa-preview-muted)}\r\n@media(max-width:1100px){html:root .pmw-root.sa-workspace-shell:has(.pmw-ai) .sa-empty-workspace{grid-template-columns:minmax(0,1fr)}}\r\n@media(max-width:760px){.sa-empty-workspace{grid-template-columns:minmax(0,1fr);gap:18px;margin-top:0}.sa-stage-start{padding:22px}.sa-empty-workspace>.sa-deliverable{grid-column:auto;grid-row:auto}html:root .pmw-root.sa-workspace-shell .pmw-stages{padding:16px 12px 18px}html:root .pmw-root.sa-workspace-shell .pmw-step__number{width:34px;height:34px;min-width:34px}html:root .pmw-root.sa-workspace-shell .sa-stage-connector{top:16px;left:calc(-50% + 21px);width:calc(100% - 42px)}html:root .pmw-root.sa-workspace-shell .pmw-step__label{font-size:11px}}\r\n";
2944
+ function StageGlyph(props){
2945
+ var paths={intake:['M4 5h16v11H9l-5 4V5','M8 9h8M8 12h5'],solution:['M4 4h6v6H4zM14 14h6v6h-6z','M10 7h7v7M7 10v7h7'],prd:['M14 3H6a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V8l-5-5z','M14 3v5h5M8 14l2 2 5-5'],prototype:['M3 4h18v16H3z','M3 9h18M9 9v11']};
2946
+ return e('svg',{width:20,height:20,viewBox:'0 0 24 24',fill:'none',stroke:'currentColor',strokeWidth:1.65,strokeLinecap:'round',strokeLinejoin:'round','aria-hidden':true},(paths[props.stage] || paths.prd).map(function(d,i){return e('path',{key:i,d:d})}))
2947
+ }
2948
+ function StageStartCard(props){
2949
+ var action={intake:'开始梳理',solution:'开始设计',prd:'开始编写',prototype:'开始制作'}[props.stage];
2950
+ return e('section',{className:'sa-stage-start','aria-label':props.title},
2951
+ e('header',{className:'sa-stage-start__header'},e('span',{className:'sa-stage-start__glyph'},e(StageGlyph,{stage:props.stage})),e('span',null,props.archived?'归档记录':'准备开始'),e('span',{className:'sa-stage-start__state'},props.archived?'未包含':'尚未生成')),
2952
+ e('h3',null,props.title),e('p',{className:'sa-stage-start__intro'},props.description),
2953
+ props.sources,
2954
+ props.artifact && e('div',{className:'sa-stage-output'},e('span',{className:'sa-stage-output__icon'},e(StageGlyph,{stage:props.stage})),e('div',null,e('small',null,props.archived?'未包含文件':'交付文件'),e('code',null,props.artifact.path))),
2955
+ !props.archived && props.artifact && e('footer',{className:'sa-stage-start__actions'},e('button',{className:'pmw-btn pmw-btn--primary',disabled:props.busy,onClick:props.onStart},props.busy?'正在准备…':action,e('svg',{width:16,height:16,viewBox:'0 0 24 24',fill:'none',stroke:'currentColor',strokeWidth:1.8,'aria-hidden':true},e('path',{d:'M5 12h14M13 6l6 6-6 6',strokeLinecap:'round',strokeLinejoin:'round'}))),e('span',null,'使用当前工作方法')))
2956
+ }
2957
+ function WorkspaceNavigation(props){
2958
+ var active=props.current==='create'?'home':props.current;
2959
+ return e('header',{className:'sa-workspace-toolbar'},
2960
+ e('nav',{'aria-label':'SA 工作台导航',className:'sa-workspace-tabs'},[['home','需求'],['kb','知识库'],['plib','归档库'],['settings','工作方法']].map(function(t){return e('button',{key:t[0],type:'button','aria-current':active===t[0]?'page':undefined,onClick:function(){props.onNavigate(t[0])}},t[1])})),
2961
+ e('span',{className:'sa-workspace-label'},'SA 工作台'),
2962
+ e('button',{className:'sa-mobile-create',type:'button','aria-label':'新建需求',onClick:function(){props.onNavigate('create')}},e(UiIcon,{name:'plus'})),
2963
+ e('div',{className:'sa-theme-switch','aria-label':'工作台外观'},['light','dark'].map(function(a){return e('button',{key:a,type:'button','aria-label':a==='light'?'浅色模式':'暗色模式','aria-pressed':(pmBus.state.appearance || saAppearance())===a,onClick:function(){setSaAppearance(a)}},a==='light'?'☀':'☾')})))
2964
+ }
2965
+ function stageDeliverableModel(stage,requirement,artifact){
2966
+ var definitions={
2967
+ intake:{title:'一份可继续设计的业务需求',items:['业务目标与使用场景','范围、现状与资料依据','需要进一步确认的问题']},
2968
+ solution:{title:'一份可讨论的高阶方案',items:['关键设计点与系统职责','业务流程、依赖及改造范围','方案依据与待决策事项']},
2969
+ prd:{title:'一份可评审、可验证的 PRD',items:['用户故事与完整业务规则','Given / When / Then 验收条件','相关流程与交互说明']},
2970
+ prototype:{title:'一份可操作的交互原型',items:['主要页面与关键任务路径','适用的正常、异常与空状态','供讨论与迭代的页面交互']}
2971
+ };
2972
+ var model=definitions[stage] || definitions.intake;
2973
+ var prior=stage==='solution'?['intake']:stage==='prd'?['intake','solution']:stage==='prototype'?['prd']:[];
2974
+ var missing=prior.filter(function(id){var s=(requirement.stages || []).find(function(s){return s.id===id});return !s || !(s.artifacts || []).some(function(a){return a.exists})});
2975
+ return {title:model.title,items:model.items,missing:missing.map(function(id){return {intake:'业务需求',solution:'高阶方案',prd:'PRD'}[id]}),file:artifact && artifact.path,archived:!!requirement.archived};
2976
+ }
2977
+ function StageDeliverablePreview(props){
2978
+ var model=stageDeliverableModel(props.stage,props.requirement,props.artifact);
2979
+ if(model.archived)return null;
2980
+ return e('aside',{className:'sa-deliverable','aria-label':'本阶段交付预览'},
2981
+ e('div',{className:'sa-deliverable__eyebrow'},'本阶段交付'),e('h4',null,model.title),
2982
+ e('ul',null,model.items.map(function(text,i){return e('li',{key:text},e('span',{'aria-hidden':true},String(i+1).padStart(2,'0')),text)})),
2983
+ model.missing.length>0 && e('p',{className:'sa-deliverable__missing'},'尚未发现'+model.missing.join('、')+'文档。助手会先核对依据,必要时补充澄清。'),
2984
+ e('p',{className:'sa-deliverable__hint'},'以上为预期内容,当前尚未生成;生成后仍需评审。'))
2985
+ }
2986
+ function RequirementKanban(props){
2987
+ return e('div',{className:'sa-requirement-board','aria-label':'需求状态看板'},[['waiting','待启动'],['running','进行中'],['done','已完成']].map(function(group){
2988
+ var rows=props.requirements.filter(function(r){return overviewStatus(r)===group[0]});
2989
+ return e('section',{key:group[0],className:'sa-board-column'},e('header',null,e('span',{className:'pmw-stage-pill is-'+group[0]},e('i',{'aria-hidden':true}),group[1]),e('span',null,rows.length)),
2990
+ rows.length?rows.map(function(req){var c=collaborationValue(req),stages=req.stages || [],existing=stages.filter(function(s){return (s.artifacts || []).some(function(a){return a.exists})}).length;return e('button',{key:req.id,className:'sa-board-card',onClick:function(){props.onOpen(req)},'aria-label':'查看 '+req.code+' '+req.title},e('code',null,req.code),e('strong',null,req.title),e('span',{className:'sa-board-card__stage'},stageTitle(req)),e('footer',null,e('span',null,c.pmOwner || 'SA 待填写'),e('span',null,existing?existing+' 个阶段已有稿':'尚无阶段稿')))}):e('p',{className:'sa-board-empty'},'当前筛选下暂无需求'))
2991
+ }))
2992
+ }
2993
+
2940
2994
  function Panel(props) {
2941
2995
  var layout = props.layout
2942
2996
  var pm = props.pm
@@ -2949,6 +3003,7 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
2949
3003
  var form = useState('home')
2950
3004
  var view = form[0]
2951
3005
  var setView = form[1]
3006
+ var pendingNavigationSt=useState(null),pendingNavigation=pendingNavigationSt[0],setPendingNavigation=pendingNavigationSt[1]
2952
3007
  var ft = useState('')
2953
3008
  var formTitle = ft[0]
2954
3009
  var setFormTitle = ft[1]
@@ -3348,7 +3403,7 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3348
3403
  return pm.sendToReq(selected, dir, body.prompt).then(function (res) {
3349
3404
  setBusy(false)
3350
3405
  if (!res || !res.ok) setOpErr((res && res.error) || '发送失败')
3351
- else {setNotice('已发送到对话 · 使用 '+body.skill.name+';请在会话中查看进展。');if(stageId==='intake')return apiSend('POST','/requirement-start',{id:selected.id}).then(reload)}
3406
+ else {pmBus.set({focus:false});setNotice('已发送到对话 · 使用 '+body.skill.name+';请在会话中查看进展。');if(stageId==='intake')return apiSend('POST','/requirement-start',{id:selected.id}).then(reload)}
3352
3407
  })
3353
3408
  }).catch(function (err) {
3354
3409
  setBusy(false)
@@ -3517,10 +3572,16 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3517
3572
  }).catch(function(err) { if (pmBus.state.selectedId === owner.id) setOpErr(String(err.message || err)) }).finally(function(){setBusy(false)})
3518
3573
  }
3519
3574
 
3575
+ function navigateWorkspace(target){
3576
+ if(editor){setPendingNavigation(target);return}
3577
+ completeNavigation(target)
3578
+ }
3579
+ function completeNavigation(target){setPendingNavigation(null);setEditor(null);pmBus.set({nav:target,selectedId:null,activeSessionId:null,settingsReturn:null});setView(target)}
3580
+ var workspaceNav=e(WorkspaceNavigation,{current:view,onNavigate:navigateWorkspace})
3520
3581
  var children = []
3521
3582
 
3522
- if (data.data && (data.data.setupRequired || data.data.restartRequired)) return e('div',{className:'pmw-root','data-sa-appearance':bus.appearance || saAppearance()},e(SettingsPanel))
3523
- if (view === 'settings') return e('div', { className: 'pmw-root', 'data-sa-appearance':bus.appearance || saAppearance() }, e(SettingsPanel))
3583
+ if (data.data && (data.data.setupRequired || data.data.restartRequired)) return e('div',{className:'pmw-root','data-sa-appearance':bus.appearance || saAppearance()},e(SettingsPanel,{onboarding:true,onComplete:function(){pmBus.set({nav:'home',selectedId:null,activeSessionId:null,settingsReturn:null});setView('home');reload()}}))
3584
+ if (view === 'settings') return e('div', { className: 'pmw-root sa-workspace-shell', 'data-sa-appearance':bus.appearance || saAppearance() },e('style',null,WORKSPACE_PREVIEW_CSS),workspaceNav,e('div',{className:'sa-settings-scroll'},e(SettingsPanel)))
3524
3585
 
3525
3586
  // header(纯标题,动作全部收进各自语境:Tab 空态/地铁图归档站/右栏线程条)
3526
3587
  if (!selected && (view !== 'home' || !data.data)) children.push(e('div', { className: 'pmw-header', key: 'header' },
@@ -3541,7 +3602,7 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3541
3602
  e('div',{className:'pmw-dialog__body'},e('label',{className:'pmw-field'},e('span',{className:'pmw-field__label'},'文件名称'),e('input',{className:'pmw-input',autoFocus:true,'aria-label':'文件名称',value:newFile.name,maxLength:110,onChange:function(ev){setNewFile(Object.assign({},newFile,{name:ev.target.value}))},placeholder:'例如:接口说明'})),
3542
3603
  e('label',{className:'pmw-field'},e('span',{className:'pmw-field__label'},'文档内容'),e('textarea',{className:'pmw-textarea','aria-label':'新增文档内容',value:newFile.content,onChange:function(ev){setNewFile(Object.assign({},newFile,{content:ev.target.value}))},placeholder:'支持 Markdown'})),opErr && e('p',{role:'alert'},opErr)),
3543
3604
  e('div',{className:'pmw-dialog__foot'},e('button',{type:'button',className:'pmw-btn',disabled:isBusy,onClick:function(){setNewFile(null)}},'取消'),e('button',{type:'submit',className:'pmw-btn pmw-btn--primary',disabled:isBusy || !newFile.name.trim() || !newFile.content.trim()},isBusy?'正在添加…':'添加文档')))))
3544
- return e('div', { ref:rootRef, className: 'pmw-root' + (expanded ? ' is-expanded' : ''), 'data-sa-appearance':bus.appearance || saAppearance() }, children)
3605
+ return e('div', { ref:rootRef, className: 'pmw-root sa-workspace-shell' + (expanded ? ' is-expanded' : ''), 'data-sa-appearance':bus.appearance || saAppearance() },e('style',null,WORKSPACE_PREVIEW_CSS),!expanded && workspaceNav,pendingNavigation && e(DetailDialog,{title:'离开未保存的文档?',onClose:function(){setPendingNavigation(null)},footer:e(React.Fragment,null,e('button',{className:'pmw-btn',onClick:function(){setPendingNavigation(null)}},'继续编辑'),e('button',{className:'pmw-btn pmw-btn--primary',onClick:function(){completeNavigation(pendingNavigation)}},'放弃修改并离开'))},e('p',null,'当前修改尚未保存。继续编辑可保留草稿;离开将放弃这些修改,原文件不变。')),children)
3545
3606
  }
3546
3607
 
3547
3608
  // body: main + chat
@@ -3676,13 +3737,10 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3676
3737
  return e('button', { key: stage.id, className: 'pmw-step' + (stage.id === curTab ? ' is-active' : '') + (exists ? ' is-complete' : '') + (current ? ' is-current' : '') + (optional ? ' is-optional' : ''),
3677
3738
  'aria-pressed': stage.id === curTab, 'aria-current': current ? 'step' : undefined, title: stage.title + ' · ' + (exists ? '已有文档' : '尚未生成') + (stage.id === curTab ? ' · 正在查看' : ''),
3678
3739
  onClick: function () { if (stage.id === curTab) return; if (editor && !confirm('有未保存的修改,确定放弃并切换文档?')) return; setEditor(null); setTabSt(stage.id) },
3679
- }, e('span', { className: 'pmw-step__number', 'aria-hidden': true }, exists ? e(UiIcon,{name:'check'}) : String(index + 1)),
3740
+ },index>0 && e('span',{className:'sa-stage-connector'+(optional?' is-optional':'')+((exists || current) && selected.stages[index-1].artifacts[0].exists?' is-reached':''),'aria-hidden':true}),e('span',{className:'pmw-step__number','aria-hidden':true},e(StageGlyph,{stage:stage.id}),exists && e('span',{className:'sa-stage-done'},e(UiIcon,{name:'check'}))),
3680
3741
  e('span', {className:'pmw-step__label'}, label), e('small', null, status))
3681
3742
  })
3682
- metroNodes.unshift(e('svg',{key:'route',className:'pmw-metro__track',viewBox:'0 0 1000 64',preserveAspectRatio:'none','aria-hidden':true},
3683
- e('path',{className:'pmw-metro__line',d:'M125 20 H625',vectorEffect:'non-scaling-stroke'}),
3684
- progressX > 125 && e('path',{className:'pmw-metro__line is-travelled',d:'M125 20 H'+progressX,vectorEffect:'non-scaling-stroke'}),
3685
- e('path',{className:'pmw-metro__line pmw-metro__branch'+(prototypeExists ? ' is-travelled' : ''),d:'M625 20 H875',vectorEffect:'non-scaling-stroke'})))
3743
+
3686
3744
 
3687
3745
  var currentDocReady = doc && curArt && doc.path === curArt.path && !doc.loading && !doc.error
3688
3746
  var cloudReceipt = currentDocReady && doc.receipt
@@ -3713,20 +3771,9 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3713
3771
  var sourcesNode = curTab === 'intake' && e(SourceInputs,{key:'sources-'+selected.id,id:selected.id,readOnly:!!selected.archived,hasDoc:!!(curArt && curArt.exists),stageBusy:isBusy,onBusy:setSourceBusy,onStart:function(){handStage('intake')}})
3714
3772
  if (!curArt || !curArt.exists) {
3715
3773
  var emptyCopy={intake:['梳理业务需求','从你的诉求和业务资料开始,澄清目标、使用场景与范围,保留待确认的问题。','梳理需求'],solution:['形成高阶方案','结合业务需求与现状,明确系统职责、改造方向、依赖与未决事项。','设计高阶方案'],prd:['编写 PRD','基于需求与高阶方案,展开可验证的功能、业务规则和验收条件。','编写 PRD'],prototype:['制作交互原型','用可操作的页面检验 PRD 中的流程与交互。原型按需交付,不阻止归档。','制作原型']}[curTab]
3716
- contentNode = e('div', { className: 'pmw-doc pmw-doc--empty', key: 'empty' },e('section',{className:'pmw-empty-state'},
3717
- e('div',{className:'pmw-empty-state__heading'},
3718
- e('div',{className:'pmw-empty-state__icon','aria-hidden':true},e(UiIcon,{name:curTab==='prototype'?'select':'doc'})),
3719
- e('h3',null,selected.archived ? '本次归档未包含'+documentName : emptyCopy[0])),
3720
- e('p',{className:'pmw-empty-state__description'},selected.archived ? '此归档保留了当时已有的交付文件,未生成的文档不会自动补齐。' : emptyCopy[1]),
3721
- sourcesNode,
3722
- curArt && e('div',{className:'pmw-empty-state__file'},e(UiIcon,{name:'doc'}),selected.archived?'未包含文件':'交付文件',e('code',null,curArt.path)),
3723
- !selected.archived && curArt && e('button', {
3724
- className: 'pmw-btn pmw-btn--primary',
3725
- disabled: isBusy || sourceBusy,
3726
- onClick: function () { handStage(curTab) },
3727
- }, isBusy ? '正在准备…' : '开始动手吧'),
3728
- !selected.archived && e('p',{className:'pmw-empty-state__note'},'使用当前绑定的工作方法发送到当前对话;信息不足时先澄清。'),
3729
- ))
3774
+ contentNode=e('div',{className:'pmw-doc pmw-doc--empty',key:'empty'},e('div',{className:'sa-empty-workspace'},
3775
+ e(StageStartCard,{stage:curTab,title:selected.archived?'本次归档未包含'+documentName:emptyCopy[0],description:selected.archived?'此归档保留了当时已有的交付文件,未生成的文档不会自动补齐。':emptyCopy[1],artifact:curArt,archived:!!selected.archived,sources:sourcesNode,busy:isBusy || sourceBusy,onStart:function(){handStage(curTab)}}),
3776
+ e(StageDeliverablePreview,{stage:curTab,requirement:selected,artifact:curArt})))
3730
3777
  } else if (doc && doc.path === curArt.path) {
3731
3778
  var isHtml = /\.html?$/i.test(doc.path)
3732
3779
  // UX 标注工具条:原型 Tab、当前版本即出现;已归档降级为只读(可看 pin,不可新增/改稿)
@@ -3785,10 +3832,10 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3785
3832
  mainChildren.push(e('div', { className: 'pmw-detail', key: 'detail' },
3786
3833
  !expanded && e('div', { className: 'pmw-detail__head' },
3787
3834
  e('h2', { className: 'pmw-detail__title' }, selected.title),
3788
- e('button',{className:'pmw-btn pmw-btn--ghost',onClick:function(){setRequirementInfo(selected)}},e(UiIcon,{name:'settings'}),'协作信息'),
3835
+ e('button',{className:'pmw-btn pmw-btn--ghost',onClick:function(){setRequirementInfo(selected)}},e(UiIcon,{name:'users'}),'协作信息'),
3789
3836
  selected.code ? e('span', { className: 'pmw-tag pmw-tag--code' }, selected.code) : null,
3790
3837
  e('span', { className: 'pmw-detail__version' }, selected.version || '未排期'),
3791
- e('button', { className: 'pmw-btn pmw-btn--ghost pmw-btn--icon', 'aria-label': bus.focus ? '显示会话' : '专注阅读', 'aria-pressed': bus.focus, onClick: function () { pmBus.set({ focus: !bus.focus }) } }, e(UiIcon, { name: 'focus' })),
3838
+ e('button', { className: 'pmw-btn pmw-btn--ghost sa-assistant-toggle', 'aria-label':bus.focus?'打开需求助手':'收起需求助手','aria-expanded':!bus.focus,onClick:function(){pmBus.set({focus:!bus.focus})} },e(UiIcon,{name:'chat'}),bus.focus?'助手':'收起助手'),
3792
3839
  ),
3793
3840
  !expanded && e('nav', { className: 'pmw-stages', 'aria-label': '需求交付阶段' }, metroNodes),
3794
3841
  tabBar,
@@ -3842,7 +3889,7 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3842
3889
  var chatError = bus.sessionError || (convRef && convRef.id === activeSessionId && convRef.error)
3843
3890
  chatNode = e('div', { className: 'pmw-ai', key: 'ai' },
3844
3891
  barNode,
3845
- e('div', { className: 'pmw-ai__context' }, e(UiIcon, { name: 'link' }), e('span', null, selected.code + ' · ' + selected.title)),
3892
+ e('div', { className: 'pmw-ai__context' }, e(UiIcon, { name: 'link' }), e('span', null, selected.code + ' · ' + selected.title),e('button',{className:'pmw-btn pmw-btn--ghost','aria-label':'收起需求助手',onClick:function(){pmBus.set({focus:true})}},e(UiIcon,{name:'close'}))),
3846
3893
  canChat
3847
3894
  ? e('div', { className: 'pmw-ai__conv', key: 'conv' },
3848
3895
  e(props.SessionProvider, { session: convRef.ref }, props.renderSlot('pm.conv', {})))
@@ -3881,7 +3928,7 @@ div:has(> [data-slot='sidebar.footer.action']) { display: contents; }
3881
3928
  e('div',{className:'pmw-dialog__body'},e('label',{className:'pmw-field'},e('span',{className:'pmw-field__label'},'文件名称'),e('input',{className:'pmw-input',autoFocus:true,'aria-label':'文件名称',value:newFile.name,maxLength:110,onChange:function(ev){setNewFile(Object.assign({},newFile,{name:ev.target.value}))},placeholder:'例如:接口说明'})),
3882
3929
  e('label',{className:'pmw-field'},e('span',{className:'pmw-field__label'},'文档内容'),e('textarea',{className:'pmw-textarea','aria-label':'新增文档内容',value:newFile.content,onChange:function(ev){setNewFile(Object.assign({},newFile,{content:ev.target.value}))},placeholder:'支持 Markdown'})),opErr && e('p',{role:'alert'},opErr)),
3883
3930
  e('div',{className:'pmw-dialog__foot'},e('button',{type:'button',className:'pmw-btn',disabled:isBusy,onClick:function(){setNewFile(null)}},'取消'),e('button',{type:'submit',className:'pmw-btn pmw-btn--primary',disabled:isBusy || !newFile.name.trim() || !newFile.content.trim()},isBusy?'正在添加…':'添加文档')))))
3884
- return e('div', { ref:rootRef, className: 'pmw-root' + (expanded ? ' is-expanded' : ''), 'data-sa-appearance':bus.appearance || saAppearance() }, children)
3931
+ return e('div', { ref:rootRef, className: 'pmw-root sa-workspace-shell' + (expanded ? ' is-expanded' : ''), 'data-sa-appearance':bus.appearance || saAppearance() },e('style',null,WORKSPACE_PREVIEW_CSS),!expanded && workspaceNav,pendingNavigation && e(DetailDialog,{title:'离开未保存的文档?',onClose:function(){setPendingNavigation(null)},footer:e(React.Fragment,null,e('button',{className:'pmw-btn',onClick:function(){setPendingNavigation(null)}},'继续编辑'),e('button',{className:'pmw-btn pmw-btn--primary',onClick:function(){completeNavigation(pendingNavigation)}},'放弃修改并离开'))},e('p',null,'当前修改尚未保存。继续编辑可保留草稿;离开将放弃这些修改,原文件不变。')),children)
3885
3932
  }
3886
3933
 
3887
3934
  // -----------------------------------------------------------------------
@@ -1 +1 @@
1
- {"type":"module","version":"0.1.27"}
1
+ {"type":"module","version":"0.1.29"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-sa-workbench",
3
- "version": "0.1.27",
3
+ "version": "0.1.29",
4
4
  "description": "SA 工作台:需求整理、方案、PRD、原型和交付归档,一个插件统一安装与更新。",
5
5
  "type": "module",
6
6
  "main": "index.js",