psyclaw 0.27.15 → 0.27.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +7 -7
  2. package/dist/apps/panel/index.html +8 -7
  3. package/dist/src/adapters/pi/extension.js +429 -175
  4. package/dist/src/adapters/pi/extension.js.map +1 -1
  5. package/dist/src/adapters/pi/search-tools.d.ts +21 -0
  6. package/dist/src/adapters/pi/search-tools.js +248 -0
  7. package/dist/src/adapters/pi/search-tools.js.map +1 -0
  8. package/dist/src/analysis/hooks.js +3 -3
  9. package/dist/src/analysis/hooks.js.map +1 -1
  10. package/dist/src/analysis/pre-registration.d.ts +5 -4
  11. package/dist/src/analysis/pre-registration.js +3 -3
  12. package/dist/src/analysis/pre-registration.js.map +1 -1
  13. package/dist/src/branding.d.ts +1 -1
  14. package/dist/src/branding.js +17 -12
  15. package/dist/src/branding.js.map +1 -1
  16. package/dist/src/chat.js +9 -0
  17. package/dist/src/chat.js.map +1 -1
  18. package/dist/src/cli-args.d.ts +2 -0
  19. package/dist/src/cli-args.js +7 -0
  20. package/dist/src/cli-args.js.map +1 -0
  21. package/dist/src/cli.js +7 -18
  22. package/dist/src/cli.js.map +1 -1
  23. package/dist/src/index.d.ts +1 -0
  24. package/dist/src/index.js +1 -0
  25. package/dist/src/index.js.map +1 -1
  26. package/dist/src/orchestration/contracts.d.ts +4 -1
  27. package/dist/src/panel/events.js +28 -1
  28. package/dist/src/panel/events.js.map +1 -1
  29. package/dist/src/panel/extension.d.ts +1 -1
  30. package/dist/src/panel/extension.js +16 -9
  31. package/dist/src/panel/extension.js.map +1 -1
  32. package/dist/src/panel/projection.d.ts +1 -1
  33. package/dist/src/panel/projection.js +30 -12
  34. package/dist/src/panel/projection.js.map +1 -1
  35. package/dist/src/panel/server.d.ts +11 -1
  36. package/dist/src/panel/server.js +86 -4
  37. package/dist/src/panel/server.js.map +1 -1
  38. package/dist/src/project/approvals.d.ts +8 -0
  39. package/dist/src/project/approvals.js +6 -7
  40. package/dist/src/project/approvals.js.map +1 -1
  41. package/dist/src/project/bootstrap.d.ts +0 -17
  42. package/dist/src/project/bootstrap.js +1 -87
  43. package/dist/src/project/bootstrap.js.map +1 -1
  44. package/dist/src/project/hitl.d.ts +4 -1
  45. package/dist/src/project/hitl.js +8 -5
  46. package/dist/src/project/hitl.js.map +1 -1
  47. package/dist/src/research/brief.js +1 -1
  48. package/dist/src/research/brief.js.map +1 -1
  49. package/dist/src/research/decision.d.ts +46 -0
  50. package/dist/src/research/decision.js +85 -0
  51. package/dist/src/research/decision.js.map +1 -0
  52. package/dist/src/style/cli-ui.js +4 -4
  53. package/dist/src/style/cli-ui.js.map +1 -1
  54. package/dist/src/tui/skill-manager.d.ts +1 -0
  55. package/dist/src/tui/skill-manager.js +6 -1
  56. package/dist/src/tui/skill-manager.js.map +1 -1
  57. package/dist/src/wizard.js +16 -7
  58. package/dist/src/wizard.js.map +1 -1
  59. package/dist/src/workflows/expert-review-runner.js +4 -6
  60. package/dist/src/workflows/expert-review-runner.js.map +1 -1
  61. package/dist/src/workflows/institutional-fulltext.js +3 -3
  62. package/dist/src/workflows/institutional-fulltext.js.map +1 -1
  63. package/dist/src/workflows/publish.js +3 -2
  64. package/dist/src/workflows/publish.js.map +1 -1
  65. package/dist/src/workflows/spec.js +1 -1
  66. package/dist/src/workflows/spec.js.map +1 -1
  67. package/dist/src/workflows/writing-review.js +40 -7
  68. package/dist/src/workflows/writing-review.js.map +1 -1
  69. package/package.json +3 -2
  70. package/scripts/psyclaw.mjs +27 -0
  71. package/scripts/rebrand-pi.mjs +88 -17
  72. package/skills/core/academic-grill/SKILL.md +9 -1
  73. package/skills/core/citation-audit/SKILL.md +2 -0
  74. package/skills/core/research-brief/SKILL.md +6 -0
  75. package/skills/core/research-intake/SKILL.md +1 -1
  76. package/skills/recommended/catalog.json +11 -28
  77. package/skills/recommended/mcp-catalog.json +13 -1
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # PsyClaw
2
2
 
3
- PsyClaw 是面向社会科学研究的智能体工作台。它把研究项目、证据来源、Claim-Evidence 账本、完整性门禁、人工裁决、可恢复工作流和本地面板接到内置运行时上;它不替代统计软件,也不会把未经核验的引用、结果或审稿意见写成事实。
3
+ PsyClaw 是面向社会科学研究的智能体工作台。它把研究项目、证据来源、Claim-Evidence 账本、完整性门禁、可恢复工作流和本地面板接到内置运行时上;只有无法由证据和通行方法消解、且会实质改变研究设计或解释的分歧才交由研究者取舍。它不替代统计软件,也不会把未经核验的引用、结果或审稿意见写成事实。
4
4
 
5
- 当前版本:`0.27.15`。正式命令、用户配置目录和后续发布统一使用 `psyclaw`。
5
+ 当前版本:`0.27.19`。正式命令、用户配置目录和后续发布统一使用 `psyclaw`。
6
6
 
7
7
  ## 发布流程
8
8
 
@@ -19,19 +19,19 @@ RELEASE_MESSAGE="release: describe the change" pnpm release:push
19
19
  需要 Node.js `>=22.19.0`。官方 npm 源:
20
20
 
21
21
  ```powershell
22
- npm install -g psyclaw@0.27.15
22
+ npm install -g psyclaw@0.27.19
23
23
  ```
24
24
 
25
25
  如果本机 npm 配置把 registry 误写成带有 `~/` 的地址,请显式指定官方源:
26
26
 
27
27
  ```bash
28
- npm install -g psyclaw@0.27.15 --registry=https://registry.npmjs.org/
28
+ npm install -g psyclaw@0.27.19 --registry=https://registry.npmjs.org/
29
29
  ```
30
30
 
31
31
  中国大陆网络较慢或无法访问官方源时:
32
32
 
33
33
  ```powershell
34
- npm install -g psyclaw@0.27.15 --registry=https://registry.npmmirror.com
34
+ npm install -g psyclaw@0.27.19 --registry=https://registry.npmmirror.com
35
35
  ```
36
36
 
37
37
  确认命令入口:
@@ -40,7 +40,7 @@ npm install -g psyclaw@0.27.15 --registry=https://registry.npmmirror.com
40
40
  psyclaw --help
41
41
  ```
42
42
 
43
- 直接运行 `psyclaw` 会启动交互研究工作台;首次没有模型配置时会进入配置向导。向导会检查当前进程、macOS `launchctl` 和已有用户凭据,也允许直接遮罩输入 Key。`launchctl` Key 只注入当前运行进程、不落盘;登录 shell 仅在用户明确按 `Ctrl+I` 后读取。直接输入或明确导入的 Key 只保存到 PsyClaw 用户级 `auth.json`,不会写入项目或 `models.json`。也可显式运行 `psyclaw wizard`,或使用 `psyclaw setup --provider deepseek` 写入仅引用环境变量的预设。不要把 API key 写进命令参数、项目、README 或 Git 仓库。
43
+ 直接运行 `psyclaw` 会启动交互研究工作台;首次没有模型配置时会自动进入配置流程。配置界面会检查当前进程、macOS `launchctl` 和已有用户凭据,也允许直接遮罩输入 Key。`launchctl` Key 只注入当前运行进程、不落盘;登录 shell 仅在用户明确按 `Ctrl+I` 后读取。直接输入或明确导入的 Key 只保存到 PsyClaw 用户级 `auth.json`,不会写入项目或 `models.json`。模型、凭据、会话和宿主资源统一保存在 `~/.psyclaw/agent`,PsyClaw 不创建或使用 `~/.pi`。不要把 API key 写进命令参数、项目、README 或 Git 仓库。
44
44
 
45
45
  ## 五分钟开始
46
46
 
@@ -69,12 +69,12 @@ psyclaw brief
69
69
  | 需求 | 命令或操作 |
70
70
  | --- | --- |
71
71
  | 启动研究对话 | `psyclaw` 或 `psyclaw chat` |
72
+ | 续接当前项目最近一次会话 | `psyclaw --continue` 或 `psyclaw -c` |
72
73
  | 创建研究项目 | `psyclaw init <goal> --paradigm <profile>` |
73
74
  | 启动受控研究流程 | 对话中依次输入 `/init <goal>`、`/run [--skills a,b] [objective]` |
74
75
  | 模拟同行评审 | 论文完成后在对话中输入 `/review` |
75
76
  | 登记本地证据 | `psyclaw evidence add <path> --level user\|fulltext` |
76
77
  | 生成离线简报 | `psyclaw brief` |
77
- | 创建人工裁决模板 | `psyclaw hitl init` |
78
78
  | 写研究移交记录 | `psyclaw handoff` |
79
79
  | 扫描本机其他 Agent | `psyclaw agents` |
80
80
  | 查看 PsyClaw 和内置运行时更新 | `psyclaw check-updates` |
@@ -17,7 +17,7 @@
17
17
  <div class="layout">
18
18
  <nav class="nav" aria-label="Panel 导航">
19
19
  <button class="active" data-view="project">项目文件</button>
20
- <button data-view="ecosystem">Skill / MCP</button>
20
+ <button data-view="ecosystem">Skill / Plugin / MCP</button>
21
21
  <button data-view="provider">Provider 与成本</button>
22
22
  </nav>
23
23
  <main class="main">
@@ -33,8 +33,8 @@
33
33
  </section>
34
34
 
35
35
  <section id="view-ecosystem" class="view">
36
- <div class="page-head"><div><h1>Skill / MCP 生态</h1><p>安装、启用和停用研究能力。配置变更后使用 <code>/reload</code>。</p></div><button id="refresh-ecosystem" class="button">刷新</button></div>
37
- <div class="controls" style="margin-bottom:12px"><input id="eco-search" placeholder="搜索名称或描述"><select id="eco-kind"><option value="all">全部类型</option><option value="skill">Skill</option><option value="plugin">Plugin</option><option value="local">用户 Skill</option><option value="mcp">MCP</option><option value="external">外部工具</option></select><select id="eco-status"><option value="all">全部状态</option><option value="enabled">已启用</option><option value="available">未启用</option></select></div>
36
+ <div class="page-head"><div><h1>Skill / Plugin / MCP 生态</h1><p>在同一页面管理研究 Skill、Pi Plugin 与 MCP。配置变更后使用 <code>/reload</code>。</p></div><button id="refresh-ecosystem" class="button">刷新</button></div>
37
+ <div class="controls" style="margin-bottom:12px"><input id="eco-search" placeholder="搜索名称或描述"><div class="segmented" aria-label="能力类型"><button class="active" data-eco-kind="all">全部</button><button data-eco-kind="skill">Skill</button><button data-eco-kind="plugin">Plugin</button><button data-eco-kind="mcp">MCP</button></div><select id="eco-kind" aria-label="更多类型"><option value="all">全部来源</option><option value="local">用户 Skill</option><option value="external">外部工具</option></select><select id="eco-status"><option value="all">全部状态</option><option value="enabled">已启用</option><option value="available">未启用</option></select></div>
38
38
  <div class="table-wrap"><table class="data"><thead><tr><th>名称</th><th>类型</th><th>来源</th><th>状态</th><th>操作</th></tr></thead><tbody id="ecosystem-body"><tr><td colspan="5">读取中...</td></tr></tbody></table></div>
39
39
  </section>
40
40
 
@@ -50,7 +50,7 @@
50
50
  </div>
51
51
  </div>
52
52
  <script>
53
- const state={view:"project",files:[],eco:[],models:[],active:{},usage:null,currency:"cny"};
53
+ const state={view:"project",files:[],eco:[],ecoKind:"all",models:[],active:{},usage:null,currency:"cny"};
54
54
  const $=id=>document.getElementById(id);
55
55
  const esc=value=>String(value??"").replace(/[&<>"']/g,ch=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"}[ch]));
56
56
  async function json(url,options){const response=await fetch(url,options);const body=await response.json().catch(()=>({error:"请求失败"}));if(!response.ok)throw new Error(body.error||"请求失败");return body}
@@ -65,11 +65,12 @@ function selectTree(button){document.querySelectorAll(".tree-item").forEach(item
65
65
  async function openFile(path,button){selectTree(button);$("viewer-path").textContent=path;$("viewer-kind").textContent="读取中";$("viewer-body").className="viewer-body empty";$("viewer-body").textContent="读取中...";try{const file=await json(`/api/project-file?path=${encodeURIComponent(path)}`);$("viewer-kind").textContent=file.format;$("viewer-body").className="viewer-body";$("viewer-body").innerHTML=file.format==="markdown"?`<article class="markdown">${renderMarkdown(file.content)}</article>`:`<pre class="raw">${esc(file.format==="json"?JSON.stringify(JSON.parse(file.content),null,2):file.content)}</pre>`}catch(error){$("viewer-body").className="viewer-body empty";$("viewer-body").textContent=error.message}}
66
66
  async function loadProject(){const files=await json("/api/project-files");state.files=files.files||[];renderTree();const goal=document.querySelector('[data-file="notes/goal.md"]')||document.querySelector("[data-file]");if(goal)goal.click()}
67
67
 
68
- async function loadEcosystem(){try{const[skills,mcps,enabled]=await Promise.all([json("/api/recommended-skills"),json("/api/recommended-mcps"),json("/api/enabled-capabilities")]);const skillSet=new Set((enabled.skills||[]).map(item=>item.id)),mcpSet=new Set((enabled.mcp||[]).map(item=>item.id));state.eco=[...(enabled.coreSkills||[]).map(item=>({...item,kind:"core",description:"PsyClaw 内置 Skill",sourceRef:"bundled",enabled:item.enabled,installed:true})),...(skills.items||[]).map(item=>({...item,kind:"skill",enabled:skillSet.has(item.id),installed:skillSet.has(item.id)})),...(skills.plugins||[]).map(item=>({...item,kind:"plugin",enabled:false,installed:false})),...(enabled.localSkills||[]).map(item=>({...item,kind:"local",sourceRef:item.path||"用户目录",installed:true})),...(mcps.items||[]).map(item=>({...item,kind:"mcp",enabled:mcpSet.has(item.id),installed:mcpSet.has(item.id)})),...(skills.externalTools||[]).map(item=>({...item,kind:"external",enabled:false,installed:false}))];renderEcosystem()}catch(error){$("ecosystem-body").innerHTML=`<tr><td colspan="5">${esc(error.message)}</td></tr>`}}
69
- function renderEcosystem(){const query=$("eco-search").value.trim().toLowerCase(),kind=$("eco-kind").value,status=$("eco-status").value;const items=state.eco.filter(item=>(kind==="all"||item.kind===kind)&&(status==="all"||(status==="enabled"?item.enabled:!item.enabled))&&`${item.name} ${item.description||""}`.toLowerCase().includes(query));$("ecosystem-body").innerHTML=items.map(item=>`<tr><td><div class="name">${esc(item.name)}</div><div class="subtle">${esc(item.description||"")}</div></td><td>${esc(item.kind==="core"?"Core Skill":item.kind==="local"?"用户 Skill":item.kind.toUpperCase())}</td><td>${/^https?:/.test(item.sourceRef||"")?`<a href="${esc(item.sourceRef)}" target="_blank" rel="noreferrer">来源</a>`:esc(item.sourceRef||"bundled")}</td><td><span class="tag ${item.enabled?"ok":""}">${item.enabled?"已启用":item.kind==="external"?"外部工具":"未启用"}</span></td><td>${item.kind==="external"?"—":item.enabled?`<button class="button small" onclick="toggleCapability('${item.kind}','${esc(item.id)}',false)">停用</button>`:item.kind==="local"?`<button class="button small primary" onclick="toggleCapability('local','${esc(item.id)}',true)">启用</button>`:item.kind==="plugin"?`<button class="button small primary" onclick="installCapability('plugin','${esc(item.id)}')">安装</button>`:`<button class="button small primary" onclick="installCapability('${item.kind}','${esc(item.id)}')">${item.kind==="core"?"启用":"安装"}</button>`}</td></tr>`).join("")||'<tr><td colspan="5">没有匹配项</td></tr>'}
68
+ async function loadEcosystem(){try{const[skills,plugins,mcps,enabled]=await Promise.all([json("/api/recommended-skills"),json("/api/recommended-plugins"),json("/api/recommended-mcps"),json("/api/enabled-capabilities")]);const skillSet=new Set((enabled.skills||[]).map(item=>item.id)),mcpSet=new Set((enabled.mcp||[]).map(item=>item.id));state.eco=[...(enabled.coreSkills||[]).map(item=>({...item,kind:"core",description:"PsyClaw 内置 Skill",sourceRef:"bundled",enabled:item.enabled,installed:true})),...(skills.items||[]).map(item=>({...item,kind:"skill",enabled:skillSet.has(item.id),installed:skillSet.has(item.id)})),...(plugins.items||[]).map(item=>({...item,kind:"plugin",enabled:Boolean(item.enabled),installed:Boolean(item.installed)})),...(enabled.localSkills||[]).map(item=>({...item,kind:"local",sourceRef:item.path||"用户目录",installed:true})),...(mcps.items||[]).map(item=>({...item,kind:"mcp",enabled:mcpSet.has(item.id),installed:mcpSet.has(item.id)})),...(skills.externalTools||[]).map(item=>({...item,kind:"external",enabled:false,installed:false}))];renderEcosystem()}catch(error){$("ecosystem-body").innerHTML=`<tr><td colspan="5">${esc(error.message)}</td></tr>`}}
69
+ function renderEcosystem(){const query=$("eco-search").value.trim().toLowerCase(),sourceKind=$("eco-kind").value,status=$("eco-status").value,primaryKind=state.ecoKind;const primaryMatches=item=>primaryKind==="all"||(primaryKind==="skill"?(item.kind==="skill"||item.kind==="core"||item.kind==="local"):item.kind===primaryKind);const items=state.eco.filter(item=>primaryMatches(item)&&(sourceKind==="all"||item.kind===sourceKind)&&(status==="all"||(status==="enabled"?item.enabled:!item.enabled))&&`${item.name} ${item.description||""}`.toLowerCase().includes(query));$("ecosystem-body").innerHTML=items.map(item=>`<tr><td><div class="name">${esc(item.name)}</div><div class="subtle">${esc(item.description||"")}${item.kind==="plugin"&&item.scope?` · ${item.scope==="project"?"当前项目":"所有项目"}${item.filtered?" · 已限定资源范围":""}`:""}</div></td><td>${esc(item.kind==="core"?"Core Skill":item.kind==="local"?"用户 Skill":item.kind.toUpperCase())}</td><td>${/^https?:/.test(item.sourceRef||"")?`<a href="${esc(item.sourceRef)}" target="_blank" rel="noreferrer">来源</a>`:esc(item.sourceRef||"bundled")}</td><td><span class="tag ${item.enabled?"ok":item.configured?"warn":""}">${item.enabled?(item.kind==="plugin"?"已安装":"已启用"):item.kind==="plugin"&&item.configured?"配置存在,文件缺失":item.kind==="external"?"可安装外部工具":"未启用"}</span></td><td>${item.kind==="plugin"&&item.local?"—":item.kind==="plugin"?`<button class="button small ${item.installed?"":"primary"}" onclick="installCapability('plugin','${esc(item.id)}')">${item.installed?"重新安装":"安装"}</button>`:item.kind==="external"?`<button class="button small primary" onclick="installCapability('external','${esc(item.id)}')">安装</button>`:item.enabled?`<button class="button small" onclick="toggleCapability('${item.kind}','${esc(item.id)}',false)">停用</button>`:item.kind==="local"?`<button class="button small primary" onclick="toggleCapability('local','${esc(item.id)}',true)">启用</button>`:`<button class="button small primary" onclick="installCapability('${item.kind}','${esc(item.id)}')">${item.kind==="core"?"启用":"安装"}</button>`}</td></tr>`).join("")||'<tr><td colspan="5">没有匹配项</td></tr>'}
70
70
  async function toggleCapability(kind,id,enabled){await json("/api/recommendation-state",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({kind:kind==="core"?"core-skill":kind==="skill"?"skills":kind==="local"?"local-skill":kind,id,enabled})});await loadEcosystem()}
71
- async function installCapability(kind,id){if(kind==="core"){await toggleCapability(kind,id,true);return}const scope=kind==="skill"?(confirm("安装到系统目录?\n确定:所有项目使用;取消:仅当前项目使用。")?"user":"project"):undefined;if(!confirm(`确认安装 ${id}?安装完成后需要 /reload。`))return;const result=await json("/api/install/execute",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({kind,id,scope,approved:true,actor:"researcher"})});alert(result.message||(result.ok?"安装任务已处理,请执行 /reload。":"安装未完成"));await loadEcosystem()}
71
+ async function installCapability(kind,id){if(kind==="core"){await toggleCapability(kind,id,true);return}const scope=kind==="skill"||kind==="plugin"?(confirm("安装到系统目录?\n确定:所有项目使用;取消:仅当前项目使用。")?"user":"project"):undefined;if(!confirm(`确认安装 ${id}?${kind==="external"?"模型将按官方来源安装并验证。":"安装完成后需要 /reload。"}`))return;const result=await json("/api/install/execute",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({kind,id,scope,approved:true,actor:"researcher"})});alert(result.message||(result.ok?"安装任务已处理。":"安装未完成"));await loadEcosystem()}
72
72
  [$("eco-search"),$("eco-kind"),$("eco-status")].forEach(control=>control.addEventListener("input",renderEcosystem));
73
+ document.querySelectorAll("[data-eco-kind]").forEach(button=>button.addEventListener("click",()=>{state.ecoKind=button.dataset.ecoKind;document.querySelectorAll("[data-eco-kind]").forEach(item=>item.classList.toggle("active",item===button));renderEcosystem()}));
73
74
 
74
75
  function providerModels(provider){return state.models.filter(model=>model.provider===provider)}
75
76
  function updateModels(){const models=providerModels($("provider-select").value);$("model-select").innerHTML=models.map(model=>`<option value="${esc(model.version||model.id.split("/").slice(1).join("/"))}">${esc(model.name)}</option>`).join("");if(state.active.provider===$("provider-select").value&&state.active.model)$("model-select").value=state.active.model}