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.
Files changed (39) hide show
  1. package/README.md +9 -7
  2. package/dist/apps/panel/index.html +11 -11
  3. package/dist/src/adapters/pi/extension.js +383 -55
  4. package/dist/src/adapters/pi/extension.js.map +1 -1
  5. package/dist/src/chat.js +2 -2
  6. package/dist/src/chat.js.map +1 -1
  7. package/dist/src/cli.js +1 -4
  8. package/dist/src/cli.js.map +1 -1
  9. package/dist/src/index.d.ts +1 -0
  10. package/dist/src/index.js +1 -0
  11. package/dist/src/index.js.map +1 -1
  12. package/dist/src/integrations/mcp-runtime.d.ts +26 -0
  13. package/dist/src/integrations/mcp-runtime.js +154 -0
  14. package/dist/src/integrations/mcp-runtime.js.map +1 -0
  15. package/dist/src/panel/events.d.ts +2 -1
  16. package/dist/src/panel/events.js +2 -5
  17. package/dist/src/panel/events.js.map +1 -1
  18. package/dist/src/panel/server.js +28 -8
  19. package/dist/src/panel/server.js.map +1 -1
  20. package/dist/src/project/bootstrap.d.ts +17 -0
  21. package/dist/src/project/bootstrap.js +87 -1
  22. package/dist/src/project/bootstrap.js.map +1 -1
  23. package/dist/src/skills/user-skills.d.ts +57 -0
  24. package/dist/src/skills/user-skills.js +294 -0
  25. package/dist/src/skills/user-skills.js.map +1 -0
  26. package/dist/src/style/cli-ui.js +1 -1
  27. package/dist/src/style/cli-ui.js.map +1 -1
  28. package/dist/src/telemetry/export.d.ts +8 -6
  29. package/dist/src/telemetry/export.js +81 -18
  30. package/dist/src/telemetry/export.js.map +1 -1
  31. package/dist/src/tui/skill-manager.d.ts +3 -0
  32. package/dist/src/tui/skill-manager.js +11 -1
  33. package/dist/src/tui/skill-manager.js.map +1 -1
  34. package/package.json +1 -1
  35. package/scripts/rebrand-pi.mjs +66 -4
  36. package/skills/core/citation-audit/SKILL.md +9 -9
  37. package/skills/core/evidence-capture/SKILL.md +9 -9
  38. package/skills/core/research-brief/SKILL.md +8 -8
  39. 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":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAsC,MAAM,UAAU,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AActD,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAc;IACxC,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC;QAChC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAA6B,EAAE,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC;QACtH,CAAC,CAAC,EAAE,CAAC;IACP,OAAO;QACL,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,GAAG,UAAU;KACd,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,KAAc;IACrC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC5G,IAAI,KAAK,CAAC,OAAO,KAAK,KAAK,IAAI,KAAK,CAAC,OAAO,KAAK,KAAK,IAAI,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,IAAI,KAAK,CAAC,SAAS,KAAK,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IAC3I,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACjH,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,IAAI;QACJ,GAAG,EAAE,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC;QAClC,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,IAAI;QACb,GAAG,CAAC,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,SAAS,EAAE,OAAO;KACnB,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,SAAiB;IACxC,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK,GAAG,CAAC,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACrF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,OAAO,GAAuB,EAAE,CAAC;IACvC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;YAC1F,IAAI,MAAM;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC;QAAC,MAAM,CAAC,CAAC,sEAAsE,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAYD;;;;GAIG;AACH,KAAK,UAAU,YAAY,CAAC,SAAiB,EAAE,KAAyB;IACtE,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK,GAAG,CAAC,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACrF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,OAAO,GAAyB,EAAE,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,CAA4B,CAAC;YACnG,IAAI,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ;gBAAE,SAAS;YAChF,OAAO,CAAC,IAAI,CAAC;gBACX,EAAE,EAAE,KAAK,CAAC,EAAE;gBACZ,IAAI,EAAE,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE;gBAC5D,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,OAAO,EAAE,KAAK,CAAC,OAAO,KAAK,KAAK;gBAChC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC;gBAC3B,KAAK;aACN,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC,CAAC,+BAA+B,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,oEAAoE;AACpE,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,KAAyB,EAAE,OAAgB;IACvF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAA4B,CAAC;IACxF,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,MAAM,eAAe,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,OAAO,kBAAkB;IACZ,WAAW,GAAG,IAAI,GAAG,EAA6B,CAAC;IAE7D,KAAK,CAAC,IAAI,CAAC,IAAY,EAAE,QAAiB;QAC/C,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACzC,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QACzF,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,QAAQ,EAAE,CAAC,CAAC;QAC/G,OAAO,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YAC/C,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YACvD,UAAU,CAAC,KAAK,KAAK,MAAM,UAAU,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,IAAI,MAAM,CAAC,EAAE,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,CAAC;QAChG,CAAC,CAAC,CAAC,CAAC;IACN,CAAC;IAEM,KAAK,CAAC,IAAI,CAAC,IAAY,EAAE,QAAgB,EAAE,IAAY,EAAE,KAA8B;QAC5F,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC;QACzF,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,4CAA4C,QAAQ,EAAE,CAAC,CAAC;QACrF,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACvD,UAAU,CAAC,KAAK,KAAK,MAAM,UAAU,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACzD,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,QAAQ,IAAI,IAAI,EAAE,CAAC,CAAC;QACtI,OAAO,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACjD,CAAC;IAEM,KAAK;QACV,KAAK,MAAM,UAAU,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE;YAAE,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC9E,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED,+EAA+E;IACxE,KAAK,CAAC,eAAe,CAAC,IAAY;QACvC,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;QAC5E,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC;QAC7E,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QACjE,KAAK,MAAM,KAAK,IAAI,OAAO;YAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IACrF,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,IAAY;QAChC,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC;QACjE,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC;QAC/D,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;QAClE,KAAK,MAAM,MAAM,IAAI,OAAO;YAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAC5D,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9B,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,IAAY,EAAE,MAAwB;QAC7D,MAAM,GAAG,GAAG,GAAG,IAAI,SAAS,MAAM,CAAC,EAAE,SAAS,MAAM,CAAC,OAAO,SAAS,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QACnG,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAC9B,MAAM,SAAS,GAAG,IAAI,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,SAAS,CAAC,CAAC;QACxC,MAAM,MAAM,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,aAAa,EAAE,CAAC,CAAC;QACpG,MAAM,CAAC,WAAW,EAAE,CAAC;QACrB,MAAM,UAAU,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;QACjD,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QACtC,OAAO,UAAU,CAAC;IACpB,CAAC;CACF"}
@@ -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;
@@ -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,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE1E;;;GAGG;AACH,MAAM,OAAO,WAAW;IAGc;IAA+B;IAFlD,IAAI,CAAS;IAE9B,YAAoC,IAAY,EAAmB,KAAa;QAA5C,SAAI,GAAJ,IAAI,CAAQ;QAAmB,UAAK,GAAL,KAAK,CAAQ;QAC9E,IAAI,CAAC,oCAAoC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACtD,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACjE,CAAC;QACD,IAAI,CAAC,IAAI,GAAG,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,KAAK,QAAQ,CAAC;IAC1D,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,KAAgD;QAClE,MAAM,IAAI,GAAa;YACrB,aAAa,EAAE,sBAAsB;YACrC,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,GAAG,KAAK;YACR,qEAAqE;YACrE,+DAA+D;YAC/D,GAAG,CAAC,KAAK,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClF,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAC5E,MAAM,IAAI,GAAG,MAAM,sBAAsB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACjE,MAAM,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACvC,MAAM,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAEM,KAAK,CAAC,QAAQ;QACnB,MAAM,IAAI,GAAG,MAAM,sBAAsB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACjE,MAAM,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,MAAM,SAAS,CAAU,IAAI,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YAC7B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;gBACjD,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC;YAC/D,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,IAAY,EAAE,KAAa;IACtE,IAAI,CAAC,oCAAoC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,qBAAqB,CAAC,IAAI,EAAE,iBAAiB,KAAK,QAAQ,CAAC,CAAC;IAC/E,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,IAAY,EAAE,YAAqB;IACrE,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,IAAI,CAAC,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IACxG,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,YAAY,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO;QAC/E,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,KAAK,GAAG,KAA0B,CAAC;IACzC,MAAM,UAAU,GAAuB;QACrC,SAAS;QACT,SAAS;QACT,SAAS;QACT,MAAM;QACN,YAAY;QACZ,WAAW;QACX,SAAS;KACV,CAAC;IACF,OAAO,CACL,KAAK,CAAC,aAAa,KAAK,sBAAsB;QAC9C,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ;QAC/B,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ;QAC5B,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;QAC9B,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAwB,CAAC,CACpD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/panel/events.ts"],"names":[],"mappings":"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"}
@@ -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 { projectTraceSnapshot } from "../telemetry/export.js";
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
- if (!kind || !/^[a-z0-9][a-z0-9._-]{0,63}$/i.test(id) || typeof body.enabled !== "boolean")
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)