psyclaw 0.30.5 → 0.30.7
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 +5 -5
- package/dist/src/adapters/pi/extension.js +235 -1
- package/dist/src/adapters/pi/extension.js.map +1 -1
- package/dist/src/ars/pi-panel-executor.js +14 -4
- package/dist/src/ars/pi-panel-executor.js.map +1 -1
- package/dist/src/ars/re-review.js +14 -4
- package/dist/src/ars/re-review.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/observability/index.d.ts +8 -2
- package/dist/src/observability/index.js +26 -0
- package/dist/src/observability/index.js.map +1 -1
- package/dist/src/observability/llm.js +11 -4
- package/dist/src/observability/llm.js.map +1 -1
- package/dist/src/observability/node-sdks.d.ts +5 -0
- package/dist/src/observability/node-sdks.js +25 -0
- package/dist/src/observability/node-sdks.js.map +1 -1
- package/dist/src/observability/pi-rpc.d.ts +15 -0
- package/dist/src/observability/pi-rpc.js +48 -0
- package/dist/src/observability/pi-rpc.js.map +1 -0
- package/dist/src/session/help.js +1 -0
- package/dist/src/session/help.js.map +1 -1
- package/dist/src/skills/biosignal-pack.d.ts +23 -0
- package/dist/src/skills/biosignal-pack.js +93 -0
- package/dist/src/skills/biosignal-pack.js.map +1 -0
- package/dist/src/style/cli-ui.js +1 -0
- package/dist/src/style/cli-ui.js.map +1 -1
- package/dist/src/tui/biosignal-wizard.d.ts +43 -0
- package/dist/src/tui/biosignal-wizard.js +149 -0
- package/dist/src/tui/biosignal-wizard.js.map +1 -0
- package/package.json +1 -1
- package/skills/recommended/biosignal-pack.json +63 -0
- package/skills/recommended/catalog.json +179 -50
- package/skills/recommended/mcp-catalog.json +1 -1
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.30.
|
|
7
|
+
当前版本:`0.30.7`。正式命令、用户配置目录和后续发布统一使用 `psyclaw`。
|
|
8
8
|
|
|
9
9
|
## 发布流程
|
|
10
10
|
|
|
@@ -21,19 +21,19 @@ 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.30.
|
|
24
|
+
npm install -g psyclaw@0.30.7
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
如果本机 npm 配置把 registry 误写成带有 `~/` 的地址,请显式指定官方源:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
npm install -g psyclaw@0.30.
|
|
30
|
+
npm install -g psyclaw@0.30.7 --registry=https://registry.npmjs.org/
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
中国大陆网络较慢或无法访问官方源时:
|
|
34
34
|
|
|
35
35
|
```powershell
|
|
36
|
-
npm install -g psyclaw@0.30.
|
|
36
|
+
npm install -g psyclaw@0.30.7 --registry=https://registry.npmmirror.com
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
或安装脚本:
|
|
@@ -46,7 +46,7 @@ PSYCLAW_CN=1 curl -fsSL https://exekiel179.github.io/psyclaw/install.sh | sh
|
|
|
46
46
|
```powershell
|
|
47
47
|
# Windows PowerShell
|
|
48
48
|
irm https://exekiel179.github.io/psyclaw/install.ps1 | iex
|
|
49
|
-
# 可选:$env:PSYCLAW_CN = "1";$env:PSYCLAW_VERSION = "0.30.
|
|
49
|
+
# 可选:$env:PSYCLAW_CN = "1";$env:PSYCLAW_VERSION = "0.30.7"
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
检测到国内 npm registry(如 npmmirror)、`PSYCLAW_CN=1` 或 `PSYCLAW_GITHUB_MIRROR` 时,内置路径统一走国内可用路由:
|
|
@@ -16,6 +16,8 @@ import { dirname } from "node:path";
|
|
|
16
16
|
import { fileURLToPath } from "node:url";
|
|
17
17
|
import { coreSkillNames, enabledRecommendedSkillPaths, normalizeRecommendedSkillId, readRecommendationState, readRecommendedCatalog, recommendedSkillTarget, saveRecommendationState, validateModelInstalledRecommendedSkill, } from "../../skills/recommended.js";
|
|
18
18
|
import { SkillManagerComponent } from "../../tui/skill-manager.js";
|
|
19
|
+
import { BiosignalWizardComponent } from "../../tui/biosignal-wizard.js";
|
|
20
|
+
import { readBiosignalPackCatalog, resolveBiosignalInstallPlan, } from "../../skills/biosignal-pack.js";
|
|
19
21
|
import { WakeOptionsComponent } from "../../tui/wake-options.js";
|
|
20
22
|
import { applyWakeVerifySync, buildWakePrompt, createWakeVerifyChecklist, formatWakeResult, labelsFor, waitForPanelWakeAnswer, } from "../../wake-options/runtime.js";
|
|
21
23
|
import { panelHub } from "../../panel/hub.js";
|
|
@@ -36,7 +38,37 @@ import { continuouslyWorkWarningText, isContinuouslyWorkEnabled, } from "../../s
|
|
|
36
38
|
import { assertHumanVerifyGate, formatVerifyChecklist, isNaturalPlanConfirm, isPlanRitualConfirm, PLAN_RITUAL_PHRASE, ensureDefaultVerifyChecklist, loadVerifyChecklist } from "../../verify/checklist.js";
|
|
37
39
|
import { formatSessionHelp, formatSessionHelpBrief } from "../../session/help.js";
|
|
38
40
|
import { openResearchWorkbench } from "../../panel/workbench.js";
|
|
39
|
-
import { captureAgentError, initNodeObservability, readTelemetryPreference, shutdownObservability, trackGateWaiting, trackSkillInstall, withAgentSpan, writeTelemetryPreference, } from "../../observability/index.js";
|
|
41
|
+
import { captureAgentError, extractPiGeneration, finishAgentSpan, initNodeObservability, lastPiGeneration, readTelemetryPreference, shutdownObservability, startAgentSpan, trackGateWaiting, trackLlmGeneration, trackSkillInstall, withAgentSpan, writeTelemetryPreference, } from "../../observability/index.js";
|
|
42
|
+
function ctxProviderModel(ctx) {
|
|
43
|
+
const provider = typeof ctx.model?.provider === "string" ? ctx.model.provider : undefined;
|
|
44
|
+
const model = typeof ctx.model?.id === "string" ? ctx.model.id : undefined;
|
|
45
|
+
return {
|
|
46
|
+
...(provider === undefined ? {} : { provider }),
|
|
47
|
+
...(model === undefined ? {} : { model }),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function piTurnSpanAttributes(extras = {}) {
|
|
51
|
+
return {
|
|
52
|
+
phase: "pi_turn",
|
|
53
|
+
...(extras.provider ? { provider: extras.provider.slice(0, 80) } : {}),
|
|
54
|
+
...(extras.model ? { model: extras.model.slice(0, 120) } : {}),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async function emitPiTurnGeneration(generation, extras) {
|
|
58
|
+
if (!generation)
|
|
59
|
+
return false;
|
|
60
|
+
const provider = generation.provider ?? extras.provider;
|
|
61
|
+
const model = generation.model ?? extras.model;
|
|
62
|
+
await trackLlmGeneration({
|
|
63
|
+
...generation,
|
|
64
|
+
...(provider === undefined ? {} : { provider }),
|
|
65
|
+
...(model === undefined ? {} : { model }),
|
|
66
|
+
...(extras.latencyMs === undefined ? {} : { latencyMs: extras.latencyMs }),
|
|
67
|
+
surface: "cli",
|
|
68
|
+
spanName: "pi-turn",
|
|
69
|
+
});
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
40
72
|
/** Codex-style slash surface: bare command, or command + trailing free text. No subcommand trees. */
|
|
41
73
|
function parseInitArgs(args) {
|
|
42
74
|
const goal = args.trim();
|
|
@@ -801,6 +833,147 @@ async function queueModelSkillInstall(pi, ctx, row) {
|
|
|
801
833
|
ctx.ui.notify(`已将 ${row.name} 的安装任务交给当前模型(默认启用),目标为${skillScopeLabel(scope)}。完成后请执行 /reload。`, "info");
|
|
802
834
|
});
|
|
803
835
|
}
|
|
836
|
+
function modelBiosignalPackInstallTask(root, plan, skillRows, mcpRows, mcpPlans, skillScope) {
|
|
837
|
+
const skillLines = plan.skillIds.map((id) => {
|
|
838
|
+
const row = skillRows.find((candidate) => candidate.id === id);
|
|
839
|
+
const target = recommendedSkillTarget(root, id, skillScope);
|
|
840
|
+
return [
|
|
841
|
+
`- Skill ${row?.name ?? id} (${id})`,
|
|
842
|
+
` 来源:${row?.sourceRef ?? "未提供"}`,
|
|
843
|
+
...(row?.installHint ? [` 入口提示:${row.installHint}`] : []),
|
|
844
|
+
` 目标目录:${target}`,
|
|
845
|
+
row?.collection
|
|
846
|
+
? " 形态:多 Skill 套件(子目录含 SKILL.md)"
|
|
847
|
+
: " 形态:叶子 Skill(目标目录直接含 SKILL.md)",
|
|
848
|
+
].join("\n");
|
|
849
|
+
});
|
|
850
|
+
const mcpLines = plan.mcpIds.map((id) => {
|
|
851
|
+
const row = mcpRows.find((candidate) => candidate.id === id);
|
|
852
|
+
const prep = mcpPlans.find((candidate) => candidate.id === id);
|
|
853
|
+
return [
|
|
854
|
+
`- MCP ${row?.name ?? id} (${id})`,
|
|
855
|
+
` 来源:${row?.sourceRef ?? "未提供"}`,
|
|
856
|
+
` 参考命令:${typeof prep?.command === "string" ? prep.command : "请阅读来源仓库安装说明"}`,
|
|
857
|
+
` 建议配置:${typeof prep?.target === "string" ? prep.target : `.psyclaw/mcp/${id}.json`}`,
|
|
858
|
+
].join("\n");
|
|
859
|
+
});
|
|
860
|
+
return [
|
|
861
|
+
"安装并配置「生理信号分析」能力包。",
|
|
862
|
+
`研究域:${plan.domainNames.join("、")}(${plan.domainIds.join(", ")})`,
|
|
863
|
+
`当前项目:${root}`,
|
|
864
|
+
`Skill 安装位置:${skillScopeLabel(skillScope)}。`,
|
|
865
|
+
"用户已通过 /biosignal 向导明确授权本次打包安装。你可以直接联网、克隆或下载来源、使用所需包管理器安装依赖、执行安装命令,并写入与清单有关的项目或用户级配置;不要再次要求用户批准这些安装步骤。",
|
|
866
|
+
"不要写入 data/raw、.git、凭据或符号链接目标。不要把模型口头声称当作完成证据;每个条目安装后检查目标目录或 MCP 配置是否存在。",
|
|
867
|
+
"",
|
|
868
|
+
"MCP 清单:",
|
|
869
|
+
...(mcpLines.length > 0 ? mcpLines : ["(无)"]),
|
|
870
|
+
"",
|
|
871
|
+
"Skill 清单:",
|
|
872
|
+
...(skillLines.length > 0 ? skillLines : ["(无)"]),
|
|
873
|
+
"",
|
|
874
|
+
"目录中的版本、命令和依赖只作参考;请先阅读各来源仓库的实际安装说明再落地。各项已在推荐状态中默认启用;全部完成后执行 /reload,并提醒用户:Shift+Tab 切到 analysis,用自然语言描述数据与分析目标即可开始。",
|
|
875
|
+
"若某一条目安装命令本身失败,直接诊断并修复;只有遇到必须由用户提供的凭据或外部软件许可证时才向用户说明。",
|
|
876
|
+
].join("\n");
|
|
877
|
+
}
|
|
878
|
+
async function markBiosignalPackDesired(root, plan, skillScope) {
|
|
879
|
+
const state = await readRecommendationState(root);
|
|
880
|
+
const skills = new Set(state.skills);
|
|
881
|
+
const mcp = new Set(state.mcp);
|
|
882
|
+
const skillScopes = { ...(state.skillScopes ?? {}) };
|
|
883
|
+
for (const id of plan.skillIds) {
|
|
884
|
+
const normalized = normalizeRecommendedSkillId(id);
|
|
885
|
+
skills.add(normalized);
|
|
886
|
+
skillScopes[normalized] = skillScope;
|
|
887
|
+
}
|
|
888
|
+
for (const id of plan.mcpIds)
|
|
889
|
+
mcp.add(id);
|
|
890
|
+
state.skills = [...skills];
|
|
891
|
+
state.mcp = [...mcp];
|
|
892
|
+
state.skillScopes = skillScopes;
|
|
893
|
+
await saveRecommendationState(root, state);
|
|
894
|
+
}
|
|
895
|
+
async function queueBiosignalPackInstall(pi, ctx, plan, runtime) {
|
|
896
|
+
if (plan.mcpIds.length === 0 && plan.skillIds.length === 0) {
|
|
897
|
+
ctx.ui.notify("所选研究域没有需要安装的 MCP 或 Skill。", "info");
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
const skillScope = plan.skillIds.length > 0 ? await chooseSkillScope(ctx) : "project";
|
|
901
|
+
if (plan.skillIds.length > 0 && !skillScope)
|
|
902
|
+
return;
|
|
903
|
+
const scope = skillScope ?? "project";
|
|
904
|
+
const skillCatalog = await readRecommendedCatalog();
|
|
905
|
+
const mcpCatalog = await recommendedItems("mcp");
|
|
906
|
+
const missingSkills = plan.skillIds.filter((id) => {
|
|
907
|
+
const item = skillCatalog.items.find((candidate) => normalizeRecommendedSkillId(String(candidate.id ?? "")) === normalizeRecommendedSkillId(id));
|
|
908
|
+
return !item || typeof item.sourceRef !== "string" || !/^https:\/\//.test(item.sourceRef);
|
|
909
|
+
});
|
|
910
|
+
if (missingSkills.length > 0) {
|
|
911
|
+
throw new Error(`能力包 Skill 缺少可安装来源:${missingSkills.join(", ")}`);
|
|
912
|
+
}
|
|
913
|
+
const skillRows = plan.skillIds.map((id) => {
|
|
914
|
+
const item = skillCatalog.items.find((candidate) => normalizeRecommendedSkillId(String(candidate.id ?? "")) === normalizeRecommendedSkillId(id));
|
|
915
|
+
return {
|
|
916
|
+
id: normalizeRecommendedSkillId(id),
|
|
917
|
+
name: String(item.name ?? id),
|
|
918
|
+
description: String(item.description ?? ""),
|
|
919
|
+
sourceRef: String(item.sourceRef),
|
|
920
|
+
...(typeof item.installHint === "string" ? { installHint: item.installHint } : {}),
|
|
921
|
+
collection: item.skillLayout === "collection",
|
|
922
|
+
installed: false,
|
|
923
|
+
enabled: true,
|
|
924
|
+
scope,
|
|
925
|
+
blocked: false,
|
|
926
|
+
source: "recommended",
|
|
927
|
+
};
|
|
928
|
+
});
|
|
929
|
+
const mcpRows = await mcpManagerRows(ctx.cwd, await readRecommendationState(ctx.cwd), runtime);
|
|
930
|
+
const selectedMcp = plan.mcpIds.map((id) => {
|
|
931
|
+
const row = mcpRows.find((candidate) => candidate.id === id);
|
|
932
|
+
if (!row?.sourceRef)
|
|
933
|
+
throw new Error(`能力包 MCP 缺少来源网址:${id}`);
|
|
934
|
+
return row;
|
|
935
|
+
});
|
|
936
|
+
const summary = [
|
|
937
|
+
`研究域:${plan.domainNames.join("、")}`,
|
|
938
|
+
plan.mcpIds.length > 0 ? `MCP:${plan.mcpIds.join(", ")}` : "MCP:无",
|
|
939
|
+
plan.skillIds.length > 0 ? `Skill:${plan.skillIds.join(", ")}` : "Skill:无",
|
|
940
|
+
plan.skillIds.length > 0 ? `Skill 安装位置:${skillScopeLabel(scope)}` : "",
|
|
941
|
+
].filter(Boolean).join("\n");
|
|
942
|
+
const approved = await ctx.ui.confirm("交给当前模型安装生理信号能力包?", `${summary}\n\n模型将按现有 /mcp 与 /skill 约定完成下载与配置;安装后默认启用。`);
|
|
943
|
+
if (!approved)
|
|
944
|
+
return;
|
|
945
|
+
await markBiosignalPackDesired(ctx.cwd, plan, scope);
|
|
946
|
+
pi.sendUserMessage(modelBiosignalPackInstallTask(ctx.cwd, plan, skillRows, selectedMcp, mcpCatalog.installPrep, scope), ctx.isIdle() ? {} : { deliverAs: "followUp" });
|
|
947
|
+
ctx.ui.notify("已将生理信号能力包安装任务交给当前模型。完成后请执行 /reload,并 Shift+Tab 切到 analysis 使用。", "info");
|
|
948
|
+
}
|
|
949
|
+
async function showBiosignalPack(pi, ctx, runtime) {
|
|
950
|
+
const catalog = await readBiosignalPackCatalog();
|
|
951
|
+
if (!ctx.hasUI || typeof ctx.ui.custom !== "function") {
|
|
952
|
+
const lines = [
|
|
953
|
+
"生理信号分析能力包(无交互 UI 时仅列出研究域):",
|
|
954
|
+
...catalog.domains.map((domain) => `- ${domain.id}: ${domain.name} — ${domain.description}`),
|
|
955
|
+
"请在交互式终端运行 /biosignal 完成选型与安装。",
|
|
956
|
+
];
|
|
957
|
+
ctx.ui.notify(lines.join("\n"), "info");
|
|
958
|
+
return;
|
|
959
|
+
}
|
|
960
|
+
const result = await ctx.ui.custom((tui, theme, keybindings, done) => (new BiosignalWizardComponent(catalog.domains.map((domain) => ({
|
|
961
|
+
id: domain.id,
|
|
962
|
+
name: domain.name,
|
|
963
|
+
description: domain.description,
|
|
964
|
+
})), (domainIds) => {
|
|
965
|
+
const plan = resolveBiosignalInstallPlan(catalog, domainIds);
|
|
966
|
+
return {
|
|
967
|
+
domainNames: plan.domainNames,
|
|
968
|
+
mcpIds: plan.mcpIds,
|
|
969
|
+
skillIds: plan.skillIds,
|
|
970
|
+
};
|
|
971
|
+
}, tui, theme, keybindings, done)));
|
|
972
|
+
if (result.type === "close")
|
|
973
|
+
return;
|
|
974
|
+
const plan = resolveBiosignalInstallPlan(catalog, result.domainIds);
|
|
975
|
+
await queueBiosignalPackInstall(pi, ctx, plan, runtime);
|
|
976
|
+
}
|
|
804
977
|
async function showSkillManager(pi, ctx) {
|
|
805
978
|
if (!ctx.hasUI || typeof ctx.ui.custom !== "function") {
|
|
806
979
|
const state = await readRecommendationState(ctx.cwd);
|
|
@@ -976,6 +1149,9 @@ export default function psyclawExtension(pi) {
|
|
|
976
1149
|
let arsModeEditor;
|
|
977
1150
|
let arsUiContext;
|
|
978
1151
|
let sessionMode = "chat";
|
|
1152
|
+
let turnStartedAt;
|
|
1153
|
+
let llmTurnSpan;
|
|
1154
|
+
let capturedTurnGeneration = false;
|
|
979
1155
|
const applySessionMode = (mode, opts) => {
|
|
980
1156
|
sessionMode = mode;
|
|
981
1157
|
arsModeEditor?.setMode(mode);
|
|
@@ -1020,9 +1196,55 @@ export default function psyclawExtension(pi) {
|
|
|
1020
1196
|
});
|
|
1021
1197
|
if (!legacyTestApi && typeof pi.on === "function")
|
|
1022
1198
|
pi.on("session_shutdown", () => {
|
|
1199
|
+
finishAgentSpan(llmTurnSpan);
|
|
1200
|
+
llmTurnSpan = undefined;
|
|
1023
1201
|
runtimeMcps.close();
|
|
1024
1202
|
void shutdownObservability();
|
|
1025
1203
|
});
|
|
1204
|
+
if (!legacyTestApi && typeof pi.on === "function")
|
|
1205
|
+
pi.on("agent_start", () => {
|
|
1206
|
+
capturedTurnGeneration = false;
|
|
1207
|
+
});
|
|
1208
|
+
if (!legacyTestApi && typeof pi.on === "function")
|
|
1209
|
+
pi.on("turn_start", async (event, ctx) => {
|
|
1210
|
+
finishAgentSpan(llmTurnSpan);
|
|
1211
|
+
turnStartedAt = typeof event.timestamp === "number" && Number.isFinite(event.timestamp)
|
|
1212
|
+
? event.timestamp
|
|
1213
|
+
: Date.now();
|
|
1214
|
+
llmTurnSpan = await startAgentSpan("cli.llm_call", piTurnSpanAttributes(ctxProviderModel(ctx)));
|
|
1215
|
+
});
|
|
1216
|
+
if (!legacyTestApi && typeof pi.on === "function")
|
|
1217
|
+
pi.on("turn_end", async (event, ctx) => {
|
|
1218
|
+
const fallback = ctxProviderModel(ctx);
|
|
1219
|
+
const generation = extractPiGeneration({ type: "message", message: event.message });
|
|
1220
|
+
const latencyMs = turnStartedAt === undefined ? undefined : Math.max(0, Date.now() - turnStartedAt);
|
|
1221
|
+
const provider = generation?.provider ?? fallback.provider;
|
|
1222
|
+
const model = generation?.model ?? fallback.model;
|
|
1223
|
+
finishAgentSpan(llmTurnSpan, piTurnSpanAttributes({
|
|
1224
|
+
...(provider === undefined ? {} : { provider }),
|
|
1225
|
+
...(model === undefined ? {} : { model }),
|
|
1226
|
+
}));
|
|
1227
|
+
llmTurnSpan = undefined;
|
|
1228
|
+
if (await emitPiTurnGeneration(generation, { ...fallback, ...(latencyMs === undefined ? {} : { latencyMs }) })) {
|
|
1229
|
+
capturedTurnGeneration = true;
|
|
1230
|
+
turnStartedAt = undefined;
|
|
1231
|
+
}
|
|
1232
|
+
});
|
|
1233
|
+
if (!legacyTestApi && typeof pi.on === "function")
|
|
1234
|
+
pi.on("agent_end", async (event, ctx) => {
|
|
1235
|
+
const fallback = ctxProviderModel(ctx);
|
|
1236
|
+
finishAgentSpan(llmTurnSpan, piTurnSpanAttributes(fallback));
|
|
1237
|
+
llmTurnSpan = undefined;
|
|
1238
|
+
const latencyMs = turnStartedAt === undefined ? undefined : Math.max(0, Date.now() - turnStartedAt);
|
|
1239
|
+
turnStartedAt = undefined;
|
|
1240
|
+
if (capturedTurnGeneration) {
|
|
1241
|
+
capturedTurnGeneration = false;
|
|
1242
|
+
return;
|
|
1243
|
+
}
|
|
1244
|
+
capturedTurnGeneration = false;
|
|
1245
|
+
const generation = lastPiGeneration([event]);
|
|
1246
|
+
await emitPiTurnGeneration(generation, { ...fallback, ...(latencyMs === undefined ? {} : { latencyMs }) });
|
|
1247
|
+
});
|
|
1026
1248
|
if (!legacyTestApi && typeof pi.on === "function")
|
|
1027
1249
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
1028
1250
|
if (!(await readActiveProject(ctx?.cwd ?? process.cwd())))
|
|
@@ -1559,6 +1781,18 @@ export default function psyclawExtension(pi) {
|
|
|
1559
1781
|
}
|
|
1560
1782
|
},
|
|
1561
1783
|
});
|
|
1784
|
+
if (!legacyTestApi)
|
|
1785
|
+
pi.registerCommand("biosignal", {
|
|
1786
|
+
description: "生理信号分析能力包:选型研究域并安装 MCP/Skill",
|
|
1787
|
+
handler: async (_args, ctx) => {
|
|
1788
|
+
try {
|
|
1789
|
+
await showBiosignalPack(pi, ctx, runtimeMcps);
|
|
1790
|
+
}
|
|
1791
|
+
catch (error) {
|
|
1792
|
+
await notifyError(ctx, error);
|
|
1793
|
+
}
|
|
1794
|
+
},
|
|
1795
|
+
});
|
|
1562
1796
|
if (!legacyTestApi)
|
|
1563
1797
|
pi.registerCommand("ars", {
|
|
1564
1798
|
description: "学术模式:单独开启,或附带任务文本启动完整流程",
|