@pi-unipi/unipi 2.4.2 → 2.5.0
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/CHANGELOG.md +25 -0
- package/package.json +23 -22
- package/packages/ask-user/package.json +2 -2
- package/packages/autocomplete/package.json +1 -1
- package/packages/btw/package.json +2 -2
- package/packages/cocoindex/package.json +2 -2
- package/packages/compactor/package.json +3 -3
- package/packages/core/package.json +1 -1
- package/packages/core/sandbox.ts +7 -6
- package/packages/footer/package.json +2 -2
- package/packages/image/package.json +2 -2
- package/packages/info-screen/package.json +2 -2
- package/packages/input-shortcuts/package.json +2 -2
- package/packages/kanboard/package.json +2 -2
- package/packages/mcp/README.md +9 -0
- package/packages/mcp/package.json +5 -2
- package/packages/mcp/src/bridge/registry.ts +244 -137
- package/packages/mcp/src/bridge/translator.ts +77 -9
- package/packages/mcp/src/index.ts +43 -67
- package/packages/mcp/src/tui/settings-overlay.ts +3 -9
- package/packages/memory/README.md +15 -11
- package/packages/memory/bridge/mempalace_bridge.py +636 -0
- package/packages/memory/mempalace.ts +169 -18
- package/packages/memory/package.json +3 -3
- package/packages/memory/storage.ts +27 -10
- package/packages/milestone/README.md +11 -3
- package/packages/milestone/hooks.ts +103 -29
- package/packages/milestone/index.ts +1 -1
- package/packages/milestone/package.json +5 -2
- package/packages/notify/package.json +2 -2
- package/packages/ralph/package.json +3 -3
- package/packages/subagents/package.json +1 -1
- package/packages/unipi/bundled.js +693 -408
- package/packages/updater/package.json +2 -2
- package/packages/utility/package.json +2 -2
- package/packages/web-api/package.json +2 -2
- package/packages/workflow/README.md +8 -0
- package/packages/workflow/commands.ts +16 -26
- package/packages/workflow/index.ts +165 -85
- package/packages/workflow/package.json +5 -2
|
@@ -18,6 +18,7 @@ import type { ResolvedServer } from "./types.js";
|
|
|
18
18
|
import { loadAndResolve, getGlobalConfigDir } from "./config/manager.js";
|
|
19
19
|
import { syncCatalog, loadCatalog } from "./config/sync.js";
|
|
20
20
|
import { ServerRegistry } from "./bridge/registry.js";
|
|
21
|
+
import { compareCodeUnits } from "./bridge/translator.js";
|
|
21
22
|
import { renderMcpAddOverlay } from "./tui/add-overlay.js";
|
|
22
23
|
import { renderMcpSettingsOverlay } from "./tui/settings-overlay.js";
|
|
23
24
|
|
|
@@ -42,24 +43,32 @@ export default function (pi: ExtensionAPI) {
|
|
|
42
43
|
// Session start — load configs, start servers
|
|
43
44
|
pi.on("session_start", async (_event, ctx) => {
|
|
44
45
|
// Create registry with pi integration callbacks
|
|
46
|
+
const toolApi = pi as ExtensionAPI & {
|
|
47
|
+
registerExternalTool?: (tool: unknown) => void;
|
|
48
|
+
unregisterTool?: (toolName: string) => void;
|
|
49
|
+
unregisterExternalTool?: (toolName: string) => void;
|
|
50
|
+
};
|
|
51
|
+
const registerTool = typeof toolApi.registerTool === "function"
|
|
52
|
+
? (tool: unknown) => toolApi.registerTool(tool as Parameters<typeof toolApi.registerTool>[0])
|
|
53
|
+
: typeof toolApi.registerExternalTool === "function"
|
|
54
|
+
? (tool: unknown) => toolApi.registerExternalTool!(tool)
|
|
55
|
+
: () => {
|
|
56
|
+
throw new Error("Pi does not expose a supported MCP tool registration API");
|
|
57
|
+
};
|
|
58
|
+
const canUnregisterTools =
|
|
59
|
+
typeof toolApi.unregisterTool === "function" ||
|
|
60
|
+
typeof toolApi.unregisterExternalTool === "function";
|
|
61
|
+
const unregisterTool = typeof toolApi.unregisterTool === "function"
|
|
62
|
+
? (toolName: string) => toolApi.unregisterTool!(toolName)
|
|
63
|
+
: typeof toolApi.unregisterExternalTool === "function"
|
|
64
|
+
? (toolName: string) => toolApi.unregisterExternalTool!(toolName)
|
|
65
|
+
: () => {};
|
|
66
|
+
|
|
45
67
|
registry = new ServerRegistry({
|
|
46
68
|
emitEvent: (event, payload) => emitEvent(pi, event, payload),
|
|
47
|
-
registerTool
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
(pi as any).registerExternalTool?.(tool);
|
|
51
|
-
} catch {
|
|
52
|
-
// Tool registration may not be available in all contexts
|
|
53
|
-
}
|
|
54
|
-
},
|
|
55
|
-
unregisterTool: (toolName) => {
|
|
56
|
-
try {
|
|
57
|
-
(pi as any).unregisterTool?.(toolName) ??
|
|
58
|
-
(pi as any).unregisterExternalTool?.(toolName);
|
|
59
|
-
} catch {
|
|
60
|
-
// Ignore
|
|
61
|
-
}
|
|
62
|
-
},
|
|
69
|
+
registerTool,
|
|
70
|
+
unregisterTool,
|
|
71
|
+
canUnregisterTools,
|
|
63
72
|
});
|
|
64
73
|
|
|
65
74
|
// Load and resolve server configs
|
|
@@ -73,21 +82,13 @@ export default function (pi: ExtensionAPI) {
|
|
|
73
82
|
// Config load failure — servers will be empty, visible via /unipi:mcp-status.
|
|
74
83
|
}
|
|
75
84
|
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// Server status visible via /unipi:mcp-status or info screen.
|
|
84
|
-
} catch (err) {
|
|
85
|
-
// Removed console.error — errors surfaced via info-screen MCP group.
|
|
86
|
-
// Server failure tracked in registry state.
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
await Promise.allSettled(startPromises);
|
|
85
|
+
// Connect/discover in parallel, then register the successful combined set
|
|
86
|
+
// after a barrier so tool order is stable across runs.
|
|
87
|
+
try {
|
|
88
|
+
await registry.startServers(servers.filter((server) => server.enabled));
|
|
89
|
+
} catch (_err) {
|
|
90
|
+
// Errors are tracked in registry state and surfaced by the info screen.
|
|
91
|
+
}
|
|
91
92
|
|
|
92
93
|
// Register info-screen group
|
|
93
94
|
const infoRegistry = getInfoRegistry();
|
|
@@ -153,16 +154,17 @@ export default function (pi: ExtensionAPI) {
|
|
|
153
154
|
`unipi:${MCP_COMMANDS.STATUS}`,
|
|
154
155
|
`unipi:${MCP_COMMANDS.RELOAD}`,
|
|
155
156
|
],
|
|
156
|
-
tools: activeServers
|
|
157
|
-
registry?.getEntry(
|
|
158
|
-
|
|
157
|
+
tools: activeServers
|
|
158
|
+
.flatMap((server) => registry?.getEntry(server.name)?.toolNames ?? [])
|
|
159
|
+
.sort(compareCodeUnits),
|
|
159
160
|
});
|
|
160
161
|
});
|
|
161
162
|
|
|
162
|
-
// Session shutdown
|
|
163
|
+
// Session shutdown tears down clients. Pi tears down this extension's tool
|
|
164
|
+
// registry itself, so do not claim per-tool unregistration here.
|
|
163
165
|
pi.on("session_shutdown", async (_event, _ctx) => {
|
|
164
166
|
if (registry) {
|
|
165
|
-
await registry.
|
|
167
|
+
await registry.disconnectAll();
|
|
166
168
|
registry = null;
|
|
167
169
|
}
|
|
168
170
|
});
|
|
@@ -305,38 +307,12 @@ export default function (pi: ExtensionAPI) {
|
|
|
305
307
|
|
|
306
308
|
// /unipi:mcp-reload — restart all MCP servers
|
|
307
309
|
pi.registerCommand(`unipi:${MCP_COMMANDS.RELOAD}`, {
|
|
308
|
-
description: "
|
|
310
|
+
description: "Explain how to reload MCP servers safely",
|
|
309
311
|
handler: async (_args: string, ctx: ExtensionCommandContext) => {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
const all = reg.getAll();
|
|
317
|
-
if (all.length === 0) {
|
|
318
|
-
ctx.ui.notify("No MCP servers configured. Use /unipi:mcp-add to add one.", "info");
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
ctx.ui.notify(`Reloading ${all.length} MCP server(s)...`, "info");
|
|
323
|
-
|
|
324
|
-
let restarted = 0;
|
|
325
|
-
let failed = 0;
|
|
326
|
-
for (const state of all) {
|
|
327
|
-
try {
|
|
328
|
-
await reg.restartServer(state.name);
|
|
329
|
-
restarted++;
|
|
330
|
-
} catch (_err) {
|
|
331
|
-
failed++;
|
|
332
|
-
// Silently ignore — restart failure tracked in failed count.
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const msg = failed > 0
|
|
337
|
-
? `Reloaded: ${restarted} ok, ${failed} failed`
|
|
338
|
-
: `Reloaded ${restarted} MCP server(s) successfully`;
|
|
339
|
-
ctx.ui.notify(msg, failed > 0 ? "warning" : "info");
|
|
312
|
+
// Pi 0.80 does not expose dynamic tool removal. Restarting in place can
|
|
313
|
+
// leave stale schemas in the provider-visible tool list, so require a
|
|
314
|
+
// process/extension restart to establish a clean cache epoch.
|
|
315
|
+
ctx.ui.notify("Restart Pi to reload MCP servers and tool schemas safely.", "info");
|
|
340
316
|
},
|
|
341
317
|
});
|
|
342
318
|
}
|
|
@@ -141,15 +141,9 @@ export function renderMcpSettingsOverlay(params?: {
|
|
|
141
141
|
};
|
|
142
142
|
saveMetadata(configDir, meta);
|
|
143
143
|
|
|
144
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
await registry.stopServer(server.name);
|
|
148
|
-
} catch {
|
|
149
|
-
// Ignore stop errors
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
144
|
+
// Pi 0.80 cannot remove a registered tool definition at runtime.
|
|
145
|
+
// Persist the setting now; the next Pi restart applies the new set as
|
|
146
|
+
// one deterministic cache epoch.
|
|
153
147
|
refreshServers();
|
|
154
148
|
refresh();
|
|
155
149
|
} catch (err) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Persistent memory that survives across sessions. Stores facts, preferences, and decisions with semantic vector search, so the agent remembers what you told it last week.
|
|
4
4
|
|
|
5
|
-
**Primary backend: [MemPalace](https://github.com/mempalace/mempalace)** — auto-installed via `uv` on first load, with
|
|
5
|
+
**Primary backend: [MemPalace](https://github.com/mempalace/mempalace)** — auto-installed via `uv` on first load, with verified, resumable migration of existing legacy memories. If MemPalace or `uv` is unavailable, the package transparently falls back to the bundled SQLite + sqlite-vec store, so memory never hard-fails.
|
|
6
6
|
|
|
7
7
|
Two storage tiers: MemPalace (or SQLite) for vector similarity search, markdown files for a durable human-readable copy you can edit by hand. Project-scoped memories stay separate per codebase, global memories are accessible everywhere.
|
|
8
8
|
|
|
@@ -76,7 +76,7 @@ Memory has no configuration file. Storage paths are fixed:
|
|
|
76
76
|
```
|
|
77
77
|
~/.unipi/memory/ # UniPi memory root (legacy + markdown tier)
|
|
78
78
|
├── .mempalace-install # Cached MemPalace venv detection
|
|
79
|
-
├── .mempalace-migrated #
|
|
79
|
+
├── .mempalace-migrated # Versioned migration verification state
|
|
80
80
|
├── global/
|
|
81
81
|
│ ├── memory.db # Global vector DB (SQLite fallback)
|
|
82
82
|
│ └── *.md # Global memory files
|
|
@@ -94,14 +94,18 @@ On first load, the memory package:
|
|
|
94
94
|
`uv tool install mempalace` once (caches the venv python path in
|
|
95
95
|
`~/.unipi/memory/.mempalace-install`).
|
|
96
96
|
2. Pings the bridge to confirm the palace is usable.
|
|
97
|
-
3.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
97
|
+
3. Fingerprints the durable SQLite and markdown sources. If they differ from
|
|
98
|
+
the verified state in `~/.unipi/memory/.mempalace-migrated`, performs an
|
|
99
|
+
idempotent read-only migration into MemPalace drawers. Unchanged drawers are
|
|
100
|
+
skipped, new or changed memories are upserted, and the versioned state is
|
|
101
|
+
written only after every discovered record is verified in MemPalace.
|
|
102
|
+
Failed or partial migrations remain unmarked and retry on a later session.
|
|
103
|
+
Legacy files are never deleted or mutated.
|
|
104
|
+
|
|
105
|
+
Each memory operation invokes the packaged Python bridge
|
|
106
|
+
(`bridge/mempalace_bridge.py`) once via `spawnSync` (~0.5s per call). Both the
|
|
107
|
+
standalone memory package and the all-in-one umbrella tarball ship and resolve
|
|
108
|
+
this bridge. The
|
|
105
109
|
first MemPalace use on a machine also downloads the default ONNX embedding
|
|
106
110
|
model (~80MB, cached at `~/.cache/chroma/onnx_models/`).
|
|
107
111
|
|
|
@@ -109,7 +113,7 @@ model (~80MB, cached at `~/.cache/chroma/onnx_models/`).
|
|
|
109
113
|
|
|
110
114
|
```bash
|
|
111
115
|
rm ~/.unipi/memory/.mempalace-install # re-detect MemPalace next session
|
|
112
|
-
rm ~/.unipi/memory/.mempalace-migrated #
|
|
116
|
+
rm ~/.unipi/memory/.mempalace-migrated # force a full verified migration pass next session
|
|
113
117
|
```
|
|
114
118
|
|
|
115
119
|
### Backend override
|