psyclaw 0.27.5 → 0.27.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 +9 -7
- package/dist/apps/panel/index.html +11 -11
- package/dist/src/adapters/pi/extension.js +383 -55
- package/dist/src/adapters/pi/extension.js.map +1 -1
- package/dist/src/chat.js +2 -2
- package/dist/src/chat.js.map +1 -1
- package/dist/src/cli.js +1 -4
- package/dist/src/cli.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/integrations/mcp-runtime.d.ts +26 -0
- package/dist/src/integrations/mcp-runtime.js +154 -0
- package/dist/src/integrations/mcp-runtime.js.map +1 -0
- package/dist/src/panel/events.d.ts +2 -1
- package/dist/src/panel/events.js +2 -5
- package/dist/src/panel/events.js.map +1 -1
- package/dist/src/panel/server.js +28 -8
- package/dist/src/panel/server.js.map +1 -1
- package/dist/src/project/bootstrap.d.ts +17 -0
- package/dist/src/project/bootstrap.js +87 -1
- package/dist/src/project/bootstrap.js.map +1 -1
- package/dist/src/skills/user-skills.d.ts +57 -0
- package/dist/src/skills/user-skills.js +294 -0
- package/dist/src/skills/user-skills.js.map +1 -0
- package/dist/src/style/cli-ui.js +1 -1
- package/dist/src/style/cli-ui.js.map +1 -1
- package/dist/src/telemetry/export.d.ts +8 -6
- package/dist/src/telemetry/export.js +81 -18
- package/dist/src/telemetry/export.js.map +1 -1
- package/dist/src/tui/skill-manager.d.ts +3 -0
- package/dist/src/tui/skill-manager.js +11 -1
- package/dist/src/tui/skill-manager.js.map +1 -1
- package/package.json +1 -1
- package/scripts/rebrand-pi.mjs +66 -4
- package/skills/core/citation-audit/SKILL.md +9 -9
- package/skills/core/evidence-capture/SKILL.md +9 -9
- package/skills/core/research-brief/SKILL.md +8 -8
- package/skills/core/research-intake/SKILL.md +9 -9
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { McpClient, StdioMcpTransport } from "./mcp.js";
|
|
5
|
+
import { atomicWriteFile } from "../project/jsonl.js";
|
|
6
|
+
function isRecord(value) {
|
|
7
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8
|
+
}
|
|
9
|
+
function runtimeEnvironment(value) {
|
|
10
|
+
const configured = isRecord(value)
|
|
11
|
+
? Object.fromEntries(Object.entries(value).filter((entry) => typeof entry[1] === "string"))
|
|
12
|
+
: {};
|
|
13
|
+
return {
|
|
14
|
+
...(process.env.PATH ? { PATH: process.env.PATH } : {}),
|
|
15
|
+
...(process.env.HOME ? { HOME: process.env.HOME } : {}),
|
|
16
|
+
...(process.env.TMPDIR ? { TMPDIR: process.env.TMPDIR } : {}),
|
|
17
|
+
...(process.env.LANG ? { LANG: process.env.LANG } : {}),
|
|
18
|
+
...configured,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function asRuntimeConfig(value) {
|
|
22
|
+
if (!isRecord(value) || typeof value.id !== "string" || typeof value.command !== "string")
|
|
23
|
+
return undefined;
|
|
24
|
+
if (value.enabled === false || value.trusted === false || (value.transport !== undefined && value.transport !== "stdio"))
|
|
25
|
+
return undefined;
|
|
26
|
+
const args = Array.isArray(value.args) && value.args.every((item) => typeof item === "string") ? value.args : [];
|
|
27
|
+
return {
|
|
28
|
+
id: value.id,
|
|
29
|
+
command: value.command,
|
|
30
|
+
args,
|
|
31
|
+
env: runtimeEnvironment(value.env),
|
|
32
|
+
trusted: true,
|
|
33
|
+
enabled: true,
|
|
34
|
+
...(typeof value.name === "string" ? { name: value.name } : {}),
|
|
35
|
+
transport: "stdio",
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
async function configsIn(directory) {
|
|
39
|
+
let names;
|
|
40
|
+
try {
|
|
41
|
+
names = (await readdir(directory)).filter((name) => name.endsWith(".json")).sort();
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
const configs = [];
|
|
47
|
+
for (const name of names) {
|
|
48
|
+
try {
|
|
49
|
+
const config = asRuntimeConfig(JSON.parse(await readFile(join(directory, name), "utf8")));
|
|
50
|
+
if (config)
|
|
51
|
+
configs.push(config);
|
|
52
|
+
}
|
|
53
|
+
catch { /* Ignore malformed entries; they remain visible in MCP management. */ }
|
|
54
|
+
}
|
|
55
|
+
return configs;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Read every MCP config JSON in the user and project directories without the
|
|
59
|
+
* enabled/trusted filter, so the management page can show and toggle disabled
|
|
60
|
+
* servers too. Malformed entries are skipped but still reported by id.
|
|
61
|
+
*/
|
|
62
|
+
async function rawConfigsIn(directory, scope) {
|
|
63
|
+
let names;
|
|
64
|
+
try {
|
|
65
|
+
names = (await readdir(directory)).filter((name) => name.endsWith(".json")).sort();
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
const entries = [];
|
|
71
|
+
for (const name of names) {
|
|
72
|
+
try {
|
|
73
|
+
const value = JSON.parse(await readFile(join(directory, name), "utf8"));
|
|
74
|
+
if (typeof value.id !== "string" || typeof value.command !== "string")
|
|
75
|
+
continue;
|
|
76
|
+
entries.push({
|
|
77
|
+
id: value.id,
|
|
78
|
+
name: typeof value.name === "string" ? value.name : value.id,
|
|
79
|
+
command: value.command,
|
|
80
|
+
enabled: value.enabled !== false,
|
|
81
|
+
path: join(directory, name),
|
|
82
|
+
scope,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
catch { /* Ignore malformed entries. */ }
|
|
86
|
+
}
|
|
87
|
+
return entries;
|
|
88
|
+
}
|
|
89
|
+
/** Rewrite a user MCP config file, preserving every other field. */
|
|
90
|
+
export async function setUserMcpConfigEnabled(entry, enabled) {
|
|
91
|
+
const value = JSON.parse(await readFile(entry.path, "utf8"));
|
|
92
|
+
value.enabled = enabled;
|
|
93
|
+
await atomicWriteFile(entry.path, `${JSON.stringify(value, null, 2)}\n`);
|
|
94
|
+
}
|
|
95
|
+
export class RuntimeMcpRegistry {
|
|
96
|
+
connections = new Map();
|
|
97
|
+
async list(root, serverId) {
|
|
98
|
+
const configs = await this.configs(root);
|
|
99
|
+
const selected = serverId ? configs.filter((config) => config.id === serverId) : configs;
|
|
100
|
+
if (serverId && selected.length === 0)
|
|
101
|
+
throw new Error(`MCP server is not configured or enabled: ${serverId}`);
|
|
102
|
+
return Promise.all(selected.map(async (config) => {
|
|
103
|
+
const connection = await this.connection(root, config);
|
|
104
|
+
connection.tools ??= await connection.client.listTools();
|
|
105
|
+
return { serverId: config.id, serverName: config.name ?? config.id, tools: connection.tools };
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
108
|
+
async call(root, serverId, tool, input) {
|
|
109
|
+
const config = (await this.configs(root)).find((candidate) => candidate.id === serverId);
|
|
110
|
+
if (!config)
|
|
111
|
+
throw new Error(`MCP server is not configured or enabled: ${serverId}`);
|
|
112
|
+
const connection = await this.connection(root, config);
|
|
113
|
+
connection.tools ??= await connection.client.listTools();
|
|
114
|
+
if (!connection.tools.some((candidate) => candidate.name === tool))
|
|
115
|
+
throw new Error(`MCP tool is not available: ${serverId}.${tool}`);
|
|
116
|
+
return connection.client.callTool(tool, input);
|
|
117
|
+
}
|
|
118
|
+
close() {
|
|
119
|
+
for (const connection of this.connections.values())
|
|
120
|
+
connection.client.close();
|
|
121
|
+
this.connections.clear();
|
|
122
|
+
}
|
|
123
|
+
/** All user/project MCP config files (enabled and disabled) for management. */
|
|
124
|
+
async listUserConfigs(root) {
|
|
125
|
+
const user = await rawConfigsIn(join(homedir(), ".psyclaw", "mcp"), "user");
|
|
126
|
+
const project = await rawConfigsIn(join(root, ".psyclaw", "mcp"), "project");
|
|
127
|
+
const merged = new Map(user.map((entry) => [entry.path, entry]));
|
|
128
|
+
for (const entry of project)
|
|
129
|
+
merged.set(entry.path, entry);
|
|
130
|
+
return [...merged.values()].sort((left, right) => left.id.localeCompare(right.id));
|
|
131
|
+
}
|
|
132
|
+
async configs(root) {
|
|
133
|
+
const user = await configsIn(join(homedir(), ".psyclaw", "mcp"));
|
|
134
|
+
const project = await configsIn(join(root, ".psyclaw", "mcp"));
|
|
135
|
+
const merged = new Map(user.map((config) => [config.id, config]));
|
|
136
|
+
for (const config of project)
|
|
137
|
+
merged.set(config.id, config);
|
|
138
|
+
return [...merged.values()];
|
|
139
|
+
}
|
|
140
|
+
async connection(root, config) {
|
|
141
|
+
const key = `${root}\u0000${config.id}\u0000${config.command}\u0000${JSON.stringify(config.args)}`;
|
|
142
|
+
const existing = this.connections.get(key);
|
|
143
|
+
if (existing)
|
|
144
|
+
return existing;
|
|
145
|
+
const transport = new StdioMcpTransport(config);
|
|
146
|
+
const client = new McpClient(transport);
|
|
147
|
+
await client.initialize({ name: "psyclaw", version: process.env.PSYCLAW_VERSION ?? "development" });
|
|
148
|
+
client.initialized();
|
|
149
|
+
const connection = { config, transport, client };
|
|
150
|
+
this.connections.set(key, connection);
|
|
151
|
+
return connection;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=mcp-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-runtime.js","sourceRoot":"","sources":["../../../src/integrations/mcp-runtime.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { RunEvent } from "../orchestration/contracts.js";
|
|
2
2
|
/**
|
|
3
3
|
* Append-only projection of a run's facts. The panel may replay this log, but
|
|
4
|
-
* it never becomes an alternative state store.
|
|
4
|
+
* it never becomes an alternative state store. Event messages and receipts are
|
|
5
|
+
* stored verbatim so traces keep the inputs needed to diagnose each step.
|
|
5
6
|
*/
|
|
6
7
|
export declare class RunEventLog {
|
|
7
8
|
private readonly root;
|
package/dist/src/panel/events.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { redactSecrets } from "../core/redact.js";
|
|
2
1
|
import { lstat } from "node:fs/promises";
|
|
3
2
|
import { appendJsonl, readJsonl } from "../project/jsonl.js";
|
|
4
3
|
import { assertSafeProjectPath, projectPaths } from "../project/paths.js";
|
|
5
4
|
/**
|
|
6
5
|
* Append-only projection of a run's facts. The panel may replay this log, but
|
|
7
|
-
* it never becomes an alternative state store.
|
|
6
|
+
* it never becomes an alternative state store. Event messages and receipts are
|
|
7
|
+
* stored verbatim so traces keep the inputs needed to diagnose each step.
|
|
8
8
|
*/
|
|
9
9
|
export class RunEventLog {
|
|
10
10
|
root;
|
|
@@ -23,9 +23,6 @@ export class RunEventLog {
|
|
|
23
23
|
schemaVersion: "psyclaw/run-event/v1",
|
|
24
24
|
runId: this.runId,
|
|
25
25
|
...event,
|
|
26
|
-
// Free-form text in the log is scrubbed so a model or untrusted tool
|
|
27
|
-
// cannot exfiltrate a credential through a projection surface.
|
|
28
|
-
...(event.message !== undefined ? { message: redactSecrets(event.message) } : {}),
|
|
29
26
|
};
|
|
30
27
|
if (!full.at.trim())
|
|
31
28
|
throw new Error("Run event timestamp cannot be empty");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/panel/events.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/panel/events.ts"],"names":[],"mappings":"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"}
|
package/dist/src/panel/server.js
CHANGED
|
@@ -30,7 +30,7 @@ import { resumePlanWithPi } from "../orchestration/pi-executor.js";
|
|
|
30
30
|
import { RunEventLog } from "./events.js";
|
|
31
31
|
import { PSYCLAW_IDENTITY_PROMPT } from "../branding.js";
|
|
32
32
|
import { recommendedSkillTarget } from "../skills/recommended.js";
|
|
33
|
-
import {
|
|
33
|
+
import { readUserSkillState, scanLocalSkills, setLocalSkillEnabled, userSkillId, } from "../skills/user-skills.js";
|
|
34
34
|
const activePanelRuns = new Set();
|
|
35
35
|
async function readRecommendationState(root) {
|
|
36
36
|
try {
|
|
@@ -848,11 +848,6 @@ export function createPanelServer(root, options = {}) {
|
|
|
848
848
|
response.end(JSON.stringify({ schemaVersion: "psyclaw/panel-project-file/v1", ...(await readPanelProjectFile(root, relative)) }));
|
|
849
849
|
return;
|
|
850
850
|
}
|
|
851
|
-
if (url.pathname === "/api/traces") {
|
|
852
|
-
response.writeHead(200, { "content-type": "application/json" });
|
|
853
|
-
response.end(JSON.stringify(await projectTraceSnapshot({ root })));
|
|
854
|
-
return;
|
|
855
|
-
}
|
|
856
851
|
if (url.pathname === "/api/config") {
|
|
857
852
|
const promptPath = await assertSafeProjectPath(root, ".psyclaw/system-prompt.md");
|
|
858
853
|
let supplement = "";
|
|
@@ -896,12 +891,24 @@ export function createPanelServer(root, options = {}) {
|
|
|
896
891
|
const item = (catalog.items ?? []).find((candidate) => candidate.id === id);
|
|
897
892
|
return typeof item?.name === "string" ? item.name : id;
|
|
898
893
|
};
|
|
894
|
+
// User-installed (non-catalog) skills from the expanded discovery
|
|
895
|
+
// roots, with their individual enable state.
|
|
896
|
+
const userSkillState = await readUserSkillState(root);
|
|
897
|
+
const disabledUserSkills = new Set(userSkillState.disabled);
|
|
898
|
+
const localSkills = (await scanLocalSkills(root, { includeManaged: false })).map((skill) => ({
|
|
899
|
+
id: userSkillId(skill.name),
|
|
900
|
+
name: skill.name,
|
|
901
|
+
description: skill.description,
|
|
902
|
+
path: skill.path,
|
|
903
|
+
enabled: !disabledUserSkills.has(skill.name),
|
|
904
|
+
}));
|
|
899
905
|
response.writeHead(200, { "content-type": "application/json" });
|
|
900
906
|
response.end(JSON.stringify({
|
|
901
907
|
schemaVersion: "psyclaw/enabled-capabilities/v1",
|
|
902
908
|
coreSkills: CORE_SKILLS.map((skill) => ({ id: skill.id, name: skill.name, enabled: !disabled.coreSkills.includes(skill.id) })),
|
|
903
909
|
skills: state.skills.filter((id) => skillIds.has(id)).map((id) => ({ id, name: nameOf("skill", id), enabled: true })),
|
|
904
910
|
mcp: state.mcp.filter((id) => mcpIds.has(id)).map((id) => ({ id, name: nameOf("mcp", id), enabled: true })),
|
|
911
|
+
localSkills,
|
|
905
912
|
}));
|
|
906
913
|
return;
|
|
907
914
|
}
|
|
@@ -1036,9 +1043,12 @@ export function createPanelServer(root, options = {}) {
|
|
|
1036
1043
|
return;
|
|
1037
1044
|
}
|
|
1038
1045
|
const body = await readJsonBody(request);
|
|
1039
|
-
const kind = body.kind === "skill" || body.kind === "skills" ? "skills" : body.kind === "mcp" ? "mcp" : body.kind === "core-skill" ? "core-skill" : undefined;
|
|
1046
|
+
const kind = body.kind === "skill" || body.kind === "skills" ? "skills" : body.kind === "mcp" ? "mcp" : body.kind === "core-skill" ? "core-skill" : body.kind === "local-skill" ? "local-skill" : undefined;
|
|
1040
1047
|
const id = String(body.id ?? "").trim();
|
|
1041
|
-
|
|
1048
|
+
const idValid = kind === "local-skill"
|
|
1049
|
+
? /^local:[^\r\n/\\]{1,64}$/i.test(id)
|
|
1050
|
+
: /^[a-z0-9][a-z0-9._-]{0,63}$/i.test(id);
|
|
1051
|
+
if (!kind || !idValid || typeof body.enabled !== "boolean")
|
|
1042
1052
|
throw new Error("kind, id and enabled are required");
|
|
1043
1053
|
if (kind === "core-skill") {
|
|
1044
1054
|
if (!CORE_SKILLS.some((skill) => skill.id === id))
|
|
@@ -1055,6 +1065,16 @@ export function createPanelServer(root, options = {}) {
|
|
|
1055
1065
|
response.end(JSON.stringify({ schemaVersion: "psyclaw/capability-state-receipt/v1", ok: true, coreSkills: disabled.coreSkills }));
|
|
1056
1066
|
return;
|
|
1057
1067
|
}
|
|
1068
|
+
if (kind === "local-skill") {
|
|
1069
|
+
// id here is the `local:<name>` management key; strip the prefix to
|
|
1070
|
+
// write the user-skill enable state.
|
|
1071
|
+
const name = id.startsWith("local:") ? id.slice("local:".length) : id;
|
|
1072
|
+
await setLocalSkillEnabled(root, name, body.enabled);
|
|
1073
|
+
const state = await readUserSkillState(root);
|
|
1074
|
+
response.writeHead(200, { "content-type": "application/json" });
|
|
1075
|
+
response.end(JSON.stringify({ schemaVersion: "psyclaw/local-skill-state-receipt/v1", ok: true, id, enabled: body.enabled, disabled: state.disabled }));
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1058
1078
|
const state = await readRecommendationState(root);
|
|
1059
1079
|
const values = new Set(state[kind]);
|
|
1060
1080
|
if (body.enabled)
|