@pi-unipi/unipi 0.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/README.md +143 -0
- package/package.json +70 -0
- package/packages/btw/README.md +95 -0
- package/packages/btw/extensions/btw.ts +1972 -0
- package/packages/btw/skills/btw/SKILL.md +149 -0
- package/packages/core/README.md +74 -0
- package/packages/core/index.ts +10 -0
- package/packages/info-screen/README.md +115 -0
- package/packages/info-screen/index.ts +165 -0
- package/packages/memory/README.md +94 -0
- package/packages/memory/index.ts +209 -0
- package/packages/memory/skills/memory/SKILL.md +151 -0
- package/packages/ralph/README.md +101 -0
- package/packages/ralph/index.ts +548 -0
- package/packages/subagents/README.md +114 -0
- package/packages/unipi/index.ts +28 -0
- package/packages/workflow/README.md +129 -0
- package/packages/workflow/index.ts +155 -0
- package/packages/workflow/skills/brainstorm/SKILL.md +202 -0
- package/packages/workflow/skills/consolidate/SKILL.md +142 -0
- package/packages/workflow/skills/consultant/SKILL.md +97 -0
- package/packages/workflow/skills/document/SKILL.md +120 -0
- package/packages/workflow/skills/gather-context/SKILL.md +122 -0
- package/packages/workflow/skills/plan/SKILL.md +169 -0
- package/packages/workflow/skills/quick-work/SKILL.md +110 -0
- package/packages/workflow/skills/review-work/SKILL.md +131 -0
- package/packages/workflow/skills/scan-issues/SKILL.md +183 -0
- package/packages/workflow/skills/work/SKILL.md +144 -0
- package/packages/workflow/skills/worktree-create/SKILL.md +69 -0
- package/packages/workflow/skills/worktree-list/SKILL.md +67 -0
- package/packages/workflow/skills/worktree-merge/SKILL.md +79 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: btw
|
|
3
|
+
description: Helps you use the /btw side-conversation workflow effectively. Use when you want to think in parallel, ask side questions without interrupting ongoing work, or inject a side thread back into the main agent.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# BTW
|
|
7
|
+
|
|
8
|
+
Use this skill when the user wants to work in parallel with the main agent instead of derailing the current turn.
|
|
9
|
+
|
|
10
|
+
## When to use BTW
|
|
11
|
+
|
|
12
|
+
Prefer the BTW workflow when the user wants to:
|
|
13
|
+
|
|
14
|
+
- ask a side question while the main agent keeps working
|
|
15
|
+
- brainstorm or compare options without interrupting the current run
|
|
16
|
+
- prepare a plan or summary before handing it back to the main agent
|
|
17
|
+
- keep exploratory discussion out of the main transcript/context
|
|
18
|
+
|
|
19
|
+
## Commands
|
|
20
|
+
|
|
21
|
+
Use these commands in your guidance to the user:
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
/btw <question>
|
|
25
|
+
/btw --save <question>
|
|
26
|
+
/btw:new [question]
|
|
27
|
+
/btw:tangent <question>
|
|
28
|
+
/btw:tangent --save <question>
|
|
29
|
+
/btw:clear
|
|
30
|
+
/btw:inject [instructions]
|
|
31
|
+
/btw:summarize [instructions]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## How to guide the user
|
|
35
|
+
|
|
36
|
+
### For a quick side question
|
|
37
|
+
|
|
38
|
+
Recommend:
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
/btw <question>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Use this when the user wants an immediate aside and does not need a visible saved note.
|
|
45
|
+
|
|
46
|
+
### For a saved one-off note
|
|
47
|
+
|
|
48
|
+
Recommend:
|
|
49
|
+
|
|
50
|
+
```text
|
|
51
|
+
/btw --save <question>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Use this when the user wants the exchange to appear as a visible BTW note in the session transcript.
|
|
55
|
+
|
|
56
|
+
### For a fresh side thread
|
|
57
|
+
|
|
58
|
+
Recommend:
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
/btw:new
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
or
|
|
65
|
+
|
|
66
|
+
```text
|
|
67
|
+
/btw:new <question>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Use this when the previous BTW discussion is no longer relevant, but you still want the new side thread to inherit the current main-session context.
|
|
71
|
+
|
|
72
|
+
### For a contextless tangent thread
|
|
73
|
+
|
|
74
|
+
Recommend:
|
|
75
|
+
|
|
76
|
+
```text
|
|
77
|
+
/btw:tangent <question>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
or
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
/btw:tangent --save <question>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Use this when the user wants a side conversation that does not include the current main-session context.
|
|
87
|
+
|
|
88
|
+
### To hand the full thread back to the main agent
|
|
89
|
+
|
|
90
|
+
Recommend:
|
|
91
|
+
|
|
92
|
+
```text
|
|
93
|
+
/btw:inject <instructions>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Use this when the exact discussion matters and the user wants the main agent to act on it.
|
|
97
|
+
|
|
98
|
+
### To hand back a condensed version
|
|
99
|
+
|
|
100
|
+
Recommend:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
/btw:summarize <instructions>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Use this when the thread is long and only the distilled outcome should go back into the main agent.
|
|
107
|
+
|
|
108
|
+
## Recommendation rules
|
|
109
|
+
|
|
110
|
+
- Prefer `/btw` over normal chat when the user explicitly wants a side conversation.
|
|
111
|
+
- Prefer `/btw:tangent` when the user wants that side conversation to be contextless.
|
|
112
|
+
- Prefer `/btw:summarize` over `/btw:inject` for long exploratory threads.
|
|
113
|
+
- Prefer `/btw:inject` when precise wording, detailed tradeoffs, or a full plan matters.
|
|
114
|
+
- Suggest `/btw:new` before starting a totally unrelated side topic when main-session context is still useful.
|
|
115
|
+
- Suggest `/btw:clear` when the widget/thread should be dismissed.
|
|
116
|
+
|
|
117
|
+
## Response style
|
|
118
|
+
|
|
119
|
+
When helping the user use BTW:
|
|
120
|
+
|
|
121
|
+
- give the exact slash command to run
|
|
122
|
+
- explain briefly why that command fits
|
|
123
|
+
- keep the guidance short and operational
|
|
124
|
+
|
|
125
|
+
## Examples
|
|
126
|
+
|
|
127
|
+
### Example: brainstorm while coding continues
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
/btw what are the risks of switching this to optimistic updates?
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Example: create a clean new thread
|
|
134
|
+
|
|
135
|
+
```text
|
|
136
|
+
/btw:new sketch a safer migration plan
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Example: start a contextless tangent
|
|
140
|
+
|
|
141
|
+
```text
|
|
142
|
+
/btw:tangent think through this from first principles without using the current chat context
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Example: send the result back
|
|
146
|
+
|
|
147
|
+
```text
|
|
148
|
+
/btw:summarize implement the recommended migration plan
|
|
149
|
+
```
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# @pi-unipi/core
|
|
2
|
+
|
|
3
|
+
Shared utilities, event types, and constants for the [Unipi](https://github.com/Neuron-Mr-White/unipi) extension suite.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pi install npm:@pi-unipi/core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or as part of the full suite:
|
|
12
|
+
```bash
|
|
13
|
+
pi install npm:unipi
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { UNIPI_EVENTS, MODULES, sanitize, emitEvent } from "@pi-unipi/core";
|
|
20
|
+
|
|
21
|
+
// Emit module ready event
|
|
22
|
+
emitEvent(pi, UNIPI_EVENTS.MODULE_READY, {
|
|
23
|
+
name: MODULES.WORKFLOW,
|
|
24
|
+
version: "1.0.0",
|
|
25
|
+
commands: ["brainstorm", "plan"],
|
|
26
|
+
tools: [],
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Use shared utilities
|
|
30
|
+
const safeName = sanitize("my/feature: branch");
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Exports
|
|
34
|
+
|
|
35
|
+
### Constants
|
|
36
|
+
- `UNIPI_PREFIX` — Command prefix (`unipi:`)
|
|
37
|
+
- `MODULES` — All module names
|
|
38
|
+
- `WORKFLOW_COMMANDS` — Workflow command names
|
|
39
|
+
- `RALPH_COMMANDS` — Ralph command names
|
|
40
|
+
- `RALPH_TOOLS` — Ralph tool names
|
|
41
|
+
- `RALPH_DEFAULTS` — Default ralph settings
|
|
42
|
+
- `RALPH_DIR` — Ralph state directory
|
|
43
|
+
- `RALPH_COMPLETE_MARKER` — Loop completion marker
|
|
44
|
+
|
|
45
|
+
### Events
|
|
46
|
+
- `UNIPI_EVENTS` — Event names
|
|
47
|
+
- `UnipiModuleEvent` — Module ready/gone payload
|
|
48
|
+
- `UnipiWorkflowEvent` — Workflow start/end payload
|
|
49
|
+
- `UnipiRalphLoopEvent` — Ralph loop start/end payload
|
|
50
|
+
- `UnipiRalphIterationEvent` — Ralph iteration payload
|
|
51
|
+
- `UnipiStatusRequestEvent` / `UnipiStatusResponseEvent` — Status payloads
|
|
52
|
+
|
|
53
|
+
### Utilities
|
|
54
|
+
- `sanitize(name)` — Sanitize string for filenames
|
|
55
|
+
- `ensureDir(path)` — Create parent directories
|
|
56
|
+
- `tryDelete(path)` — Safe file deletion
|
|
57
|
+
- `tryRead(path)` — Safe file read
|
|
58
|
+
- `safeMtimeMs(path)` — File modification time
|
|
59
|
+
- `tryRemoveDir(path)` — Safe directory removal
|
|
60
|
+
- `resolvePath(cwd, path)` — Resolve relative/absolute paths
|
|
61
|
+
- `fileExists(path)` — Check file existence
|
|
62
|
+
- `writeFile(path, content)` — Write file with dir creation
|
|
63
|
+
- `readJson<T>(path)` — Read JSON file
|
|
64
|
+
- `writeJson(path, data)` — Write JSON file
|
|
65
|
+
- `randomId(length)` — Generate random ID
|
|
66
|
+
- `now()` — ISO timestamp
|
|
67
|
+
- `parseArgs(str)` — Parse quoted arguments
|
|
68
|
+
- `getPackageVersion(dir)` — Read package version
|
|
69
|
+
- `isModuleAvailable(cwd, name)` — Check if npm module exists
|
|
70
|
+
- `emitEvent(pi, name, payload)` — Safe event emission
|
|
71
|
+
|
|
72
|
+
## License
|
|
73
|
+
|
|
74
|
+
MIT
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# @pi-unipi/info-screen
|
|
2
|
+
|
|
3
|
+
Dashboard and module registry for [Unipi](https://github.com/Neuron-Mr-White/unipi). Shows a configurable info overlay on boot with tabbed groups from all registered modules.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pi install npm:@pi-unipi/info-screen
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or as part of the full suite:
|
|
12
|
+
```bash
|
|
13
|
+
pi install npm:unipi
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Commands
|
|
17
|
+
|
|
18
|
+
| Command | Description |
|
|
19
|
+
|---------|-------------|
|
|
20
|
+
| `/unipi:info` | Show info screen dashboard |
|
|
21
|
+
| `/unipi:info-settings` | Configure info display (groups, stats, visibility) |
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- **Module discovery** — listens for `MODULE_READY` events, tracks all registered modules
|
|
26
|
+
- **Tabbed groups** — each module registers info groups with custom data providers
|
|
27
|
+
- **Configurable** — per-group and per-stat visibility via settings
|
|
28
|
+
- **Boot overlay** — shows dashboard on session start (configurable)
|
|
29
|
+
- **Styled dialog chrome** — uses pi-tui theme API for consistent borders, scrollable content, and navigation hints (matching the overlay style used by @pi-unipi/btw)
|
|
30
|
+
- **Core groups** — modules, tools, load time, session info out of the box
|
|
31
|
+
|
|
32
|
+
## Registering a Group
|
|
33
|
+
|
|
34
|
+
Other modules register info groups via the global registry:
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { infoRegistry } from "@pi-unipi/info-screen";
|
|
38
|
+
|
|
39
|
+
infoRegistry.registerGroup({
|
|
40
|
+
id: "my-module",
|
|
41
|
+
name: "My Module",
|
|
42
|
+
icon: "📦",
|
|
43
|
+
priority: 60,
|
|
44
|
+
config: {
|
|
45
|
+
showByDefault: true,
|
|
46
|
+
stats: [
|
|
47
|
+
{ id: "status", label: "Status", show: true },
|
|
48
|
+
{ id: "count", label: "Count", show: true },
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
dataProvider: async () => ({
|
|
52
|
+
status: { value: "running" },
|
|
53
|
+
count: { value: "42", detail: "items processed" },
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## API
|
|
59
|
+
|
|
60
|
+
### `infoRegistry`
|
|
61
|
+
|
|
62
|
+
Singleton registry instance. Also available globally via `globalThis.__unipi_info_registry`.
|
|
63
|
+
|
|
64
|
+
| Method | Description |
|
|
65
|
+
|--------|-------------|
|
|
66
|
+
| `registerGroup(group)` | Register an info group |
|
|
67
|
+
| `unregisterGroup(id)` | Remove a group |
|
|
68
|
+
| `getGroups()` | Get visible groups (sorted by priority) |
|
|
69
|
+
| `getAllGroups()` | Get all groups (including hidden) |
|
|
70
|
+
| `getGroupData(id)` | Get data for a group (cached) |
|
|
71
|
+
| `updateGroupData(id, data)` | Manually update group data |
|
|
72
|
+
| `getVisibleStats(id)` | Get enabled stats for a group |
|
|
73
|
+
| `invalidateCache(id)` | Invalidate cached data |
|
|
74
|
+
|
|
75
|
+
### Load Tracking
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import { startLoadTracking, recordLoadTime, finishLoadTracking, recordModuleStart } from "@pi-unipi/info-screen";
|
|
79
|
+
|
|
80
|
+
// Track module load times
|
|
81
|
+
startLoadTracking();
|
|
82
|
+
recordModuleStart("@pi-unipi/memory");
|
|
83
|
+
// ... module loads ...
|
|
84
|
+
recordLoadTime("@pi-unipi/memory", "module", 150);
|
|
85
|
+
finishLoadTracking();
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Settings
|
|
89
|
+
|
|
90
|
+
Configure in pi `settings.json`:
|
|
91
|
+
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"unipi": {
|
|
95
|
+
"infoScreen": {
|
|
96
|
+
"showOnBoot": true,
|
|
97
|
+
"bootTimeoutMs": 8000,
|
|
98
|
+
"groups": {
|
|
99
|
+
"modules": { "show": true },
|
|
100
|
+
"ralph": { "show": true },
|
|
101
|
+
"memory": { "show": false }
|
|
102
|
+
},
|
|
103
|
+
"groupOrder": ["modules", "ralph", "subagents"]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## Dependencies
|
|
110
|
+
|
|
111
|
+
- `@pi-unipi/core` — shared constants and events
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
MIT
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pi-unipi/info-screen — Extension entry
|
|
3
|
+
*
|
|
4
|
+
* Cache-first reactive dashboard.
|
|
5
|
+
* Opens immediately with cached data, updates in background.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* /unipi:info - Show info dashboard
|
|
9
|
+
* /unipi:info-settings - Configure info display
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
|
13
|
+
import { UNIPI_EVENTS, MODULES, UNIPI_PREFIX, emitEvent, getPackageVersion } from "@pi-unipi/core";
|
|
14
|
+
import { infoRegistry } from "./registry.js";
|
|
15
|
+
import { registerCoreGroups, trackModule, trackTool, setPiApi, registerSkillDir, startLoadTracking, recordLoadTime, finishLoadTracking, recordModuleStart } from "./core-groups.js";
|
|
16
|
+
|
|
17
|
+
/** Re-export for external use */
|
|
18
|
+
export { infoRegistry, registerSkillDir, startLoadTracking, recordLoadTime, finishLoadTracking, recordModuleStart };
|
|
19
|
+
import { getInfoSettings } from "./config.js";
|
|
20
|
+
import { InfoOverlay } from "./tui/info-overlay.js";
|
|
21
|
+
import { SettingsOverlay } from "./settings/settings-tui.js";
|
|
22
|
+
|
|
23
|
+
/** Package version */
|
|
24
|
+
const VERSION = getPackageVersion(new URL(".", import.meta.url).pathname);
|
|
25
|
+
|
|
26
|
+
export default function (pi: ExtensionAPI) {
|
|
27
|
+
setPiApi(pi);
|
|
28
|
+
|
|
29
|
+
// Register core groups immediately (synchronous)
|
|
30
|
+
registerCoreGroups();
|
|
31
|
+
|
|
32
|
+
// Start load tracking
|
|
33
|
+
startLoadTracking();
|
|
34
|
+
|
|
35
|
+
// Listen for module announcements — track and trigger reactive updates
|
|
36
|
+
pi.events.on(UNIPI_EVENTS.MODULE_READY, (event: any) => {
|
|
37
|
+
if (event.name && event.name !== MODULES.INFO_SCREEN) {
|
|
38
|
+
trackModule(event.name, event.version || "unknown");
|
|
39
|
+
recordLoadTime(event.name, "module", event.loadTimeMs);
|
|
40
|
+
|
|
41
|
+
// Invalidate overview so next fetch picks up new module list
|
|
42
|
+
infoRegistry.invalidateCache("overview");
|
|
43
|
+
|
|
44
|
+
// Trigger background refresh of overview — subscribers will re-render
|
|
45
|
+
infoRegistry.getGroupData("overview");
|
|
46
|
+
|
|
47
|
+
if (event.tools && Array.isArray(event.tools)) {
|
|
48
|
+
for (const tool of event.tools) {
|
|
49
|
+
trackTool(tool, event.name);
|
|
50
|
+
}
|
|
51
|
+
// Refresh tools group too
|
|
52
|
+
infoRegistry.invalidateCache("tools");
|
|
53
|
+
infoRegistry.getGroupData("tools");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
pi.events.on(UNIPI_EVENTS.INFO_GROUP_REGISTERED, (_event: any) => {
|
|
59
|
+
// Group already registered via globalThis in registerGroup()
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Track built-in tools
|
|
63
|
+
const trackedBuiltinTools = new Set<string>();
|
|
64
|
+
pi.on("tool_call", async (event, _ctx) => {
|
|
65
|
+
const toolName = event.toolName;
|
|
66
|
+
if (!trackedBuiltinTools.has(toolName)) {
|
|
67
|
+
trackedBuiltinTools.add(toolName);
|
|
68
|
+
trackTool(toolName, "builtin");
|
|
69
|
+
}
|
|
70
|
+
return undefined;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Show the info overlay immediately.
|
|
75
|
+
* Cache-first: opens with whatever data is cached (even empty).
|
|
76
|
+
* Background: each group fetches independently, overlay re-renders reactively.
|
|
77
|
+
*/
|
|
78
|
+
function showOverlay(ctx: any): void {
|
|
79
|
+
ctx.ui.custom(
|
|
80
|
+
(tui: any, theme: any, _keybindings: any, done: () => void) => {
|
|
81
|
+
const overlay = new InfoOverlay();
|
|
82
|
+
overlay.setTheme(theme);
|
|
83
|
+
overlay.onClose = () => {
|
|
84
|
+
overlay.destroy();
|
|
85
|
+
done();
|
|
86
|
+
};
|
|
87
|
+
overlay.requestRender = () => tui.requestRender();
|
|
88
|
+
return {
|
|
89
|
+
render: (w: number) => overlay.render(w),
|
|
90
|
+
invalidate: () => overlay.invalidate(),
|
|
91
|
+
handleInput: (data: string) => {
|
|
92
|
+
overlay.handleInput(data);
|
|
93
|
+
tui.requestRender();
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
overlay: true,
|
|
99
|
+
overlayOptions: {
|
|
100
|
+
width: "80%",
|
|
101
|
+
minWidth: 60,
|
|
102
|
+
anchor: "center",
|
|
103
|
+
margin: 2,
|
|
104
|
+
},
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Session lifecycle — show immediately on boot, no blocking wait
|
|
110
|
+
pi.on("session_start", async (event, ctx) => {
|
|
111
|
+
const settings = getInfoSettings();
|
|
112
|
+
|
|
113
|
+
if (settings.showOnBoot && event.reason === "startup") {
|
|
114
|
+
// Open immediately — cache-first, no waiting
|
|
115
|
+
showOverlay(ctx);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
finishLoadTracking();
|
|
119
|
+
|
|
120
|
+
emitEvent(pi, UNIPI_EVENTS.MODULE_READY, {
|
|
121
|
+
name: MODULES.INFO_SCREEN,
|
|
122
|
+
version: VERSION,
|
|
123
|
+
commands: ["unipi:info", "unipi:info-settings"],
|
|
124
|
+
tools: [],
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// /unipi:info — open immediately
|
|
129
|
+
pi.registerCommand(`${UNIPI_PREFIX}info`, {
|
|
130
|
+
description: "Show info screen dashboard",
|
|
131
|
+
handler: async (_args, ctx) => {
|
|
132
|
+
showOverlay(ctx);
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// /unipi:info-settings
|
|
137
|
+
pi.registerCommand(`${UNIPI_PREFIX}info-settings`, {
|
|
138
|
+
description: "Configure info screen display",
|
|
139
|
+
handler: async (_args, ctx) => {
|
|
140
|
+
ctx.ui.custom(
|
|
141
|
+
(tui: any, _theme: any, _keybindings: any, done: any) => {
|
|
142
|
+
const overlay = new SettingsOverlay();
|
|
143
|
+
overlay.onClose = () => done(undefined);
|
|
144
|
+
return {
|
|
145
|
+
render: (w: number) => overlay.render(w),
|
|
146
|
+
invalidate: () => overlay.invalidate(),
|
|
147
|
+
handleInput: (data: string) => {
|
|
148
|
+
overlay.handleInput?.(data);
|
|
149
|
+
tui.requestRender();
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
overlay: true,
|
|
155
|
+
overlayOptions: {
|
|
156
|
+
width: "60%",
|
|
157
|
+
minWidth: 50,
|
|
158
|
+
anchor: "center",
|
|
159
|
+
margin: 2,
|
|
160
|
+
},
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
},
|
|
164
|
+
});
|
|
165
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# @pi-unipi/memory
|
|
2
|
+
|
|
3
|
+
Persistent cross-session memory with vector search for Pi coding agent.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Two-tier storage:** SQLite + sqlite-vec for vector search, markdown files for human-readable memory
|
|
8
|
+
- **Project-scoped + global memory:** Each project gets its own DB, global memories accessible cross-project
|
|
9
|
+
- **Hybrid search:** Vector similarity + fuzzy text matching for best recall
|
|
10
|
+
- **Session injection:** Agent sees memory titles at session start
|
|
11
|
+
- **Auto-consolidation:** Memories extracted during compaction
|
|
12
|
+
- **Update-first:** Prevents memory duplication
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# All-in-one (includes memory)
|
|
18
|
+
pi install npm:unipi
|
|
19
|
+
|
|
20
|
+
# Standalone
|
|
21
|
+
pi install npm:@pi-unipi/memory
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Tools
|
|
25
|
+
|
|
26
|
+
| Tool | Description |
|
|
27
|
+
|------|-------------|
|
|
28
|
+
| `memory_store` | Store/update memory (project scope) |
|
|
29
|
+
| `memory_search` | Search memories (project scope) |
|
|
30
|
+
| `memory_delete` | Delete memory by ID or title |
|
|
31
|
+
| `memory_list` | List all project memories |
|
|
32
|
+
| `global_memory_store` | Store/update memory (global scope) |
|
|
33
|
+
| `global_memory_search` | Search global memories |
|
|
34
|
+
| `global_memory_list` | List all global memories |
|
|
35
|
+
|
|
36
|
+
## Commands
|
|
37
|
+
|
|
38
|
+
| Command | Description |
|
|
39
|
+
|---------|-------------|
|
|
40
|
+
| `/unipi:memory-process <text>` | Analyze text and store extracted memories |
|
|
41
|
+
| `/unipi:memory-search <term>` | Search project memories |
|
|
42
|
+
| `/unipi:memory-consolidate` | Consolidate session into memory |
|
|
43
|
+
| `/unipi:memory-forget <title>` | Delete a memory by title |
|
|
44
|
+
| `/unipi:global-memory-process <text>` | Analyze text and store to global |
|
|
45
|
+
| `/unipi:global-memory-search <term>` | Search global memories |
|
|
46
|
+
| `/unipi:global-memory-list` | List all global memories |
|
|
47
|
+
|
|
48
|
+
## Memory File Format
|
|
49
|
+
|
|
50
|
+
Memories are stored as markdown with YAML frontmatter:
|
|
51
|
+
|
|
52
|
+
```markdown
|
|
53
|
+
---
|
|
54
|
+
title: auth_jwt_prefer_refresh_tokens
|
|
55
|
+
tags: [auth, jwt, preferences]
|
|
56
|
+
project: my-app
|
|
57
|
+
created: 2026-04-26T10:00:00Z
|
|
58
|
+
updated: 2026-04-26T15:30:00Z
|
|
59
|
+
type: preference
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
# Auth: Prefer Refresh Tokens
|
|
63
|
+
|
|
64
|
+
User prefers short-lived access tokens (15min) with long-lived refresh tokens (30d).
|
|
65
|
+
Always implement token rotation on refresh.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Naming Convention
|
|
69
|
+
|
|
70
|
+
**Format:** `<most_important>_<less_important>_<lesser>`
|
|
71
|
+
|
|
72
|
+
Examples:
|
|
73
|
+
- `auth_jwt_prefer_refresh_tokens`
|
|
74
|
+
- `db_postgres_use_connection_pooling`
|
|
75
|
+
- `style_typescript_strict_mode_always`
|
|
76
|
+
|
|
77
|
+
## Storage Layout
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
~/.unipi/memory/
|
|
81
|
+
├── global/
|
|
82
|
+
│ ├── memory.db # Global vector DB
|
|
83
|
+
│ └── *.md # Global memory files
|
|
84
|
+
└── <project_name>/
|
|
85
|
+
├── memory.db # Project vector DB
|
|
86
|
+
└── *.md # Project memory files
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Dependencies
|
|
90
|
+
|
|
91
|
+
- `better-sqlite3` - SQLite database
|
|
92
|
+
- `sqlite-vec` - Vector search extension
|
|
93
|
+
- `js-yaml` - YAML frontmatter parsing
|
|
94
|
+
- `@pi-unipi/core` - Shared utilities
|