@pi-unipi/unipi 2.0.13 → 2.1.1
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 +5 -5
- package/packages/ask-user/tools.ts +20 -11
- package/packages/autocomplete/README.md +0 -0
- package/packages/autocomplete/package.json +4 -4
- 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 +6 -6
- 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 +6 -6
- package/packages/cocoindex/skills/cocoindex/SKILL.md +0 -0
- package/packages/cocoindex/tools.ts +0 -0
- package/packages/compactor/package.json +7 -7
- 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/core/utils.ts +26 -0
- package/packages/footer/README.md +0 -0
- package/packages/footer/index.ts +0 -0
- package/packages/footer/package.json +5 -5
- 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 +71 -4
- 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 +109 -33
- 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 +5 -5
- package/packages/info-screen/tui/info-overlay.ts +16 -7
- package/packages/input-shortcuts/README.md +0 -0
- package/packages/input-shortcuts/index.ts +0 -0
- package/packages/input-shortcuts/package.json +5 -5
- 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 +5 -5
- package/packages/mcp/package.json +5 -5
- 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 +260 -0
- package/packages/memory/package.json +8 -5
- package/packages/memory/storage.ts +253 -22
- package/packages/memory/tools.ts +0 -0
- package/packages/milestone/commands.ts +3 -2
- package/packages/milestone/package.json +5 -5
- 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 +8 -8
- package/packages/subagents/src/index.ts +27 -23
- 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 +5 -5
- 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 +4 -4
- 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
|
@@ -4,37 +4,112 @@
|
|
|
4
4
|
* Per-message TPS calculation for live generation rate display.
|
|
5
5
|
* Tracks individual assistant messages with start/stop timestamps
|
|
6
6
|
* to measure generation rate excluding idle/tool-execution time.
|
|
7
|
+
*
|
|
8
|
+
* ## Token counting
|
|
9
|
+
*
|
|
10
|
+
* Output tokens are counted from the assistant message *content* (text +
|
|
11
|
+
* thinking blocks) via a lightweight word/char heuristic, NOT from
|
|
12
|
+
* `usage.output`. Rationale:
|
|
13
|
+
* - `usage.output` is only populated by the provider at stream end (or in
|
|
14
|
+
* a final `message_delta`), so it is 0 throughout generation and useless
|
|
15
|
+
* for a live rate.
|
|
16
|
+
* - Counting the streamed text ourselves gives a real, monotonically
|
|
17
|
+
* increasing numerator that reflects how much the model has actually
|
|
18
|
+
* produced so far.
|
|
19
|
+
* - This matches what users perceive as "tokens per second" (visible
|
|
20
|
+
* output rate) and avoids the previous bug where the displayed TPS was
|
|
21
|
+
* always inflated to 90+ t/s (caused by dividing a post-hoc `usage.output`
|
|
22
|
+
* total by a too-short, incorrectly measured elapsed window).
|
|
23
|
+
*
|
|
24
|
+
* The heuristic intentionally over-counts slightly (whitespace + punctuation
|
|
25
|
+
* are treated as tokens). That is acceptable for a live speed indicator and
|
|
26
|
+
* keeps the estimate in the right order of magnitude (within ~10-20% of the
|
|
27
|
+
* provider's reported output tokens for typical English/code output).
|
|
7
28
|
*/
|
|
8
29
|
|
|
9
30
|
/** Per-message TPS record */
|
|
10
31
|
interface MessageTpsRecord {
|
|
11
|
-
/** Message index in the session */
|
|
32
|
+
/** Message index in the session (sequential, assistant-only) */
|
|
12
33
|
messageIndex: number;
|
|
13
|
-
/**
|
|
34
|
+
/** Estimated output tokens produced so far for this message */
|
|
14
35
|
outputTokens: number;
|
|
15
|
-
/** When generation started (Date.now()) */
|
|
36
|
+
/** When generation started (Date.now(), ms) */
|
|
16
37
|
startedAt: number;
|
|
17
|
-
/** When generation completed (Date.now()), 0 if still generating */
|
|
38
|
+
/** When generation completed (Date.now(), ms), 0 if still generating */
|
|
18
39
|
completedAt: number;
|
|
19
|
-
/** Computed TPS for this message */
|
|
40
|
+
/** Computed TPS for this message (final, once completed) */
|
|
20
41
|
tps: number;
|
|
21
42
|
}
|
|
22
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Estimate the number of tokens in a string.
|
|
46
|
+
*
|
|
47
|
+
* Uses a cheap word + punctuation split. Good enough for a live TPS display;
|
|
48
|
+
* we deliberately avoid pulling in a full BPE tokenizer for performance and
|
|
49
|
+
* footprint reasons.
|
|
50
|
+
*/
|
|
51
|
+
function estimateTokens(text: string): number {
|
|
52
|
+
if (!text) return 0;
|
|
53
|
+
// Count word-ish tokens and standalone punctuation.
|
|
54
|
+
// \p{L} / \p{N} keep this Unicode-aware for non-ASCII content.
|
|
55
|
+
const wordish = text.match(/[\p{L}\p{N}]+/gu);
|
|
56
|
+
const punct = text.match(/[^\s\p{L}\p{N}]+/gu);
|
|
57
|
+
const wordCount = wordish ? wordish.length : 0;
|
|
58
|
+
const punctCount = punct ? punct.length : 0;
|
|
59
|
+
return wordCount + punctCount;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Estimate output tokens from an assistant message by summing text and
|
|
64
|
+
* thinking content lengths. Tool-call argument JSON is also counted since
|
|
65
|
+
* it represents model output.
|
|
66
|
+
*
|
|
67
|
+
* Accepts the raw message shape from pi's session entries (loosely typed).
|
|
68
|
+
*/
|
|
69
|
+
function estimateOutputTokens(message: unknown): number {
|
|
70
|
+
if (!message || typeof message !== "object") return 0;
|
|
71
|
+
const m = message as Record<string, unknown>;
|
|
72
|
+
if (m.role !== "assistant") return 0;
|
|
73
|
+
const content = m.content;
|
|
74
|
+
if (!Array.isArray(content)) return 0;
|
|
75
|
+
|
|
76
|
+
let total = 0;
|
|
77
|
+
for (const block of content) {
|
|
78
|
+
if (!block || typeof block !== "object") continue;
|
|
79
|
+
const b = block as Record<string, unknown>;
|
|
80
|
+
const type = b.type;
|
|
81
|
+
if (type === "text" && typeof b.text === "string") {
|
|
82
|
+
total += estimateTokens(b.text);
|
|
83
|
+
} else if (type === "thinking" && typeof b.thinking === "string") {
|
|
84
|
+
total += estimateTokens(b.thinking);
|
|
85
|
+
} else if (type === "tool_use" || type === "toolcall") {
|
|
86
|
+
// Count tool name + serialized arguments as model output.
|
|
87
|
+
const name = typeof b.name === "string" ? b.name : "";
|
|
88
|
+
const input = b.input ?? b.arguments;
|
|
89
|
+
let inputStr: string;
|
|
90
|
+
try {
|
|
91
|
+
inputStr = typeof input === "string" ? input : JSON.stringify(input ?? "");
|
|
92
|
+
} catch {
|
|
93
|
+
inputStr = "";
|
|
94
|
+
}
|
|
95
|
+
total += estimateTokens(name) + estimateTokens(inputStr);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return total;
|
|
99
|
+
}
|
|
100
|
+
|
|
23
101
|
/**
|
|
24
102
|
* Tracks per-message TPS and computes live/session metrics.
|
|
25
103
|
*
|
|
26
|
-
* Usage: Call `onMessageUpdate()`
|
|
27
|
-
* The tracker records generation start/stop
|
|
28
|
-
*
|
|
104
|
+
* Usage: Call `onMessageUpdate()` on every tick (e.g. 1s interval) with the
|
|
105
|
+
* current assistant message state. The tracker records generation start/stop
|
|
106
|
+
* per message and computes live TPS from elapsed wall-clock time.
|
|
29
107
|
*/
|
|
30
108
|
export class TpsTracker {
|
|
31
|
-
/** Per-message records */
|
|
109
|
+
/** Per-message records (one per assistant message, in order) */
|
|
32
110
|
private records: MessageTpsRecord[] = [];
|
|
33
111
|
|
|
34
|
-
/**
|
|
35
|
-
private lastSeenMessageCount = 0;
|
|
36
|
-
|
|
37
|
-
/** Total output tokens across all completed messages */
|
|
112
|
+
/** Total estimated output tokens across all messages */
|
|
38
113
|
private totalOutput = 0;
|
|
39
114
|
|
|
40
115
|
/**
|
|
@@ -42,15 +117,16 @@ export class TpsTracker {
|
|
|
42
117
|
* Call this on every tick (e.g. 1s interval) with the current state.
|
|
43
118
|
*
|
|
44
119
|
* @param messageIndex - Index of the assistant message (0-based, sequential)
|
|
45
|
-
* @param
|
|
120
|
+
* @param message - The assistant message object (content used to count tokens)
|
|
46
121
|
* @param hasStopReason - Whether this message has completed (has stopReason)
|
|
47
122
|
*/
|
|
48
|
-
onMessageUpdate(messageIndex: number,
|
|
123
|
+
onMessageUpdate(messageIndex: number, message: unknown, hasStopReason: boolean): void {
|
|
49
124
|
const now = Date.now();
|
|
125
|
+
const outputTokens = estimateOutputTokens(message);
|
|
50
126
|
|
|
51
127
|
// New message — create a record
|
|
52
128
|
if (messageIndex >= this.records.length) {
|
|
53
|
-
// Fill gaps if indices jump
|
|
129
|
+
// Fill gaps if indices jump (shouldn't normally happen)
|
|
54
130
|
while (this.records.length < messageIndex) {
|
|
55
131
|
this.records.push({
|
|
56
132
|
messageIndex: this.records.length,
|
|
@@ -62,11 +138,12 @@ export class TpsTracker {
|
|
|
62
138
|
}
|
|
63
139
|
|
|
64
140
|
if (hasStopReason && outputTokens > 0) {
|
|
65
|
-
// Fast message: already completed on first sighting
|
|
66
|
-
//
|
|
67
|
-
|
|
141
|
+
// Fast message: already completed on first sighting.
|
|
142
|
+
// We never observed it streaming, so we can't measure real duration.
|
|
143
|
+
// Fall back to a conservative estimate instead of inventing a 1s
|
|
144
|
+
// window (which previously produced inflated TPS values).
|
|
145
|
+
const estimatedDuration = Math.max(0.5, outputTokens / 60);
|
|
68
146
|
const tps = outputTokens / estimatedDuration;
|
|
69
|
-
|
|
70
147
|
this.records.push({
|
|
71
148
|
messageIndex,
|
|
72
149
|
outputTokens,
|
|
@@ -85,7 +162,6 @@ export class TpsTracker {
|
|
|
85
162
|
tps: 0,
|
|
86
163
|
});
|
|
87
164
|
}
|
|
88
|
-
this.lastSeenMessageCount = messageIndex + 1;
|
|
89
165
|
return;
|
|
90
166
|
}
|
|
91
167
|
|
|
@@ -93,23 +169,24 @@ export class TpsTracker {
|
|
|
93
169
|
const record = this.records[messageIndex];
|
|
94
170
|
if (!record) return;
|
|
95
171
|
|
|
96
|
-
record.
|
|
172
|
+
if (record.completedAt === 0) {
|
|
173
|
+
// Still generating — update token count (live TPS computed on demand)
|
|
174
|
+
record.outputTokens = outputTokens;
|
|
97
175
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
// Still generating — update output tokens (live TPS computed on demand)
|
|
176
|
+
if (hasStopReason) {
|
|
177
|
+
// Message just completed
|
|
178
|
+
record.completedAt = now;
|
|
179
|
+
const durationSec = (record.completedAt - record.startedAt) / 1000;
|
|
180
|
+
record.tps = durationSec > 0 ? record.outputTokens / durationSec : 0;
|
|
181
|
+
this.totalOutput += record.outputTokens;
|
|
182
|
+
}
|
|
106
183
|
}
|
|
107
184
|
}
|
|
108
185
|
|
|
109
186
|
/**
|
|
110
187
|
* Get the live TPS from the currently generating message.
|
|
111
188
|
* Returns the instantaneous rate based on tokens generated so far
|
|
112
|
-
* in the current message divided by elapsed time.
|
|
189
|
+
* in the current message divided by elapsed wall-clock time.
|
|
113
190
|
*/
|
|
114
191
|
getLiveTps(): number {
|
|
115
192
|
// Find the last record that's still generating
|
|
@@ -177,7 +254,7 @@ export class TpsTracker {
|
|
|
177
254
|
}
|
|
178
255
|
|
|
179
256
|
/**
|
|
180
|
-
* Get total output tokens for the session.
|
|
257
|
+
* Get total output tokens for the session (estimated).
|
|
181
258
|
*/
|
|
182
259
|
getTotalOutput(): number {
|
|
183
260
|
// Include tokens from incomplete messages too
|
|
@@ -195,7 +272,6 @@ export class TpsTracker {
|
|
|
195
272
|
*/
|
|
196
273
|
reset(): void {
|
|
197
274
|
this.records = [];
|
|
198
|
-
this.lastSeenMessageCount = 0;
|
|
199
275
|
this.totalOutput = 0;
|
|
200
276
|
}
|
|
201
277
|
}
|
|
File without changes
|
|
File without changes
|
package/packages/footer/types.ts
CHANGED
|
File without changes
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* /unipi:info-settings - Configure info display
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { dirname } from "node:path";
|
|
13
|
+
import { fileURLToPath } from "node:url";
|
|
12
14
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
13
15
|
import { UNIPI_EVENTS, MODULES, UNIPI_PREFIX, emitEvent, getPackageVersion, type UnipiModuleEvent, type UnipiInfoGroupEvent } from "@pi-unipi/core";
|
|
14
16
|
import { infoRegistry } from "./registry.js";
|
|
@@ -21,7 +23,7 @@ import { InfoOverlay } from "./tui/info-overlay.js";
|
|
|
21
23
|
import { SettingsOverlay } from "./settings/settings-tui.js";
|
|
22
24
|
|
|
23
25
|
/** Package version */
|
|
24
|
-
const VERSION = getPackageVersion(
|
|
26
|
+
const VERSION = getPackageVersion(dirname(fileURLToPath(import.meta.url)));
|
|
25
27
|
|
|
26
28
|
export default function (pi: ExtensionAPI) {
|
|
27
29
|
setPiApi(pi);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/info-screen",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Dashboard and module registry for Unipi
|
|
3
|
+
"version": "2.1.1",
|
|
4
|
+
"description": "Dashboard and module registry for Unipi — configurable info overlay with tabbed groups",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
7
7
|
"license": "MIT",
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@pi-unipi/core": "2.
|
|
36
|
+
"@pi-unipi/core": "2.1.1"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
40
|
-
"@earendil-works/pi-tui": "^0.
|
|
39
|
+
"@earendil-works/pi-coding-agent": "^0.80.0",
|
|
40
|
+
"@earendil-works/pi-tui": "^0.80.0",
|
|
41
41
|
"typebox": "^1.1.38"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
@@ -94,15 +94,24 @@ export class InfoOverlay implements Component {
|
|
|
94
94
|
|
|
95
95
|
/**
|
|
96
96
|
* Fetch all groups in background. Each resolves independently.
|
|
97
|
+
*
|
|
98
|
+
* Each fetch is deferred to a macrotask (setTimeout 0) so the constructor
|
|
99
|
+
* returns immediately. Without this, getGroupData() runs each group's
|
|
100
|
+
* dataProvider synchronously up to its first `await` before yielding —
|
|
101
|
+
* heavy providers (usage stats parse 1GB+ of session files, memory scans)
|
|
102
|
+
* blocked the session_start handler for seconds.
|
|
97
103
|
*/
|
|
98
|
-
private
|
|
104
|
+
private fetchAllBackground(): void {
|
|
99
105
|
for (const group of this.groups) {
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
this.
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
+
// Defer each fetch to a macrotask so the overlay constructs instantly.
|
|
107
|
+
setTimeout(() => {
|
|
108
|
+
if (this._destroyed) return;
|
|
109
|
+
infoRegistry.getGroupData(group.id).then(() => {
|
|
110
|
+
this.groupLoading.set(group.id, false);
|
|
111
|
+
}).catch(() => {
|
|
112
|
+
this.groupLoading.set(group.id, false);
|
|
113
|
+
});
|
|
114
|
+
}, 0);
|
|
106
115
|
}
|
|
107
116
|
}
|
|
108
117
|
|
|
File without changes
|
|
File without changes
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/input-shortcuts",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Keyboard shortcuts for stash/restore, undo/redo, clipboard, and thinking toggle
|
|
3
|
+
"version": "2.1.1",
|
|
4
|
+
"description": "Keyboard shortcuts for stash/restore, undo/redo, clipboard, and thinking toggle — chord-based overlay system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"license": "MIT",
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@pi-unipi/core": "2.
|
|
36
|
+
"@pi-unipi/core": "2.1.1"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
40
|
-
"@earendil-works/pi-tui": "^0.
|
|
39
|
+
"@earendil-works/pi-coding-agent": "^0.80.0",
|
|
40
|
+
"@earendil-works/pi-tui": "^0.80.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^25.6.0",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/kanboard",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "Visualization layer for unipi workflow
|
|
3
|
+
"version": "2.1.1",
|
|
4
|
+
"description": "Visualization layer for unipi workflow — HTTP server with htmx/Alpine.js UI, modular parsers, TUI overlay, and kanban board",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
7
7
|
"license": "MIT",
|
|
@@ -39,11 +39,11 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@pi-unipi/core": "2.
|
|
42
|
+
"@pi-unipi/core": "2.1.1"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
46
|
-
"@earendil-works/pi-tui": "^0.
|
|
45
|
+
"@earendil-works/pi-coding-agent": "^0.80.0",
|
|
46
|
+
"@earendil-works/pi-tui": "^0.80.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@types/node": "^25.6.0",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/mcp",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "MCP server management extension for Pi coding agent
|
|
3
|
+
"version": "2.1.1",
|
|
4
|
+
"description": "MCP server management extension for Pi coding agent — browse, add, configure, and use MCP servers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"license": "MIT",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"README.md"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@pi-unipi/core": "2.
|
|
30
|
+
"@pi-unipi/core": "2.1.1"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
34
|
-
"@earendil-works/pi-tui": "^0.
|
|
33
|
+
"@earendil-works/pi-coding-agent": "^0.80.0",
|
|
34
|
+
"@earendil-works/pi-tui": "^0.80.0",
|
|
35
35
|
"typebox": "^1.1.38"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* Registers commands, handles session lifecycle, wires up MCP server management.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { dirname } from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
7
9
|
import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
8
10
|
import {
|
|
9
11
|
UNIPI_EVENTS,
|
|
@@ -20,7 +22,7 @@ import { renderMcpAddOverlay } from "./tui/add-overlay.js";
|
|
|
20
22
|
import { renderMcpSettingsOverlay } from "./tui/settings-overlay.js";
|
|
21
23
|
|
|
22
24
|
/** Package version */
|
|
23
|
-
const VERSION = getPackageVersion(
|
|
25
|
+
const VERSION = getPackageVersion(dirname(fileURLToPath(import.meta.url)));
|
|
24
26
|
|
|
25
27
|
/** Module-local registry instance */
|
|
26
28
|
let registry: ServerRegistry | null = null;
|
|
File without changes
|
|
@@ -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
|
});
|