@pi-unipi/unipi 2.0.13 → 2.1.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/LICENSE +0 -0
- package/package.json +28 -28
- package/packages/ask-user/handoff.ts +0 -0
- package/packages/ask-user/index.ts +3 -1
- package/packages/ask-user/launcher-ui.ts +0 -0
- package/packages/ask-user/package.json +4 -4
- package/packages/ask-user/tools.ts +0 -0
- package/packages/autocomplete/README.md +0 -0
- package/packages/autocomplete/package.json +3 -3
- package/packages/autocomplete/src/__tests__/command-registry.audit.test.ts +0 -0
- package/packages/autocomplete/src/__tests__/provider.sorting.test.ts +0 -0
- package/packages/autocomplete/src/constants.ts +0 -0
- package/packages/autocomplete/src/provider.ts +0 -0
- package/packages/autocomplete/src/sorting.ts +0 -0
- package/packages/btw/package.json +5 -5
- package/packages/cocoindex/README.md +0 -0
- package/packages/cocoindex/bridge.ts +0 -0
- package/packages/cocoindex/commands.ts +0 -0
- package/packages/cocoindex/index.ts +0 -0
- package/packages/cocoindex/installer.ts +0 -0
- package/packages/cocoindex/package.json +5 -5
- package/packages/cocoindex/skills/cocoindex/SKILL.md +0 -0
- package/packages/cocoindex/tools.ts +0 -0
- package/packages/compactor/package.json +6 -6
- package/packages/compactor/src/commands/index.ts +0 -0
- package/packages/compactor/src/compaction/auto-trigger.ts +0 -0
- package/packages/compactor/src/compaction/hooks.ts +0 -0
- package/packages/compactor/src/config/manager.ts +0 -0
- package/packages/compactor/src/config/presets.ts +0 -0
- package/packages/compactor/src/config/schema.ts +0 -0
- package/packages/compactor/src/display/diff-presentation.ts +0 -0
- package/packages/compactor/src/display/diff-renderer.ts +0 -0
- package/packages/compactor/src/display/diff-width-safety.ts +0 -0
- package/packages/compactor/src/display/line-width-safety.ts +0 -0
- package/packages/compactor/src/index.ts +0 -0
- package/packages/compactor/src/info-screen.ts +0 -0
- package/packages/compactor/src/session/analytics.ts +0 -0
- package/packages/compactor/src/session/db.ts +0 -0
- package/packages/compactor/src/session/recall-blocks.ts +0 -0
- package/packages/compactor/src/tools/ctx-batch-execute.ts +0 -0
- package/packages/compactor/src/tools/ctx-doctor.ts +0 -0
- package/packages/compactor/src/tools/ctx-stats.ts +0 -0
- package/packages/compactor/src/tools/register.ts +0 -0
- package/packages/compactor/src/tui/settings-overlay.ts +0 -0
- package/packages/compactor/src/types.ts +0 -0
- package/packages/core/constants.ts +0 -0
- package/packages/core/events.ts +0 -0
- package/packages/core/global-types.ts +0 -0
- package/packages/core/global.d.ts +0 -0
- package/packages/core/package.json +3 -3
- package/packages/core/sandbox.ts +0 -0
- package/packages/footer/README.md +0 -0
- package/packages/footer/index.ts +0 -0
- package/packages/footer/package.json +4 -4
- package/packages/footer/src/commands.ts +0 -0
- package/packages/footer/src/config.ts +0 -0
- package/packages/footer/src/events.ts +0 -0
- package/packages/footer/src/help.ts +0 -0
- package/packages/footer/src/index.ts +0 -0
- package/packages/footer/src/presets.ts +0 -0
- package/packages/footer/src/registry/index.ts +0 -0
- package/packages/footer/src/rendering/icons.ts +0 -0
- package/packages/footer/src/rendering/renderer.ts +0 -0
- package/packages/footer/src/rendering/separators.ts +0 -0
- package/packages/footer/src/rendering/theme.ts +0 -0
- package/packages/footer/src/segments/compactor.ts +0 -0
- package/packages/footer/src/segments/core.ts +0 -0
- package/packages/footer/src/segments/kanboard.ts +0 -0
- package/packages/footer/src/segments/mcp.ts +0 -0
- package/packages/footer/src/segments/memory.ts +0 -0
- package/packages/footer/src/segments/notify.ts +0 -0
- package/packages/footer/src/segments/ralph.ts +0 -0
- package/packages/footer/src/segments/status-ext.ts +0 -0
- package/packages/footer/src/segments/workflow.ts +0 -0
- package/packages/footer/src/tps-tracker.ts +0 -0
- package/packages/footer/src/tui/settings-tui.ts +0 -0
- package/packages/footer/src/types.ts +0 -0
- package/packages/footer/types.ts +0 -0
- package/packages/info-screen/index.ts +3 -1
- package/packages/info-screen/package.json +4 -4
- package/packages/input-shortcuts/README.md +0 -0
- package/packages/input-shortcuts/index.ts +0 -0
- package/packages/input-shortcuts/package.json +4 -4
- package/packages/input-shortcuts/src/chord-overlay.ts +0 -0
- package/packages/input-shortcuts/src/clipboard.ts +0 -0
- package/packages/input-shortcuts/src/index.ts +0 -0
- package/packages/input-shortcuts/src/registers.ts +0 -0
- package/packages/input-shortcuts/src/settings-overlay.ts +0 -0
- package/packages/input-shortcuts/src/status.ts +0 -0
- package/packages/input-shortcuts/src/types.ts +0 -0
- package/packages/input-shortcuts/src/undo-redo.ts +0 -0
- package/packages/kanboard/index.ts +0 -0
- package/packages/kanboard/package.json +4 -4
- package/packages/mcp/package.json +4 -4
- package/packages/mcp/src/index.ts +3 -1
- package/packages/mcp/src/tui/settings-overlay.ts +0 -0
- package/packages/memory/README.md +51 -7
- package/packages/memory/index.ts +7 -4
- package/packages/memory/mempalace.ts +232 -0
- package/packages/memory/package.json +8 -5
- package/packages/memory/storage.ts +237 -22
- package/packages/memory/tools.ts +0 -0
- package/packages/milestone/commands.ts +3 -2
- package/packages/milestone/package.json +4 -4
- package/packages/notify/ask-user-prompt-message.ts +0 -0
- package/packages/notify/commands.ts +0 -0
- package/packages/notify/events.ts +0 -0
- package/packages/notify/index.ts +3 -1
- package/packages/notify/ntfy-config.ts +0 -0
- package/packages/notify/package.json +8 -6
- package/packages/notify/platforms/focus-win.ts +0 -0
- package/packages/notify/platforms/focus.ts +0 -0
- package/packages/notify/platforms/native.ts +0 -0
- package/packages/notify/settings.ts +0 -0
- package/packages/notify/src/__tests__/ask-user-prompt-message.test.ts +0 -0
- package/packages/notify/src/__tests__/event-bus.test.ts +0 -0
- package/packages/notify/tui/settings-overlay.ts +0 -0
- package/packages/notify/types.ts +0 -0
- package/packages/ralph/index.ts +3 -1
- package/packages/ralph/package.json +6 -6
- package/packages/subagents/package.json +7 -7
- package/packages/unipi/index.ts +0 -0
- package/packages/updater/README.md +0 -0
- package/packages/updater/index.ts +0 -0
- package/packages/updater/package.json +4 -4
- package/packages/updater/skills/configure-updater/SKILL.md +0 -0
- package/packages/updater/src/cache.ts +0 -0
- package/packages/updater/src/changelog.ts +0 -0
- package/packages/updater/src/checker.ts +0 -0
- package/packages/updater/src/commands.ts +0 -0
- package/packages/updater/src/installer.ts +0 -0
- package/packages/updater/src/markdown.ts +0 -0
- package/packages/updater/src/readme.ts +3 -1
- package/packages/updater/src/settings.ts +0 -0
- package/packages/updater/src/tui/changelog-overlay.ts +0 -0
- package/packages/updater/src/tui/readme-overlay.ts +0 -0
- package/packages/updater/src/tui/settings-overlay.ts +0 -0
- package/packages/updater/src/tui/update-overlay.ts +0 -0
- package/packages/updater/src/version.ts +0 -0
- package/packages/updater/types.ts +0 -0
- package/packages/utility/package.json +3 -3
- package/packages/utility/src/diff/renderer.ts +0 -0
- package/packages/utility/src/diff/theme.ts +0 -0
- package/packages/utility/src/diff/wrapper.ts +0 -0
- package/packages/utility/src/display/capabilities.ts +0 -0
- package/packages/utility/src/index.ts +3 -1
- package/packages/web-api/package.json +4 -4
- package/packages/web-api/skills/web/SKILL.md +0 -0
- package/packages/web-api/src/engine/constants.ts +0 -0
- package/packages/web-api/src/engine/dependencies.ts +0 -0
- package/packages/web-api/src/engine/dom.ts +0 -0
- package/packages/web-api/src/engine/extract.ts +0 -0
- package/packages/web-api/src/engine/format.ts +0 -0
- package/packages/web-api/src/engine/profiles.ts +0 -0
- package/packages/web-api/src/engine/types.ts +0 -0
- package/packages/web-api/src/index.ts +3 -1
- package/packages/web-api/src/providers/base.ts +0 -0
- package/packages/web-api/src/settings.ts +0 -0
- package/packages/web-api/src/tools.ts +0 -0
- package/packages/web-api/src/tui/progress.ts +0 -0
- package/packages/web-api/src/tui/result.ts +0 -0
- package/packages/web-api/src/tui/settings-dialog.ts +0 -0
- package/packages/workflow/commands.ts +0 -0
- package/packages/workflow/index.ts +3 -1
- package/packages/workflow/package.json +5 -5
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# @pi-unipi/memory
|
|
2
2
|
|
|
3
|
-
Persistent memory that survives across sessions. Stores facts, preferences, and decisions
|
|
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
|
-
|
|
5
|
+
**Primary backend: [MemPalace](https://github.com/mempalace/mempalace)** — auto-installed via `uv` on first load, with one-way auto-migration of any 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
|
+
|
|
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.
|
|
6
8
|
|
|
7
9
|
## Commands
|
|
8
10
|
|
|
@@ -72,19 +74,61 @@ Examples:
|
|
|
72
74
|
Memory has no configuration file. Storage paths are fixed:
|
|
73
75
|
|
|
74
76
|
```
|
|
75
|
-
~/.unipi/memory/
|
|
77
|
+
~/.unipi/memory/ # UniPi memory root (legacy + markdown tier)
|
|
78
|
+
├── .mempalace-install # Cached MemPalace venv detection
|
|
79
|
+
├── .mempalace-migrated # One-way migration completion flag
|
|
76
80
|
├── global/
|
|
77
|
-
│ ├── memory.db # Global vector DB
|
|
81
|
+
│ ├── memory.db # Global vector DB (SQLite fallback)
|
|
78
82
|
│ └── *.md # Global memory files
|
|
79
83
|
└── <project_name>/
|
|
80
|
-
├── memory.db # Project vector DB
|
|
84
|
+
├── memory.db # Project vector DB (SQLite fallback)
|
|
81
85
|
└── *.md # Project memory files
|
|
86
|
+
|
|
87
|
+
~/.mempalace/palace/ # MemPalace palace (primary backend)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## MemPalace backend
|
|
91
|
+
|
|
92
|
+
On first load, the memory package:
|
|
93
|
+
1. Detects MemPalace; if missing and `uv` is available, runs
|
|
94
|
+
`uv tool install mempalace` once (caches the venv python path in
|
|
95
|
+
`~/.unipi/memory/.mempalace-install`).
|
|
96
|
+
2. Pings the bridge to confirm the palace is usable.
|
|
97
|
+
3. If `~/.unipi/memory/.mempalace-migrated` is absent, performs a one-way
|
|
98
|
+
read-only migration of every legacy memory (SQLite rows + markdown files
|
|
99
|
+
across all projects) into MemPalace drawers, then writes the flag.
|
|
100
|
+
Migration is idempotent (deterministic drawer IDs) and never deletes or
|
|
101
|
+
mutates legacy files.
|
|
102
|
+
|
|
103
|
+
Each memory operation invokes a bundled Python bridge
|
|
104
|
+
(`bridge/mempalace_bridge.py`) once via `spawnSync` (~0.5s per call). The
|
|
105
|
+
first MemPalace use on a machine also downloads the default ONNX embedding
|
|
106
|
+
model (~80MB, cached at `~/.cache/chroma/onnx_models/`).
|
|
107
|
+
|
|
108
|
+
### Forcing re-detection / re-migration
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
rm ~/.unipi/memory/.mempalace-install # re-detect MemPalace next session
|
|
112
|
+
rm ~/.unipi/memory/.mempalace-migrated # re-run one-way migration next session
|
|
82
113
|
```
|
|
83
114
|
|
|
115
|
+
### Backend override
|
|
116
|
+
|
|
117
|
+
Set `UNIPI_MEMPALACE_BACKEND` to force a MemPalace backend
|
|
118
|
+
(`sqlite_exact`, `qdrant`, `pgvector`, default `chroma`).
|
|
119
|
+
|
|
120
|
+
### Embedder identity
|
|
121
|
+
|
|
122
|
+
MemPalace enforces embedder identity. If a palace was created with a
|
|
123
|
+
different embedding model, writes are rejected — the package then falls
|
|
124
|
+
back to SQLite for that session. Use `mempalace palace set-embedder`
|
|
125
|
+
intentionally to realign, then remove the install cache to re-detect.
|
|
126
|
+
|
|
84
127
|
## Dependencies
|
|
85
128
|
|
|
86
|
-
- `
|
|
87
|
-
- `
|
|
129
|
+
- `mempalace` (Python, auto-installed via `uv`) — primary backend
|
|
130
|
+
- `better-sqlite3` — SQLite fallback database
|
|
131
|
+
- `sqlite-vec` — Vector search extension (fallback)
|
|
88
132
|
- `js-yaml` — YAML frontmatter parsing
|
|
89
133
|
- `@pi-unipi/core` — Shared utilities
|
|
90
134
|
|
package/packages/memory/index.ts
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* Auto-consolidates on compaction.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { dirname } from "node:path";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
10
12
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
11
13
|
import {
|
|
12
14
|
UNIPI_EVENTS,
|
|
@@ -30,7 +32,7 @@ import { registerMemoryCommands } from "./commands.js";
|
|
|
30
32
|
import { isEmbeddingReady, hasModelChanged } from "./settings.js";
|
|
31
33
|
|
|
32
34
|
/** Package version */
|
|
33
|
-
const VERSION = getPackageVersion(
|
|
35
|
+
const VERSION = getPackageVersion(dirname(fileURLToPath(import.meta.url)));
|
|
34
36
|
|
|
35
37
|
/** Storage instance for current project */
|
|
36
38
|
let projectStorage: MemoryStorage | null = null;
|
|
@@ -170,11 +172,12 @@ export default function (pi: ExtensionAPI) {
|
|
|
170
172
|
} catch (_err) {
|
|
171
173
|
// Count unavailable — status bar shows 0.
|
|
172
174
|
}
|
|
173
|
-
const
|
|
174
|
-
const
|
|
175
|
+
const mempalaceActive = projectStorage?.isMempalace() ?? false;
|
|
176
|
+
const backendIcon = mempalaceActive ? "🧠" : (isEmbeddingReady() ? "⚡" : "📝");
|
|
177
|
+
const warn = hasModelChanged() ? " ⚠" : "";
|
|
175
178
|
ctx.ui.setStatus(
|
|
176
179
|
"unipi-memory",
|
|
177
|
-
`${
|
|
180
|
+
`${backendIcon} mem ${projectCount}p/${projectCountAll}all${warn}`
|
|
178
181
|
);
|
|
179
182
|
}
|
|
180
183
|
});
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @unipi/memory — MemPalace backend client
|
|
3
|
+
*
|
|
4
|
+
* Detects and auto-installs MemPalace (via uv), then invokes the bundled
|
|
5
|
+
* Python bridge (bridge/mempalace_bridge.py) once per operation using the
|
|
6
|
+
* MemPalace venv python. Each call is a synchronous spawnSync that prints
|
|
7
|
+
* one JSON line.
|
|
8
|
+
*
|
|
9
|
+
* If MemPalace or uv is unavailable, all operations return null so the
|
|
10
|
+
* storage layer can fall back to the legacy SQLite path. Memory must never
|
|
11
|
+
* hard-fail because the backend is missing.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { spawnSync } from "node:child_process";
|
|
15
|
+
import * as fs from "node:fs";
|
|
16
|
+
import * as path from "node:path";
|
|
17
|
+
import * as os from "node:os";
|
|
18
|
+
import { fileURLToPath } from "node:url";
|
|
19
|
+
|
|
20
|
+
/** Default MemPalace palace path. */
|
|
21
|
+
export const DEFAULT_PALACE = path.join(os.homedir(), ".mempalace", "palace");
|
|
22
|
+
|
|
23
|
+
const INSTALL_FLAG = path.join(os.homedir(), ".unipi", "memory", ".mempalace-install");
|
|
24
|
+
const MIGRATED_FLAG = path.join(os.homedir(), ".unipi", "memory", ".mempalace-migrated");
|
|
25
|
+
|
|
26
|
+
/** Path to the bundled bridge script. */
|
|
27
|
+
const BRIDGE_PATH = path.join(dirname(fileURLToPath(import.meta.url)), "bridge", "mempalace_bridge.py");
|
|
28
|
+
|
|
29
|
+
function dirname(p: string): string {
|
|
30
|
+
return path.dirname(p);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface BridgeResponse<T> {
|
|
34
|
+
ok: boolean;
|
|
35
|
+
result?: T;
|
|
36
|
+
error?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface MempalaceRecord {
|
|
40
|
+
id: string;
|
|
41
|
+
title: string;
|
|
42
|
+
content: string;
|
|
43
|
+
tags: string[];
|
|
44
|
+
project: string;
|
|
45
|
+
type: "preference" | "decision" | "pattern" | "summary";
|
|
46
|
+
created: string;
|
|
47
|
+
updated: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface MempalaceSearchResult extends MempalaceRecord {
|
|
51
|
+
score: number;
|
|
52
|
+
snippet: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface MempalaceListItem {
|
|
56
|
+
id: string;
|
|
57
|
+
title: string;
|
|
58
|
+
type: string;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface MempalaceListItemAll extends MempalaceListItem {
|
|
62
|
+
project: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface MempalaceInstall {
|
|
66
|
+
python: string;
|
|
67
|
+
version: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Check whether a binary is on PATH. */
|
|
71
|
+
function which(bin: string): string | null {
|
|
72
|
+
try {
|
|
73
|
+
const res = spawnSync(bin, ["--version"], { encoding: "utf-8", timeout: 5000 });
|
|
74
|
+
if (res.status === 0 || res.stdout || res.stderr) return bin;
|
|
75
|
+
} catch { /* ignore */ }
|
|
76
|
+
// Fallback: `which`
|
|
77
|
+
try {
|
|
78
|
+
const res = spawnSync("which", [bin], { encoding: "utf-8" });
|
|
79
|
+
if (res.status === 0) return res.stdout.trim() || null;
|
|
80
|
+
} catch { /* ignore */ }
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Locate the MemPalace venv python after a `uv tool install mempalace`.
|
|
86
|
+
* Uses `uv tool dir` to find the venv root.
|
|
87
|
+
*/
|
|
88
|
+
function findVenvPython(): string | null {
|
|
89
|
+
try {
|
|
90
|
+
const res = spawnSync("uv", ["tool", "dir"], { encoding: "utf-8", timeout: 5000 });
|
|
91
|
+
if (res.status !== 0 || !res.stdout.trim()) return null;
|
|
92
|
+
const candidate = path.join(res.stdout.trim(), "mempalace", "bin", "python");
|
|
93
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
94
|
+
// Some platforms use Scripts/ on Windows — not relevant here but be safe.
|
|
95
|
+
const win = path.join(res.stdout.trim(), "mempalace", "Scripts", "python.exe");
|
|
96
|
+
if (fs.existsSync(win)) return win;
|
|
97
|
+
} catch { /* ignore */ }
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Read a cached install record. */
|
|
102
|
+
function readCachedInstall(): MempalaceInstall | null {
|
|
103
|
+
try {
|
|
104
|
+
if (fs.existsSync(INSTALL_FLAG)) {
|
|
105
|
+
const parsed = JSON.parse(fs.readFileSync(INSTALL_FLAG, "utf-8"));
|
|
106
|
+
if (parsed && parsed.python && fs.existsSync(parsed.python)) {
|
|
107
|
+
return parsed;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} catch { /* ignore */ }
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** Persist an install record so we don't re-detect every session. */
|
|
115
|
+
function writeCachedInstall(install: MempalaceInstall): void {
|
|
116
|
+
try {
|
|
117
|
+
fs.mkdirSync(path.dirname(INSTALL_FLAG), { recursive: true });
|
|
118
|
+
fs.writeFileSync(INSTALL_FLAG, JSON.stringify(install, null, 2), "utf-8");
|
|
119
|
+
} catch { /* ignore */ }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Detect mempalace version via the venv python. */
|
|
123
|
+
function detectVersion(python: string): string {
|
|
124
|
+
try {
|
|
125
|
+
const res = spawnSync(python, ["-c", "import mempalace; print(getattr(mempalace,'__version__','unknown'))"], { encoding: "utf-8", timeout: 5000 });
|
|
126
|
+
return (res.stdout || "").trim() || "unknown";
|
|
127
|
+
} catch {
|
|
128
|
+
return "unknown";
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Ensure MemPalace is installed and return the venv python path.
|
|
134
|
+
* Auto-installs via `uv tool install mempalace` if missing and uv is
|
|
135
|
+
* available. Returns null if MemPalace cannot be made available (caller
|
|
136
|
+
* should fall back to legacy SQLite storage).
|
|
137
|
+
*/
|
|
138
|
+
export function ensureMempalace(): MempalaceInstall | null {
|
|
139
|
+
const cached = readCachedInstall();
|
|
140
|
+
if (cached) return cached;
|
|
141
|
+
|
|
142
|
+
// 1. Already installed via uv tool? Locate venv python.
|
|
143
|
+
let python = findVenvPython();
|
|
144
|
+
|
|
145
|
+
// 2. If not, and uv is available, install it.
|
|
146
|
+
if (!python && which("uv")) {
|
|
147
|
+
try {
|
|
148
|
+
const res = spawnSync("uv", ["tool", "install", "mempalace"], {
|
|
149
|
+
encoding: "utf-8",
|
|
150
|
+
timeout: 180_000, // first install downloads deps + embedding model
|
|
151
|
+
});
|
|
152
|
+
if (res.status === 0) {
|
|
153
|
+
python = findVenvPython();
|
|
154
|
+
}
|
|
155
|
+
} catch { /* ignore — fall back */ }
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!python) return null;
|
|
159
|
+
|
|
160
|
+
const version = detectVersion(python);
|
|
161
|
+
const install = { python, version };
|
|
162
|
+
writeCachedInstall(install);
|
|
163
|
+
return install;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Drop the cached install record (forces re-detection next session). */
|
|
167
|
+
export function invalidateInstallCache(): void {
|
|
168
|
+
try { if (fs.existsSync(INSTALL_FLAG)) fs.unlinkSync(INSTALL_FLAG); } catch { /* ignore */ }
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Has the one-way legacy migration been completed? */
|
|
172
|
+
export function isMigrated(): boolean {
|
|
173
|
+
return fs.existsSync(MIGRATED_FLAG);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** Mark the one-way legacy migration complete. */
|
|
177
|
+
export function markMigrated(): void {
|
|
178
|
+
try {
|
|
179
|
+
fs.mkdirSync(path.dirname(MIGRATED_FLAG), { recursive: true });
|
|
180
|
+
fs.writeFileSync(MIGRATED_FLAG, new Date().toISOString(), "utf-8");
|
|
181
|
+
} catch { /* ignore */ }
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** Force re-migration by clearing the flag. */
|
|
185
|
+
export function clearMigratedFlag(): void {
|
|
186
|
+
try { if (fs.existsSync(MIGRATED_FLAG)) fs.unlinkSync(MIGRATED_FLAG); } catch { /* ignore */ }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Run one bridge command synchronously. Returns the parsed result, or null
|
|
191
|
+
* on any failure (timeout, non-zero exit, bad JSON, ok=false).
|
|
192
|
+
*/
|
|
193
|
+
export function runBridge<T = unknown>(
|
|
194
|
+
install: MempalaceInstall,
|
|
195
|
+
palace: string,
|
|
196
|
+
cmd: string,
|
|
197
|
+
args: Record<string, unknown> = {},
|
|
198
|
+
): T | null {
|
|
199
|
+
let argsJson: string;
|
|
200
|
+
try {
|
|
201
|
+
argsJson = JSON.stringify(args);
|
|
202
|
+
} catch {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
let res;
|
|
206
|
+
try {
|
|
207
|
+
res = spawnSync(install.python, [BRIDGE_PATH, palace, cmd, argsJson], {
|
|
208
|
+
encoding: "utf-8",
|
|
209
|
+
timeout: 60_000,
|
|
210
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
211
|
+
});
|
|
212
|
+
} catch {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
if (res.error || res.status !== 0) {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
const out = (res.stdout || "").trim();
|
|
219
|
+
if (!out) return null;
|
|
220
|
+
try {
|
|
221
|
+
const parsed = JSON.parse(out) as BridgeResponse<T>;
|
|
222
|
+
if (!parsed.ok) return null;
|
|
223
|
+
return (parsed.result ?? null) as T | null;
|
|
224
|
+
} catch {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** Ping the bridge — returns true if the backend is alive. */
|
|
230
|
+
export function ping(install: MempalaceInstall, palace: string): boolean {
|
|
231
|
+
return runBridge<string>(install, palace, "ping") === "pong";
|
|
232
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/memory",
|
|
3
|
-
"version": "2.0
|
|
4
|
-
"description": "Persistent cross-session memory with
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "Persistent cross-session memory with MemPalace backend (auto-installed) and SQLite fallback for Pi coding agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
7
7
|
"license": "MIT",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"pi-coding-agent",
|
|
22
22
|
"unipi",
|
|
23
23
|
"memory",
|
|
24
|
+
"mempalace",
|
|
24
25
|
"vector-search",
|
|
25
26
|
"sqlite-vec"
|
|
26
27
|
],
|
|
@@ -32,6 +33,8 @@
|
|
|
32
33
|
"settings.ts",
|
|
33
34
|
"tools.ts",
|
|
34
35
|
"commands.ts",
|
|
36
|
+
"mempalace.ts",
|
|
37
|
+
"bridge/mempalace_bridge.py",
|
|
35
38
|
"tui/**/*",
|
|
36
39
|
"skills/**/*",
|
|
37
40
|
"README.md"
|
|
@@ -40,11 +43,11 @@
|
|
|
40
43
|
"better-sqlite3": "^12.9.0",
|
|
41
44
|
"sqlite-vec": "^0.1.9",
|
|
42
45
|
"js-yaml": "^4.1.0",
|
|
43
|
-
"@pi-unipi/core": "2.0
|
|
44
|
-
"@pi-unipi/info-screen": "2.0
|
|
46
|
+
"@pi-unipi/core": "2.1.0",
|
|
47
|
+
"@pi-unipi/info-screen": "2.1.0"
|
|
45
48
|
},
|
|
46
49
|
"peerDependencies": {
|
|
47
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
50
|
+
"@earendil-works/pi-coding-agent": "^0.80.0",
|
|
48
51
|
"typebox": "^1.1.38"
|
|
49
52
|
},
|
|
50
53
|
"devDependencies": {
|