psyclaw 0.29.4 → 0.29.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.
Files changed (35) hide show
  1. package/README.md +20 -5
  2. package/dist/apps/panel/index.html +138 -0
  3. package/dist/src/adapters/pi/extension.js +27 -4
  4. package/dist/src/adapters/pi/extension.js.map +1 -1
  5. package/dist/src/branding.js +1 -1
  6. package/dist/src/branding.js.map +1 -1
  7. package/dist/src/cli.js +12 -2
  8. package/dist/src/cli.js.map +1 -1
  9. package/dist/src/network-routing.d.ts +10 -0
  10. package/dist/src/network-routing.js +46 -4
  11. package/dist/src/network-routing.js.map +1 -1
  12. package/dist/src/panel/extension.d.ts +2 -5
  13. package/dist/src/panel/extension.js +15 -91
  14. package/dist/src/panel/extension.js.map +1 -1
  15. package/dist/src/panel/server.js +6 -0
  16. package/dist/src/panel/server.js.map +1 -1
  17. package/dist/src/panel/workbench.d.ts +16 -0
  18. package/dist/src/panel/workbench.js +78 -0
  19. package/dist/src/panel/workbench.js.map +1 -0
  20. package/dist/src/session/help.d.ts +21 -2
  21. package/dist/src/session/help.js +50 -32
  22. package/dist/src/session/help.js.map +1 -1
  23. package/dist/src/skills/recommended.js +3 -1
  24. package/dist/src/skills/recommended.js.map +1 -1
  25. package/dist/src/style/cli-ui.js +2 -2
  26. package/dist/src/style/cli-ui.js.map +1 -1
  27. package/dist/src/updates/registry.d.ts +12 -1
  28. package/dist/src/updates/registry.js +12 -4
  29. package/dist/src/updates/registry.js.map +1 -1
  30. package/dist/src/updates/update.d.ts +2 -0
  31. package/dist/src/updates/update.js +11 -8
  32. package/dist/src/updates/update.js.map +1 -1
  33. package/package.json +1 -1
  34. package/skills/scholars/README.md +6 -6
  35. package/vendor/nuwa-skill/SKILL.md +44 -17
package/README.md CHANGED
@@ -4,7 +4,7 @@ PsyClaw 是面向社会科学研究的智能体工作台。它把研究项目、
4
4
 
5
5
  PsyClaw 自有代码使用 MIT 许可证;随 npm 包内置的 Academic Research Skills 位于 `vendor/ars`,保持上游署名并单独遵循 CC BY-NC 4.0,仅限非商业用途。
6
6
 
7
- 当前版本:`0.29.4`。正式命令、用户配置目录和后续发布统一使用 `psyclaw`。
7
+ 当前版本:`0.29.5`。正式命令、用户配置目录和后续发布统一使用 `psyclaw`。
8
8
 
9
9
  ## 发布流程
10
10
 
@@ -21,22 +21,37 @@ RELEASE_MESSAGE="release: describe the change" pnpm release:push
21
21
  需要 Node.js `>=22.19.0`。官方 npm 源:
22
22
 
23
23
  ```powershell
24
- npm install -g psyclaw@0.29.4
24
+ npm install -g psyclaw@0.29.5
25
25
  ```
26
26
 
27
27
  如果本机 npm 配置把 registry 误写成带有 `~/` 的地址,请显式指定官方源:
28
28
 
29
29
  ```bash
30
- npm install -g psyclaw@0.29.4 --registry=https://registry.npmjs.org/
30
+ npm install -g psyclaw@0.29.5 --registry=https://registry.npmjs.org/
31
31
  ```
32
32
 
33
33
  中国大陆网络较慢或无法访问官方源时:
34
34
 
35
35
  ```powershell
36
- npm install -g psyclaw@0.29.4 --registry=https://registry.npmmirror.com
36
+ npm install -g psyclaw@0.29.5 --registry=https://registry.npmmirror.com
37
37
  ```
38
38
 
39
- PsyClaw 的 npm 发布包直接携带 Windows x64/arm64 版 `ripgrep` 和 `fd`,Windows 启动时直接使用包内可执行文件,不再联网下载。其他平台缺少这两个工具时仍由锁定的 Pi 原生工具管理器处理:代理环境走 GitHub 官方 API 与 Release,国内 npm registry 环境统一走国内镜像。
39
+ 或安装脚本:
40
+
41
+ ```bash
42
+ PSYCLAW_CN=1 curl -fsSL https://exekiel179.github.io/psyclaw/install.sh | sh
43
+ ```
44
+
45
+ 检测到国内 npm registry(如 npmmirror)、`PSYCLAW_CN=1` 或 `PSYCLAW_GITHUB_MIRROR` 时,内置路径统一走国内可用路由:
46
+
47
+ - 首启 `fd` / `ripgrep`(macOS/Linux):GitHub API 与 Release 经 `gh-proxy` 等镜像;Windows 仍用包内二进制,无需下载
48
+ - `psyclaw update` / `check-updates`:读版本与安装命令使用 `PSYCLAW_REGISTRY` 或 npmmirror,不再写死官方 npm
49
+ - 推荐 Skill 的托管 `git clone`:经 GitHub 镜像前缀
50
+ - `fetch` 覆盖 `api.github.com`、`github.com`、`raw.githubusercontent.com`、`codeload.github.com`
51
+
52
+ 建议把 `registry=https://registry.npmmirror.com` 写入 `~/.npmrc`,以免下次启动检测不到国内源。已有 HTTP(S) 代理时优先走代理、保持官方 GitHub URL。
53
+
54
+ PsyClaw 的 npm 发布包直接携带 Windows x64/arm64 版 `ripgrep` 和 `fd`,Windows 启动时直接使用包内可执行文件,不再联网下载。
40
55
 
41
56
  确认命令入口:
42
57
 
@@ -266,6 +266,85 @@
266
266
  font-size: 12.5px;
267
267
  }
268
268
 
269
+ .help-grid {
270
+ display: grid;
271
+ grid-template-columns: repeat(3, minmax(0, 1fr));
272
+ gap: 12px;
273
+ margin-bottom: 22px;
274
+ }
275
+ .help-mode-card {
276
+ border: 1px solid var(--border-subtle);
277
+ background: var(--bg-surface);
278
+ border-radius: var(--radius-md);
279
+ padding: 14px 16px;
280
+ box-shadow: var(--shadow-xs);
281
+ }
282
+ .help-mode-card .mode-id {
283
+ font-family: var(--font-mono);
284
+ font-size: 11px;
285
+ color: var(--accent);
286
+ letter-spacing: 0.04em;
287
+ text-transform: uppercase;
288
+ margin-bottom: 6px;
289
+ }
290
+ .help-mode-card p {
291
+ margin: 0;
292
+ font-size: 13px;
293
+ line-height: 1.55;
294
+ color: var(--text-secondary);
295
+ }
296
+ .help-block {
297
+ margin-bottom: 22px;
298
+ }
299
+ .help-block h2 {
300
+ margin: 0 0 10px;
301
+ font-size: 14px;
302
+ font-weight: 650;
303
+ color: var(--text-main);
304
+ }
305
+ .help-steps {
306
+ margin: 0;
307
+ padding-left: 1.2rem;
308
+ color: var(--text-secondary);
309
+ font-size: 13px;
310
+ line-height: 1.7;
311
+ }
312
+ .help-commands {
313
+ display: grid;
314
+ grid-template-columns: repeat(2, minmax(0, 1fr));
315
+ gap: 8px;
316
+ }
317
+ .help-cmd {
318
+ display: flex;
319
+ gap: 10px;
320
+ align-items: baseline;
321
+ border: 1px solid var(--border-subtle);
322
+ border-radius: var(--radius-sm);
323
+ padding: 10px 12px;
324
+ background: var(--bg-surface-subtle);
325
+ }
326
+ .help-cmd code {
327
+ font-family: var(--font-mono);
328
+ font-size: 12px;
329
+ color: var(--text-main);
330
+ white-space: nowrap;
331
+ }
332
+ .help-cmd span {
333
+ font-size: 12.5px;
334
+ color: var(--text-muted);
335
+ line-height: 1.45;
336
+ }
337
+ .help-notes {
338
+ margin: 0;
339
+ padding-left: 1.2rem;
340
+ color: var(--text-muted);
341
+ font-size: 12.5px;
342
+ line-height: 1.65;
343
+ }
344
+ @media (max-width: 960px) {
345
+ .help-grid, .help-commands { grid-template-columns: 1fr; }
346
+ }
347
+
269
348
  .button {
270
349
  display: inline-flex;
271
350
  align-items: center;
@@ -1174,6 +1253,10 @@
1174
1253
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
1175
1254
  模型与成本
1176
1255
  </button>
1256
+ <button data-view="help">
1257
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
1258
+ 使用速览
1259
+ </button>
1177
1260
  <button data-view="checklist">
1178
1261
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>
1179
1262
  核对清单
@@ -1382,6 +1465,28 @@
1382
1465
  </div>
1383
1466
  </section>
1384
1467
 
1468
+ <section id="view-help" class="view">
1469
+ <div class="page-head">
1470
+ <div>
1471
+ <h1 id="help-title">使用速览</h1>
1472
+ <p id="help-thinking">加载中…</p>
1473
+ </div>
1474
+ </div>
1475
+ <div class="help-grid" id="help-modes"></div>
1476
+ <div class="help-block">
1477
+ <h2>建议流程</h2>
1478
+ <ol id="help-steps" class="help-steps"></ol>
1479
+ </div>
1480
+ <div class="help-block">
1481
+ <h2>常用命令</h2>
1482
+ <div id="help-commands" class="help-commands"></div>
1483
+ </div>
1484
+ <div class="help-block">
1485
+ <h2>说明</h2>
1486
+ <ul id="help-notes" class="help-notes"></ul>
1487
+ </div>
1488
+ </section>
1489
+
1385
1490
  <section id="view-checklist" class="view">
1386
1491
  <div class="page-head">
1387
1492
  <div>
@@ -1533,6 +1638,9 @@ async function json(url, options) {
1533
1638
 
1534
1639
  function setView(view) {
1535
1640
  state.view = view;
1641
+ if (location.hash.replace(/^#/, "") !== view) {
1642
+ history.replaceState(null, "", `#${view}`);
1643
+ }
1536
1644
  document.querySelectorAll(".nav button").forEach(button => {
1537
1645
  button.classList.toggle("active", button.dataset.view === view);
1538
1646
  });
@@ -1542,10 +1650,32 @@ function setView(view) {
1542
1650
  if (view === "ecosystem") loadEcosystem();
1543
1651
  if (view === "provider") loadProvider();
1544
1652
  if (view === "checklist") loadChecklist();
1653
+ if (view === "help") loadHelp();
1545
1654
  if (view === "chat") mountConsoleInChat();
1546
1655
  else restoreConsoleDrawer();
1547
1656
  }
1548
1657
 
1658
+ async function loadHelp() {
1659
+ try {
1660
+ const doc = await json("/api/help");
1661
+ $("help-title").textContent = doc.title || "使用速览";
1662
+ $("help-thinking").textContent = doc.thinking || "";
1663
+ $("help-modes").innerHTML = (doc.modes || []).map(mode => `
1664
+ <article class="help-mode-card">
1665
+ <div class="mode-id">${esc(mode.label || mode.id)}</div>
1666
+ <p>${esc(mode.blurb)}</p>
1667
+ </article>
1668
+ `).join("");
1669
+ $("help-steps").innerHTML = (doc.steps || []).map(step => `<li>${esc(step)}</li>`).join("");
1670
+ $("help-commands").innerHTML = (doc.commands || []).map(row => `
1671
+ <div class="help-cmd"><code>${esc(row.cmd)}</code><span>${esc(row.blurb)}</span></div>
1672
+ `).join("");
1673
+ $("help-notes").innerHTML = (doc.notes || []).map(note => `<li>${esc(note)}</li>`).join("");
1674
+ } catch (error) {
1675
+ $("help-thinking").textContent = `加载失败: ${error.message}`;
1676
+ }
1677
+ }
1678
+
1549
1679
  function mountConsoleInChat() {
1550
1680
  const host = $("chat-console-host");
1551
1681
  const drawer = $("console-drawer");
@@ -2252,6 +2382,14 @@ loadProject().catch(error => {
2252
2382
  $("viewer-body").textContent = `加载失败: ${error.message}`;
2253
2383
  });
2254
2384
  loadProjectStatus();
2385
+
2386
+ const initialView = decodeURIComponent((location.hash || "").replace(/^#/, "").trim());
2387
+ const knownViews = new Set(["project", "ecosystem", "provider", "checklist", "chat", "help"]);
2388
+ if (knownViews.has(initialView)) setView(initialView);
2389
+ window.addEventListener("hashchange", () => {
2390
+ const next = decodeURIComponent((location.hash || "").replace(/^#/, "").trim());
2391
+ if (knownViews.has(next) && next !== state.view) setView(next);
2392
+ });
2255
2393
  </script>
2256
2394
  </body>
2257
2395
  </html>
@@ -29,7 +29,8 @@ import { arsRoot } from "../../ars/pi-panel-executor.js";
29
29
  import { ArsModeEditor, isArsModeEditorText } from "../../ars/mode-editor.js";
30
30
  import { MODE_STATUS, nextSessionMode, parseSessionMode, sessionModePrompt, } from "../../session/modes.js";
31
31
  import { formatVerifyChecklist, isNaturalPlanConfirm, loadVerifyChecklist, markVerifyItem, skipUnverifiedItems } from "../../verify/checklist.js";
32
- import { formatSessionHelp } from "../../session/help.js";
32
+ import { formatSessionHelp, formatSessionHelpBrief } from "../../session/help.js";
33
+ import { openResearchWorkbench } from "../../panel/workbench.js";
33
34
  const PARADIGMS = new Set([
34
35
  "survey-observational",
35
36
  "qualitative-thematic",
@@ -1137,7 +1138,18 @@ export default function psyclawExtension(pi) {
1137
1138
  return { action: "handled" };
1138
1139
  }
1139
1140
  if (/^\/help(?:\s|$)/i.test(event.text.trim())) {
1140
- ctx.ui.notify(formatSessionHelp(), "info");
1141
+ try {
1142
+ const { url, opened } = await openResearchWorkbench({
1143
+ cwd: ctx.cwd,
1144
+ isProjectTrusted: () => ctx.isProjectTrusted(),
1145
+ isIdle: () => ctx.isIdle(),
1146
+ sendUserMessage: (message, options) => pi.sendUserMessage(message, options ?? {}),
1147
+ }, { view: "help" });
1148
+ ctx.ui.notify(formatSessionHelpBrief(url) + (opened ? "" : "\n(未能自动打开浏览器时请手动访问)"), opened ? "info" : "warning");
1149
+ }
1150
+ catch (error) {
1151
+ ctx.ui.notify(`${formatSessionHelp()}\n\n(Panel 未启动:${error instanceof Error ? error.message : String(error)})`, "info");
1152
+ }
1141
1153
  return { action: "handled" };
1142
1154
  }
1143
1155
  const mode = arsModeEditor?.getMode() ?? sessionMode;
@@ -1307,9 +1319,20 @@ export default function psyclawExtension(pi) {
1307
1319
  handler: async (args, ctx) => handleCrosscheck(args, ctx),
1308
1320
  });
1309
1321
  pi.registerCommand("help", {
1310
- description: "三种模式速览与常用命令",
1322
+ description: "打开 Panel 使用速览",
1311
1323
  handler: async (_args, ctx) => {
1312
- ctx.ui.notify(formatSessionHelp(), "info");
1324
+ try {
1325
+ const { url, opened } = await openResearchWorkbench({
1326
+ cwd: ctx.cwd,
1327
+ isProjectTrusted: () => ctx.isProjectTrusted(),
1328
+ isIdle: () => ctx.isIdle(),
1329
+ sendUserMessage: (message, options) => pi.sendUserMessage(message, options ?? {}),
1330
+ }, { view: "help" });
1331
+ ctx.ui.notify(formatSessionHelpBrief(url) + (opened ? "" : "\n(未能自动打开浏览器时请手动访问)"), opened ? "info" : "warning");
1332
+ }
1333
+ catch (error) {
1334
+ ctx.ui.notify(`${formatSessionHelp()}\n\n(Panel 未启动:${error instanceof Error ? error.message : String(error)})`, "info");
1335
+ }
1313
1336
  },
1314
1337
  });
1315
1338
  pi.registerCommand("plan", {