dsh-aris-panel 0.1.4 → 0.1.5

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/dsh/client.js CHANGED
@@ -222,25 +222,25 @@ function inferStage(ov) {
222
222
  }
223
223
 
224
224
  const WORKFLOW_CHIPS = [
225
- { num: 'W1', label: 'Idea Discovery 想法发现', entry: 'idea-discovery', desc: '完整想法发现管线:多源文献调研 → 头脑风暴 8-12 个具体想法 → 可行性与算力过滤 → 深度新颖性验证 + 魔鬼代言人审 → top 2-3 想法并行 GPU 试跑(30min-2h) → 按实验信号排名 → 精炼出问题锚定提案 → claim 驱动的实验路线图。产出 IDEA_REPORT.md 排名报告 + FINAL_PROPOSAL + EXPERIMENT_PLAN。' },
226
- { num: 'W1.5', label: 'Experiment Bridge 实验桥接', entry: 'experiment-bridge', desc: '把实验计划变成运行结果:解析 EXPERIMENT_PLAN.md → 实现实验代码(带 argparse/日志/种子) → GPT-5.6-Sol 审代码抓逻辑 bug → 最小实验 sanity check → 部署 GPU 跑全套 → 收集结果更新实验追踪。' },
227
- { num: 'W2', label: 'Auto Review Loop 自动审稿循环', entry: 'auto-review-loop', desc: '无人值守审稿循环:外部审稿人深审论文/claims/实验指出弱点 → 自动修复(重写章节/加 baseline/补实验) → 重新评估,循环直到 ≥6/10 或 4 轮上限;>4 GPU 小时的实验自动跳过并标记人工跟进,断点可从 REVIEW_STATE.json 恢复。' },
228
- { num: 'W3', label: 'Paper Writing 论文写作', entry: 'paper-writing', desc: '从叙事报告到可投稿 PDF:claims-evidence 矩阵 + 章节规划 → 数据驱动图表 → 逐节 LaTeX → 编译 PDF 修错 + 页数检查 → 两轮外部内容审 + 最终格式检查。' },
229
- { num: 'W4', label: 'Rebuttal 回复审稿', entry: 'rebuttal', desc: '安全回复审稿意见:解析意见拆成 issue 卡片 → 全局策略 + 逐审稿人优先级 → 可选自动补实验 → 起草回复 → 6 项安全检查(覆盖/溯源/承诺/语气/一致性/字数) → GPT 压力测试 → 输出限字版 + 富文本版。' },
230
- { num: 'W5', label: 'Resubmit 换会重投', entry: 'resubmit-pipeline', desc: '换会议重投:硬约束(不加实验/不改 bib/不改框架/不覆盖旧稿) → 物理隔离 + 5 层匿名检查 → 白名单微编辑 → kill-argument 对抗门 → RESUBMIT_REPORT 七态账本。' },
231
- { num: 'W6', label: 'Conference Talk 会议演讲', entry: 'paper-talk', desc: '从论文到会议演讲:演讲大纲 → Beamer + PPTX + 讲稿 + Q&A 准备 → 逐页打磨 → claim/citation/匿名审计门。' },
225
+ { num: 'W1', label: 'Idea Discovery 想法发现', entry: 'idea-discovery', when: '开始新研究,有方向但还没想法时', desc: '完整想法发现管线:多源文献调研 → 头脑风暴 8-12 个具体想法 → 可行性与算力过滤 → 深度新颖性验证 + 魔鬼代言人审 → top 2-3 想法并行 GPU 试跑(30min-2h) → 按实验信号排名 → 精炼出问题锚定提案 → claim 驱动的实验路线图。产出 IDEA_REPORT.md 排名报告 + FINAL_PROPOSAL + EXPERIMENT_PLAN。' },
226
+ { num: 'W1.5', label: 'Experiment Bridge 实验桥接', entry: 'experiment-bridge', when: '已有实验计划,需要落地实现代码并跑出结果时', desc: '把实验计划变成运行结果:解析 EXPERIMENT_PLAN.md → 实现实验代码(带 argparse/日志/种子) → GPT-5.6-Sol 审代码抓逻辑 bug → 最小实验 sanity check → 部署 GPU 跑全套 → 收集结果更新实验追踪。' },
227
+ { num: 'W2', label: 'Auto Review Loop 自动审稿循环', entry: 'auto-review-loop', when: '论文/结果需要迭代打磨、想挂机自动改进时', desc: '无人值守审稿循环:外部审稿人深审论文/claims/实验指出弱点 → 自动修复(重写章节/加 baseline/补实验) → 重新评估,循环直到 ≥6/10 或 4 轮上限;>4 GPU 小时的实验自动跳过并标记人工跟进,断点可从 REVIEW_STATE.json 恢复。' },
228
+ { num: 'W3', label: 'Paper Writing 论文写作', entry: 'paper-writing', when: '叙事报告就绪、准备把研究写成论文时', desc: '从叙事报告到可投稿 PDF:claims-evidence 矩阵 + 章节规划 → 数据驱动图表 → 逐节 LaTeX → 编译 PDF 修错 + 页数检查 → 两轮外部内容审 + 最终格式检查。' },
229
+ { num: 'W4', label: 'Rebuttal 回复审稿', entry: 'rebuttal', when: '收到会议/期刊审稿意见时', desc: '安全回复审稿意见:解析意见拆成 issue 卡片 → 全局策略 + 逐审稿人优先级 → 可选自动补实验 → 起草回复 → 6 项安全检查(覆盖/溯源/承诺/语气/一致性/字数) → GPT 压力测试 → 输出限字版 + 富文本版。' },
230
+ { num: 'W5', label: 'Resubmit 换会重投', entry: 'resubmit-pipeline', when: '论文需在硬约束下换到另一个会议重投时', desc: '换会议重投:硬约束(不加实验/不改 bib/不改框架/不覆盖旧稿) → 物理隔离 + 5 层匿名检查 → 白名单微编辑 → kill-argument 对抗门 → RESUBMIT_REPORT 七态账本。' },
231
+ { num: 'W6', label: 'Conference Talk 会议演讲', entry: 'paper-talk', when: '论文录用后准备会议演讲时', desc: '从论文到会议演讲:演讲大纲 → Beamer + PPTX + 讲稿 + Q&A 准备 → 逐页打磨 → claim/citation/匿名审计门。' },
232
232
  ]
233
233
  const AUDIT_CHIPS = [
234
- { label: '实验诚实度审计', skill: 'experiment-audit', desc: '审计 eval 代码是否诚实:检查是否有假 ground truth、分数自归一化、幻影结果、范围不足——结果可信前必跑。' },
235
- { label: '结果→声明判定', skill: 'result-to-claim', desc: '判定结果支持什么:Codex 评估实验对既定 claims 的支持度,路由下一步(转向/补充/确认),实验完成后、写论文前跑。' },
236
- { label: '论文数字核对', skill: 'paper-claim-audit', desc: '核对论文数字:零上下文审稿人核对每个数字/比较/范围声明是否与原始结果一致,防止确认偏差。' },
237
- { label: '引用真实性审计', skill: 'citation-audit', desc: '审计每条引用:文献必须真实存在、归属正确、上下文确实支持——抓幻觉作者/错年份/假 venue/错上下文。' },
238
- { label: '最强拒稿模拟', skill: 'kill-argument', desc: '拒稿压力测试:新审稿人写 200 词最强拒稿信,第二名独立审稿人逐点辩护并暴露仍未解决的关键问题。' },
234
+ { label: '实验诚实度审计', skill: 'experiment-audit', when: '实验完成后、写 claim 之前', desc: '审计 eval 代码是否诚实:检查是否有假 ground truth、分数自归一化、幻影结果、范围不足——结果可信前必跑。' },
235
+ { label: '结果→声明判定', skill: 'result-to-claim', when: '实验完成、写论文之前', desc: '判定结果支持什么:Codex 评估实验对既定 claims 的支持度,路由下一步(转向/补充/确认),实验完成后、写论文前跑。' },
236
+ { label: '论文数字核对', skill: 'paper-claim-audit', when: '论文初稿完成后、投稿前', desc: '核对论文数字:零上下文审稿人核对每个数字/比较/范围声明是否与原始结果一致,防止确认偏差。' },
237
+ { label: '引用真实性审计', skill: 'citation-audit', when: '投稿前', desc: '审计每条引用:文献必须真实存在、归属正确、上下文确实支持——抓幻觉作者/错年份/假 venue/错上下文。' },
238
+ { label: '最强拒稿模拟', skill: 'kill-argument', when: '投稿前 / 冲顶会前', desc: '拒稿压力测试:新审稿人写 200 词最强拒稿信,第二名独立审稿人逐点辩护并暴露仍未解决的关键问题。' },
239
239
  ]
240
240
  const MEMORY_CHIPS = [
241
- { label: 'research-wiki 知识库', skill: 'research-wiki', desc: '跨会话研究记忆:论文/想法/实验/声明四类实体 + 图谱边;失败想法成为反重复记忆,下次构思自动避开踩过的坑。' },
242
- { label: 'wiki 补全', skill: 'wiki-enrich', desc: '补全 research-wiki 的论文页 TODO 区,把批量导入留下的骨架填充成完整摘要。' },
243
- { label: 'meta-optimize 自我优化', skill: 'meta-optimize', desc: 'ARIS 自我优化:分析 .aris/meta 使用日志,提议改进 SKILL.md 与工作流默认值,改动需审稿门控 + 人工批准。' },
241
+ { label: 'research-wiki 知识库', skill: 'research-wiki', when: '项目初始化时初始化一次,之后持续使用', desc: '跨会话研究记忆:论文/想法/实验/声明四类实体 + 图谱边;失败想法成为反重复记忆,下次构思自动避开踩过的坑。' },
242
+ { label: 'wiki 补全', skill: 'wiki-enrich', when: '批量导入论文后', desc: '补全 research-wiki 的论文页 TODO 区,把批量导入留下的骨架填充成完整摘要。' },
243
+ { label: 'meta-optimize 自我优化', skill: 'meta-optimize', when: '使用一段时间、积累了运行日志后', desc: 'ARIS 自我优化:分析 .aris/meta 使用日志,提议改进 SKILL.md 与工作流默认值,改动需审稿门控 + 人工批准。' },
244
244
  ]
245
245
  function WbPanoCard(props) {
246
246
  const it = props.item
@@ -253,6 +253,7 @@ function WbPanoCard(props) {
253
253
  h('div', { className: 'wb-pano-card-head' },
254
254
  it.num ? h('span', { className: 'wb-pano-num' }, it.num) : null,
255
255
  h('span', { className: 'wb-pano-card-title' }, it.label)),
256
+ it.when ? h('div', { className: 'wb-pano-card-when' }, '何时调用: ' + it.when) : null,
256
257
  it.desc ? h('div', { className: 'wb-pano-card-desc' }, it.desc) : null,
257
258
  h('div', { className: 'wb-pano-card-entry' }, '入口: ' + entry))
258
259
  }
@@ -287,6 +288,137 @@ function WbGuide(props) {
287
288
  cur ? h('div', { className: 'wb-guide-next' }, '下一步建议:' + cur.next) : null)
288
289
  }
289
290
 
291
+
292
+ const SKILL_ZH = {
293
+ "ablation-planner": "消融实验规划(主结果通过后规划消融)",
294
+ "academic-research-suite": "学术研究套件(深度调研/写作/审稿)",
295
+ "agent-browser": "浏览器自动化",
296
+ "alphaxiv": "论文速读(AlphaXiv 摘要)",
297
+ "analyze-results": "实验结果分析统计",
298
+ "arxiv": "arXiv 论文搜索下载",
299
+ "auto-paper-improvement-loop": "论文自动改进循环(2轮外部审+修复)",
300
+ "auto-review-loop": "自动审稿循环(审→修→再审)",
301
+ "auto-review-loop-llm": "LLM 版自动审稿循环",
302
+ "auto-review-loop-minimax": "MiniMax 版自动审稿循环",
303
+ "baseline": "基线管理(复现/对比)",
304
+ "canvas-design": "画布设计(海报/艺术图)",
305
+ "citation-audit": "引用审计(防幻觉引用)",
306
+ "claims-drafting": "专利权利要求撰写",
307
+ "claude-api": "Claude API 应用开发",
308
+ "comm-lit-review": "通信领域文献综述",
309
+ "context-window-management": "上下文窗口管理",
310
+ "deepxiv": "DeepXiv 分层论文检索",
311
+ "document-skills": "办公文档处理套件",
312
+ "docx": "Word 文档处理",
313
+ "dse-loop": "设计空间探索循环(EDA)",
314
+ "embodiment-description": "专利实施例撰写",
315
+ "exa-search": "Exa AI 网络搜索",
316
+ "experiment-audit": "实验诚实度审计",
317
+ "experiment-bridge": "实验桥接(计划→代码→结果)",
318
+ "experiment-plan": "实验路线图规划",
319
+ "experiment-queue": "实验队列调度(多任务)",
320
+ "feishu-notify": "飞书通知",
321
+ "figure-description": "专利附图说明",
322
+ "figure-spec": "确定性矢量图(FigureSpec→SVG)",
323
+ "find-skills": "技能查找与安装",
324
+ "firecrawl": "网页抓取(Firecrawl)",
325
+ "formula-derivation": "公式推导",
326
+ "gemini-search": "Gemini 论文搜索",
327
+ "gpt-image-2": "GPT Image 2 图像生成",
328
+ "grant-proposal": "基金申请书撰写",
329
+ "guizang-ppt-skill": "网页 PPT 生成",
330
+ "idea": "想法假设分析",
331
+ "idea-creator": "头脑风暴生成想法",
332
+ "idea-discovery": "想法发现全流程(W1)",
333
+ "idea-discovery-robot": "机器人领域想法发现",
334
+ "integrity-forensics": "论文诚信取证审计",
335
+ "interview-cheatsheet": "面试速查表生成",
336
+ "invention-structuring": "发明披露结构化",
337
+ "j-space": "内心工作空间(长任务推理)",
338
+ "jurisdiction-format": "专利国别格式转换",
339
+ "kill-argument": "最强拒稿模拟",
340
+ "latex-paper-en": "英文 LaTeX 论文助手",
341
+ "latex-thesis-zh": "中文 LaTeX 学位论文助手",
342
+ "mano-cua": "图形界面自动化(VLA)",
343
+ "markitdown": "文档转 Markdown",
344
+ "mermaid-diagram": "Mermaid 图表生成",
345
+ "meta-apply": "优化补丁落地(需人工批准)",
346
+ "meta-optimize": "ARIS 自我优化",
347
+ "monitor-experiment": "实验监控",
348
+ "novelty-check": "新颖性查新",
349
+ "openalex": "OpenAlex 学术检索",
350
+ "overleaf-sync": "Overleaf 双向同步",
351
+ "paper-claim-audit": "论文数字核对",
352
+ "paper-compile": "论文编译(LaTeX→PDF)",
353
+ "paper-figure": "论文图表生成",
354
+ "paper-illustration": "AI 插图生成(Gemini)",
355
+ "paper-illustration-image2": "AI 插图生成(GPT-image)",
356
+ "paper-plan": "论文大纲规划",
357
+ "paper-poster": "会议海报(已废弃)",
358
+ "paper-poster-html": "HTML 会议海报",
359
+ "paper-slides": "会议幻灯片生成",
360
+ "paper-talk": "会议演讲全流程",
361
+ "paper-write": "论文写作(逐节 LaTeX)",
362
+ "paper-writing": "论文写作全流程(W3)",
363
+ "patent-novelty-check": "专利查新",
364
+ "patent-pipeline": "专利申请全流程",
365
+ "patent-review": "专利审查意见",
366
+ "pixel-art": "像素画 SVG",
367
+ "ppt-master": "多格式 PPT 生成",
368
+ "prior-art-search": "现有技术检索",
369
+ "proof-checker": "数学证明验证",
370
+ "proof-orchestrator": "定理证明项目管理",
371
+ "proof-writer": "数学证明写作",
372
+ "qzcli": "启智平台作业管理",
373
+ "rebuttal": "审稿意见回复(W4)",
374
+ "render-html": "Markdown 产物渲染 HTML",
375
+ "research-lit": "文献调研",
376
+ "research-pipeline": "研究全流程(W1→W3)",
377
+ "research-refine": "研究方案精炼",
378
+ "research-refine-pipeline": "方案精炼+实验规划串联",
379
+ "research-review": "研究深度审稿",
380
+ "research-wiki": "研究知识库",
381
+ "resubmit-pipeline": "换会重投(W5)",
382
+ "result-to-claim": "结果→声明判定",
383
+ "run-experiment": "跑实验(GPU)",
384
+ "scientific-agent-skills-suite": "科研技能套件入口",
385
+ "semantic-scholar": "Semantic Scholar 检索",
386
+ "serverless-modal": "Modal 无服务器 GPU",
387
+ "slides-polish": "幻灯片逐页打磨",
388
+ "specification-writing": "专利说明书撰写",
389
+ "system-profile": "系统性能分析",
390
+ "training-check": "训练健康检查",
391
+ "vast-gpu": "Vast.ai 租卡",
392
+ "web-access": "联网访问",
393
+ "web-debug-search": "开发者问题检索",
394
+ "wiki-enrich": "wiki 补全",
395
+ "writing-systems-papers": "系统论文写作指南",
396
+ "xlsx": "Excel 表格处理",
397
+ }
398
+
399
+ function WbProgress(props) {
400
+ const ov = props.overview
401
+ const stage = props.stage
402
+ const pipeline = ov && ov.pipeline
403
+ const phases = pipeline && pipeline.phases ? pipeline.phases : []
404
+ const doneCount = phases.filter(function (p) { return p.status === 'accepted' || p.status === 'done' }).length
405
+ const active = phases.some(function (p) { return p.status === 'running' || p.status === 'pending' })
406
+ const pct = phases.length > 0 ? Math.round(doneCount / phases.length * 100) : 0
407
+ const cur = FLOW_STAGES.find(function (s) { return s.id === stage })
408
+ return h('div', { className: 'wb-progress' },
409
+ h('div', { className: 'wb-guide-title' }, '执行进度' + (active ? '(工作流执行中,每 10 秒自动刷新)' : '')),
410
+ pipeline ? h('div', null,
411
+ wbKey('工作流', (pipeline.runId || '(unnamed run)') + ' · executor: ' + (pipeline.executor || 'unknown')),
412
+ h('div', { className: 'wb-bar' }, h('div', { className: 'wb-bar-fill', style: { width: pct + '%' } })),
413
+ wbKey('阶段进度', doneCount + '/' + phases.length + ' 完成 (' + pct + '%)'),
414
+ h('ul', { className: 'wb-list' }, phases.map(function (p) {
415
+ return h('li', { key: p.phase },
416
+ h('span', { className: 'wb-phase-' + p.status }, p.status),
417
+ ' ', h('code', null, p.phase),
418
+ p.artifact ? ' → ' + p.artifact : '')
419
+ }))) : wbNote('尚无执行中的工作流 — 从上方「功能全景」触发一个工作流后,这里显示实时进度'),
420
+ cur ? h('div', { className: 'wb-guide-next' }, '当前阶段(我的5步): ' + cur.title + ' → 下一步: ' + cur.next) : null)
421
+ }
290
422
  function WbTrigger(props) {
291
423
  const connection = props.connection
292
424
  const sessionId = props.sessionId
@@ -295,12 +427,21 @@ function WbTrigger(props) {
295
427
  const args = props.args
296
428
  const [status, setStatus] = React.useState(undefined)
297
429
  const skillError = props.skillError
430
+ const [effort, setEffort] = React.useState('balanced')
431
+ const [assurance, setAssurance] = React.useState('draft')
432
+ const [difficulty, setDifficulty] = React.useState('medium')
433
+ const [extra, setExtra] = React.useState('')
434
+ const [venue, setVenue] = React.useState('')
435
+ const [gpu, setGpu] = React.useState('')
436
+ const [reviewer, setReviewer] = React.useState('auto')
437
+ const [humanCheckpoint, setHumanCheckpoint] = React.useState(false)
438
+ const [autoProceed, setAutoProceed] = React.useState(true)
298
439
  const [busy, setBusy] = React.useState(false)
299
440
 
300
441
  const doLaunch = function () {
301
442
  if (!skill) { setStatus('请先选择技能'); return }
302
443
  setBusy(true)
303
- connection.rpc.call(WB_CHANNEL, 'launch', { sessionId: sessionId, skill: skill, args: args, autoProceed: props.autoProceed })
444
+ connection.rpc.call(WB_CHANNEL, 'launch', { sessionId: sessionId, skill: skill, args: args, autoProceed: autoProceed, effort: effort, assurance: assurance, difficulty: difficulty, venue: venue, gpu: gpu, reviewer: reviewer, humanCheckpoint: humanCheckpoint, extra: extra })
304
445
  .then(function (res) {
305
446
  if (res.ok) {
306
447
  setStatus(res.value.injected ? '已注入会话(' + res.value.method + '),执行已唤醒,请到会话窗口查看进度' : '未能注入,请复制提示词手动发送:' + res.value.prompt)
@@ -311,22 +452,81 @@ function WbTrigger(props) {
311
452
  .catch(function (e) { setStatus('触发失败:' + String(e)) })
312
453
  .finally(function () { setBusy(false) })
313
454
  }
455
+ const buildCmd = function () {
456
+ const params = []
457
+ if (autoProceed === false) params.push('AUTO_PROCEED: false')
458
+ if (effort !== 'balanced') params.push('effort: ' + effort)
459
+ if (assurance !== 'draft') params.push('assurance: ' + assurance)
460
+ if (difficulty !== 'medium') params.push('difficulty: ' + difficulty)
461
+ if (humanCheckpoint === true) params.push('human checkpoint: true')
462
+ if (venue) params.push('venue: ' + venue)
463
+ if (gpu) params.push('gpu: ' + gpu)
464
+ if (reviewer !== 'auto') params.push('reviewer: ' + reviewer)
465
+ const ex = extra.trim()
466
+ if (ex) params.push(ex)
467
+ const arg = args.trim()
468
+ return '/' + skill + (arg ? ' "' + arg + '"' : '') + (params.length > 0 ? ' — ' + params.join(', ') : '')
469
+ }
314
470
  const doCopy = function () {
315
471
  if (!skill) { setStatus('请先选择技能'); return }
316
- const text = '请使用 ARIS 技能 ' + WB_TICK + skill + WB_TICK + ' 完成对应工作流。' + (args ? ' 参数/方向:' + args : '')
317
- navigator.clipboard.writeText(text).then(function () { setStatus('提示词已复制,粘贴到会话发送即可') }).catch(function () { setStatus('复制失败,请手动复制:' + text) })
472
+ const text = buildCmd()
473
+ navigator.clipboard.writeText(text).then(function () { setStatus('命令已复制,粘贴到会话发送即可') }).catch(function () { setStatus('复制失败,请手动复制:' + text) })
318
474
  }
319
475
 
320
476
  const selectOptions = [h('option', { value: '', key: '' }, '— 选择 ARIS 技能 —')]
321
477
  ;(skills || []).forEach(function (s) {
322
- selectOptions.push(h('option', { key: s.name, value: s.name }, s.name + (s.description ? ' — ' + s.description.slice(0, 60) : '')))
478
+ selectOptions.push(h('option', { key: s.name, value: s.name }, s.name + ' — ' + (SKILL_ZH[s.name] || s.description || '').slice(0, 60)))
323
479
  })
324
480
 
325
481
  return h('div', { className: 'wb-trigger' },
326
482
  h('div', { className: 'wb-guide-title' }, '技能触发'),
327
483
  h('div', { className: 'wb-trigger-row' },
328
484
  h('select', { className: 'wb-skill-select', value: skill, onChange: function (e) { props.onSkill(e.target.value) } }, selectOptions),
329
- h('input', { className: 'wb-args', placeholder: '参数 / 研究方向(可选)', value: args, onChange: function (e) { props.onArgs(e.target.value) } })),
485
+ h('input', { className: 'wb-args', placeholder: '研究方向 (arguments):例如 discrete diffusion LMs 的 factorized gap', value: args, onChange: function (e) { props.onArgs(e.target.value) } })),
486
+ h('div', { className: 'wb-trigger-row wb-param-row' },
487
+ h('label', { className: 'wb-param-label' }, '无人值守: '),
488
+ h('select', { className: 'wb-param-select', value: autoProceed ? 'on' : 'off', onChange: function (e) { setAutoProceed(e.target.value === 'on') } },
489
+ h('option', { value: 'on' }, 'AUTO_PROCEED: true (自动继续)'),
490
+ h('option', { value: 'off' }, 'AUTO_PROCEED: false (每步确认)')),
491
+ h('label', { className: 'wb-param-label' }, '深度: '),
492
+ h('select', { className: 'wb-param-select', value: effort, onChange: function (e) { setEffort(e.target.value) } },
493
+ h('option', { value: 'lite' }, 'lite (轻量)'),
494
+ h('option', { value: 'balanced' }, 'balanced (默认)'),
495
+ h('option', { value: 'max' }, 'max (深度)'),
496
+ h('option', { value: 'beast' }, 'beast (极限)')),
497
+ h('label', { className: 'wb-param-label' }, '保证级: '),
498
+ h('select', { className: 'wb-param-select', value: assurance, onChange: function (e) { setAssurance(e.target.value) } },
499
+ h('option', { value: 'draft' }, 'draft (草稿)'),
500
+ h('option', { value: 'polished' }, 'polished (精修)'),
501
+ h('option', { value: 'conference-ready' }, 'conference-ready'),
502
+ h('option', { value: 'submission' }, 'submission (投稿级全审计)')),
503
+ h('label', { className: 'wb-param-label' }, '审稿强度: '),
504
+ h('select', { className: 'wb-param-select', value: difficulty, onChange: function (e) { setDifficulty(e.target.value) } },
505
+ h('option', { value: 'medium' }, 'medium (默认)'),
506
+ h('option', { value: 'hard' }, 'hard (更强)'),
507
+ h('option', { value: 'nightmare' }, 'nightmare (极限)'))),
508
+ h('div', { className: 'wb-trigger-row wb-param-row' },
509
+ h('label', { className: 'wb-param-label' }, '会议: '),
510
+ h('select', { className: 'wb-param-select', value: venue, onChange: function (e) { setVenue(e.target.value) } },
511
+ h('option', { value: '' }, '(默认)'),
512
+ h('option', { value: 'ICLR' }, 'ICLR'), h('option', { value: 'NeurIPS' }, 'NeurIPS'),
513
+ h('option', { value: 'ICML' }, 'ICML'), h('option', { value: 'CVPR' }, 'CVPR'),
514
+ h('option', { value: 'AAAI' }, 'AAAI'), h('option', { value: 'ACL' }, 'ACL')),
515
+ h('label', { className: 'wb-param-label' }, 'GPU: '),
516
+ h('select', { className: 'wb-param-select', value: gpu, onChange: function (e) { setGpu(e.target.value) } },
517
+ h('option', { value: '' }, '(默认)'), h('option', { value: 'local' }, 'local'),
518
+ h('option', { value: 'remote' }, 'remote'), h('option', { value: 'vast' }, 'vast'),
519
+ h('option', { value: 'modal' }, 'modal')),
520
+ h('label', { className: 'wb-param-label' }, '审稿路由: '),
521
+ h('select', { className: 'wb-param-select', value: reviewer, onChange: function (e) { setReviewer(e.target.value) } },
522
+ h('option', { value: 'auto' }, 'auto (默认)'), h('option', { value: 'codex' }, 'codex'),
523
+ h('option', { value: 'oracle-pro' }, 'oracle-pro'), h('option', { value: 'manual' }, 'manual')),
524
+ h('label', { className: 'wb-param-label' }, '人工确认: '),
525
+ h('select', { className: 'wb-param-select', value: humanCheckpoint ? 'true' : 'false', onChange: function (e) { setHumanCheckpoint(e.target.value === 'true') } },
526
+ h('option', { value: 'false' }, 'false (默认)'), h('option', { value: 'true' }, 'true (暂停批准)'))),
527
+ h('div', { className: 'wb-trigger-row' },
528
+ h('input', { className: 'wb-extra', placeholder: '其他参数 key: value, key2: value2(可选,如 sources: arxiv, web / gpu: vast)', value: extra, onChange: function (e) { setExtra(e.target.value) } })),
529
+ skill ? h('div', { className: 'wb-cmd-preview' }, 'ARIS 命令: ' + buildCmd()) : null,
330
530
  h('div', { className: 'wb-trigger-row' },
331
531
  h('button', { className: 'wb-btn', onClick: doLaunch, disabled: busy }, busy ? '触发中…' : '触发'),
332
532
  h('button', { className: 'wb-btn wb-btn-copy', onClick: doCopy }, '复制提示词')),
@@ -352,6 +552,48 @@ function WbArtifacts(props) {
352
552
  ' ', h('code', null, item.path))
353
553
  }))
354
554
  }
555
+ function renderAudits(audits) {
556
+ if (!audits) return wbNote('(no data)')
557
+ const ORDER = [
558
+ ['experiment-audit', '实验诚实度审计'],
559
+ ['result-to-claim', '结果→声明判定'],
560
+ ['paper-claim-audit', '论文数字核对'],
561
+ ['citation-audit', '引用真实性审计'],
562
+ ['kill-argument', '最强拒稿模拟'],
563
+ ]
564
+ const keys = Object.keys(audits)
565
+ const done = keys.map(function (k) { return k.replace(/\.(md|json)$/, '') })
566
+ const next = ORDER.find(function (o) { return done.indexOf(o[0]) === -1 })
567
+ const children = []
568
+ children.push(h('div', { className: 'wb-audit-order' }, '建议顺序: ' + ORDER.map(function (o) { return o[1] }).join(' → ')))
569
+ if (keys.length === 0) {
570
+ children.push(wbNote('尚无审计产物'))
571
+ } else {
572
+ children.push(h('ul', { className: 'wb-list' }, keys.map(function (k) {
573
+ const a = audits[k]
574
+ const v = a.verdict || '?'
575
+ const cls = 'wb-verdict wb-verdict-' + v.toLowerCase()
576
+ return h('li', { key: k },
577
+ h('span', { className: cls }, v),
578
+ ' ', h('code', null, k))
579
+ })))
580
+ }
581
+ if (next) children.push(wbNote('下一步建议: 先跑 ' + next[0] + '(' + next[1] + ')'))
582
+ return h('div', null, children)
583
+ }
584
+
585
+ function renderArtifactChain(artifacts) {
586
+ if (!artifacts) return wbNote('(no data)')
587
+ const CHAIN = ['IDEA_REPORT.md', 'refine-logs/FINAL_PROPOSAL.md', 'refine-logs/EXPERIMENT_PLAN.md', 'EXPERIMENT_LOG.md', 'NARRATIVE_REPORT.md', 'paper/main.pdf']
588
+ const has = function (pp) { const e = artifacts[pp]; return !!e && e.exists }
589
+ return h('ul', { className: 'wb-list' }, CHAIN.map(function (pp, i) {
590
+ return h('li', { key: pp },
591
+ h('span', { className: has(pp) ? 'wb-dot-ok' : 'wb-dot-missing' }, has(pp) ? '●' : '○'),
592
+ ' ', h('code', null, pp),
593
+ i < CHAIN.length - 1 ? ' →' : '')
594
+ }))
595
+ }
596
+
355
597
  function renderIdeaBoard(ideas) {
356
598
  if (!ideas) return wbNote('(no data)')
357
599
  const out = []
@@ -440,7 +682,6 @@ function ArisWorkbenchView(props) {
440
682
  const [skill, setSkill] = React.useState('')
441
683
  const [args, setArgs] = React.useState('')
442
684
  const [permPreset, setPermPreset] = React.useState('read-only')
443
- const [autoProceed, setAutoProceed] = React.useState(true)
444
685
  const [permStatus, setPermStatus] = React.useState(undefined)
445
686
 
446
687
  React.useEffect(function () {
@@ -477,9 +718,9 @@ function ArisWorkbenchView(props) {
477
718
 
478
719
  React.useEffect(function () { fetchSkills() }, [fetchSkills])
479
720
 
480
- const load = React.useCallback(function () {
721
+ const load = React.useCallback(function (silent) {
481
722
  if (!sessionId) return
482
- setBusy(true)
723
+ if (!silent) setBusy(true)
483
724
  const timeout = new Promise(function (_, reject) {
484
725
  setTimeout(function () { reject(new Error('RPC 超时(6s)')) }, 6000)
485
726
  })
@@ -489,6 +730,7 @@ function ArisWorkbenchView(props) {
489
730
  connection.rpc.call(WB_CHANNEL, 'wiki', { sessionId: sessionId }),
490
731
  connection.rpc.call(WB_CHANNEL, 'ideas', { sessionId: sessionId }),
491
732
  connection.rpc.call(WB_CHANNEL, 'experiments', { sessionId: sessionId }),
733
+ connection.rpc.call(WB_CHANNEL, 'audits', { sessionId: sessionId }),
492
734
  ]),
493
735
  timeout,
494
736
  ]).then(function (results) {
@@ -498,16 +740,26 @@ function ArisWorkbenchView(props) {
498
740
  setData(undefined)
499
741
  return
500
742
  }
501
- setData({ overview: results[0].value, wiki: results[1].value, ideas: results[2].value, experiments: results[3].value })
743
+ setData({ overview: results[0].value, wiki: results[1].value, ideas: results[2].value, experiments: results[3].value, audits: results[4].value })
502
744
  setError(undefined)
503
745
  }).catch(function (cause) {
504
746
  setError(String(cause))
505
747
  setData(undefined)
506
- }).finally(function () { setBusy(false) })
748
+ }).finally(function () { if (!silent) setBusy(false) })
507
749
  }, [connection, sessionId])
508
750
 
509
751
  React.useEffect(function () { load() }, [load])
510
752
 
753
+ // 自动轮询:工作流执行中每 10 秒静默刷新进度
754
+ React.useEffect(function () {
755
+ const timer = setInterval(function () {
756
+ const p = data && data.overview && data.overview.pipeline
757
+ const active = p && p.phases && p.phases.some(function (x) { return x.status === 'running' || x.status === 'pending' })
758
+ if (active) load(true)
759
+ }, 10000)
760
+ return function () { clearInterval(timer) }
761
+ }, [data, load])
762
+
511
763
  const ov = data && data.overview
512
764
  const wiki = data && data.wiki
513
765
  const ideas = data && data.ideas
@@ -545,14 +797,10 @@ function ArisWorkbenchView(props) {
545
797
  h('option', { value: 'read-only' }, 'Plan (只读)'),
546
798
  h('option', { value: 'workspace-write' }, 'Accept Edits (可改文件)'),
547
799
  h('option', { value: 'danger-full-access' }, 'Full Access (全自动)')),
548
- h('label', null, '无人值守: '),
549
- h('select', { className: 'wb-perm-select', value: autoProceed ? 'on' : 'off', onChange: function (e) { setAutoProceed(e.target.value === 'on') } },
550
- h('option', { value: 'on' }, 'AUTO_PROCEED on (自动继续)'),
551
- h('option', { value: 'off' }, 'AUTO_PROCEED off (每步确认)')),
552
800
  permStatus ? h('span', { className: 'wb-perm-status' }, permStatus) : null))
553
801
  children.push(h(WbPanorama, { key: 'pano', onPick: function (name) { setSkill(name) } }))
554
- children.push(h(WbGuide, { key: 'guide', stage: stage, onPick: function (name) { setSkill(name) } }))
555
- children.push(h(WbTrigger, { key: 'trigger', connection: connection, sessionId: sessionId, skills: skills, skill: skill, args: args, autoProceed: autoProceed, skillError: skillError, onSkill: setSkill, onArgs: setArgs }))
802
+ children.push(h(WbProgress, { key: 'progress', overview: ov, stage: stage }))
803
+ children.push(h(WbTrigger, { key: 'trigger', connection: connection, sessionId: sessionId, skills: skills, skill: skill, args: args, skillError: skillError, onSkill: setSkill, onArgs: setArgs }))
556
804
  }
557
805
  if (sessionId !== undefined && data === undefined && !error) children.push(wbNote('加载中…'))
558
806
  if (data) {
@@ -571,6 +819,10 @@ function ArisWorkbenchView(props) {
571
819
  wbKey('Last verdict', ov.state.last_verdict || '(n/a)')) : wbNote('尚无 review-stage/REVIEW_STATE.json(未跑过 auto-review-loop)'),
572
820
  h(WbArtifacts, (ov.artifacts && Object.keys(ov.artifacts).map(function (k) { return { path: k, exists: ov.artifacts[k].exists } })) || [])))
573
821
  children.push(h('div', { className: 'wb-grid2', key: 'status' }, [
822
+ h(WbSection, { title: '产物链', key: 'chain' },
823
+ renderArtifactChain(data.overview && data.overview.artifacts)),
824
+ h(WbSection, { title: '审计链状态', key: 'aud' },
825
+ renderAudits(data.audits)),
574
826
  h(WbSection, { title: 'Idea 看板', key: 'id' }, renderIdeaBoard(ideas)),
575
827
  h(WbSection, { title: '实验', key: 'ex' }, renderExperiments(exps)),
576
828
  h(WbSection, { title: 'Wiki 图谱', key: 'wk' }, renderWiki(wiki)),
@@ -648,12 +900,37 @@ const WB_CSS = `.wb-overlay { position: fixed; inset: 0; z-index: 9999; backgrou
648
900
  .wb-pano-card-head { display: flex; align-items: baseline; gap: 6px; }
649
901
  .wb-pano-num { font-weight: 800; color: #007acc; font-size: 12px; }
650
902
  .wb-pano-card-title { font-size: 13px; font-weight: 600; }
651
- .wb-pano-card-desc { font-size: 11px; opacity: .75; line-height: 1.45; }
903
+ .wb-pano-card-desc { font-size: 11px; color: #1f1f1f; line-height: 1.45; }
652
904
  .wb-pano-card-entry { font-size: 11px; color: #0066b8; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }.wb-perm-select { background: #ffffff; color: #1f1f1f; border: 1px solid #c8c8c8; border-radius: 4px; padding: 3px 8px; font-size: 12px; margin-right: 12px; }
653
905
  .wb-perm-status { font-size: 11px; color: #107c10; margin-left: 6px; }
654
906
 
655
907
  .wb-pano-card { min-height: 158px; padding: 12px 14px; }
656
908
  .wb-pano-card-desc { line-height: 1.55; }
909
+ .wb-param-row { align-items: center; }
910
+ .wb-param-label { font-size: 11px; opacity: .7; }
911
+ .wb-param-select { background: #ffffff; color: #1f1f1f; border: 1px solid #c8c8c8; border-radius: 4px; padding: 3px 6px; font-size: 12px; }
912
+ .wb-verdict { display: inline-block; border-radius: 8px; padding: 1px 8px; font-size: 10px; font-weight: 700; margin-right: 6px; }
913
+ .wb-verdict-pass { background: #dcffe4; color: #107c10; }
914
+ .wb-verdict-warn { background: #fff8c5; color: #9a6700; }
915
+ .wb-verdict-fail { background: #ffebe9; color: #c42b1c; }
916
+ .wb-verdict-blocked { background: #ffe4e6; color: #b91c1c; }
917
+ .wb-verdict-error { background: #f6f8fa; color: #57606a; }
918
+ .wb-verdict-not_applicable { background: #f6f8fa; color: #57606a; }
919
+ .wb-verdict-? { background: #f6f8fa; color: #57606a; }
920
+ .wb-extra { flex: 1 1 100%; background: #ffffff; color: #1f1f1f; border: 1px solid #c8c8c8; border-radius: 4px; padding: 5px 10px; font-size: 12px; min-width: 200px; }
921
+ .wb-cmd-preview { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; color: #24292e; background: #f5f5f5; border: 1px solid #e0e0e0; border-radius: 6px; padding: 8px 10px; margin: 6px 0 10px; word-break: break-all; }
922
+
923
+ .wb-pano-card-when { font-size: 13px; color: #1f1f1f; }
924
+
925
+ .wb-audit-order { font-size: 12px; color: #1f1f1f; margin-bottom: 6px; }
926
+ .wb-progress { margin-bottom: 18px; border: 1px solid #e0e0e0; border-radius: 6px; padding: 12px 16px; background: #f7f7f7; }
927
+ .wb-bar { height: 8px; background: #e8e8e8; border-radius: 4px; overflow: hidden; margin: 6px 0; }
928
+ .wb-bar-fill { height: 100%; background: #007acc; border-radius: 4px; transition: width .3s; }
929
+ .wb-phase-running { color: #0969da; font-weight: 600; }
930
+ .wb-phase-accepted { color: #107c10; font-weight: 600; }
931
+ .wb-phase-done { color: #9a6700; }
932
+ .wb-phase-failed { color: #c42b1c; }
933
+ .wb-phase-pending, .wb-phase-skipped { opacity: .5; }
657
934
  `
658
935
 
659
936
  const CSS = `
package/dsh/workbench.mjs CHANGED
@@ -242,6 +242,10 @@ export function registerWorkbench(ctx) {
242
242
  'refine-logs/EXPERIMENT_PLAN.md',
243
243
  'research-wiki/index.md',
244
244
  'research-wiki/query_pack.md',
245
+ 'EXPERIMENT_LOG.md',
246
+ 'NARRATIVE_REPORT.md',
247
+ 'paper/main.tex',
248
+ 'paper/main.pdf',
245
249
  ]) {
246
250
  artifacts[rel] = await statFile(workspace, rel)
247
251
  }
@@ -262,10 +266,29 @@ export function registerWorkbench(ctx) {
262
266
  if (typeof skill !== 'string' || skill === '') {
263
267
  return { ok: false, error: { code: 'bad-request', message: 'skill is required', details: {} } }
264
268
  }
265
- const argText = typeof args === 'string' && args.trim() !== '' ? ' 参数/方向:' + args.trim() : ''
269
+ const argText = typeof args === 'string' ? args.trim() : ''
266
270
  const autoProceed = typeof payload === 'object' && payload !== null ? payload.autoProceed : undefined
267
- const autoText = autoProceed === false ? ' 请将 AUTO_PROCEED 设为 false,在每个选择点停下来等我确认。' : (autoProceed === true ? ' 请将 AUTO_PROCEED 设为 true,自动继续、无人值守。' : '')
268
- const prompt = '请使用 ARIS 技能 ' + TICK + skill + TICK + ' 完成对应工作流。' + argText + autoText
271
+ const effort = typeof payload === 'object' && payload !== null ? payload.effort : undefined
272
+ const assurance = typeof payload === 'object' && payload !== null ? payload.assurance : undefined
273
+ const difficulty = typeof payload === 'object' && payload !== null ? payload.difficulty : undefined
274
+ const extra = typeof payload === 'object' && payload !== null ? payload.extra : undefined
275
+ const venue = typeof payload === 'object' && payload !== null ? payload.venue : undefined
276
+ const gpu = typeof payload === 'object' && payload !== null ? payload.gpu : undefined
277
+ const reviewer = typeof payload === 'object' && payload !== null ? payload.reviewer : undefined
278
+ const humanCheckpoint = typeof payload === 'object' && payload !== null ? payload.humanCheckpoint : undefined
279
+ const extraText = typeof extra === 'string' ? extra.trim() : ''
280
+ const params = []
281
+ if (autoProceed === false) params.push('AUTO_PROCEED: false')
282
+ if (humanCheckpoint === true) params.push('human checkpoint: true')
283
+ if (effort && effort !== 'balanced') params.push('effort: ' + effort)
284
+ if (assurance && assurance !== 'draft') params.push('assurance: ' + assurance)
285
+ if (difficulty && difficulty !== 'medium') params.push('difficulty: ' + difficulty)
286
+ if (venue) params.push('venue: ' + venue)
287
+ if (gpu) params.push('gpu: ' + gpu)
288
+ if (reviewer && reviewer !== 'auto') params.push('reviewer: ' + reviewer)
289
+ if (extraText) params.push(extraText)
290
+ const cmd = '/' + skill + (argText ? ' "' + argText + '"' : '') + (params.length > 0 ? ' — ' + params.join(', ') : '')
291
+ const prompt = '请执行以下 ARIS 命令:\n' + cmd
269
292
  const messageId = 'aris-launch-' + Date.now() + '-' + Math.random().toString(36).slice(2, 8)
270
293
  const message = {
271
294
  id: messageId,
@@ -297,6 +320,18 @@ export function registerWorkbench(ctx) {
297
320
  }
298
321
  return { ok: true, value: { injected, method, prompt, sessionId, messageId } }
299
322
  }
323
+
324
+ case 'audits': {
325
+ const auditFiles = ['EXPERIMENT_AUDIT.md', 'EXPERIMENT_AUDIT.json', 'PAPER_CLAIM_AUDIT.md', 'PAPER_CLAIM_AUDIT.json', 'CITATION_AUDIT.md', 'CITATION_AUDIT.json', 'KILL_ARGUMENT.md', 'KILL_ARGUMENT.json']
326
+ const out = {}
327
+ for (const rel of auditFiles) {
328
+ const text = await readText(workspace, rel)
329
+ if (text === undefined) continue
330
+ const verdictMatch = /(PASS|WARN|FAIL|BLOCKED|ERROR|NOT_APPLICABLE)/.exec(text)
331
+ out[rel] = { exists: true, verdict: verdictMatch ? verdictMatch[1] : undefined, head: text.split(String.fromCharCode(10)).slice(0, 6) }
332
+ }
333
+ return { ok: true, value: out }
334
+ }
300
335
  default:
301
336
  return { ok: false, error: { code: 'internal', message: 'unknown ARIS workbench endpoint \"' + endpoint + '\"' } }
302
337
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-aris-panel",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "ARIS research-workflow skills + interactive workbench panel for DeepSeek Harness (user fork of dsh-aris: 82 skills, cross-model Codex review, idea/workflow launcher, research status board).",
5
5
  "license": "MIT",
6
6
  "type": "module",