@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.
Files changed (31) hide show
  1. package/README.md +143 -0
  2. package/package.json +70 -0
  3. package/packages/btw/README.md +95 -0
  4. package/packages/btw/extensions/btw.ts +1972 -0
  5. package/packages/btw/skills/btw/SKILL.md +149 -0
  6. package/packages/core/README.md +74 -0
  7. package/packages/core/index.ts +10 -0
  8. package/packages/info-screen/README.md +115 -0
  9. package/packages/info-screen/index.ts +165 -0
  10. package/packages/memory/README.md +94 -0
  11. package/packages/memory/index.ts +209 -0
  12. package/packages/memory/skills/memory/SKILL.md +151 -0
  13. package/packages/ralph/README.md +101 -0
  14. package/packages/ralph/index.ts +548 -0
  15. package/packages/subagents/README.md +114 -0
  16. package/packages/unipi/index.ts +28 -0
  17. package/packages/workflow/README.md +129 -0
  18. package/packages/workflow/index.ts +155 -0
  19. package/packages/workflow/skills/brainstorm/SKILL.md +202 -0
  20. package/packages/workflow/skills/consolidate/SKILL.md +142 -0
  21. package/packages/workflow/skills/consultant/SKILL.md +97 -0
  22. package/packages/workflow/skills/document/SKILL.md +120 -0
  23. package/packages/workflow/skills/gather-context/SKILL.md +122 -0
  24. package/packages/workflow/skills/plan/SKILL.md +169 -0
  25. package/packages/workflow/skills/quick-work/SKILL.md +110 -0
  26. package/packages/workflow/skills/review-work/SKILL.md +131 -0
  27. package/packages/workflow/skills/scan-issues/SKILL.md +183 -0
  28. package/packages/workflow/skills/work/SKILL.md +144 -0
  29. package/packages/workflow/skills/worktree-create/SKILL.md +69 -0
  30. package/packages/workflow/skills/worktree-list/SKILL.md +67 -0
  31. 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,10 @@
1
+ /**
2
+ * @unipi/core — Shared utilities for Unipi extension suite
3
+ *
4
+ * Re-exports all constants, events, and utilities.
5
+ */
6
+
7
+ export * from "./constants.js";
8
+ export * from "./events.js";
9
+ export * from "./sandbox.js";
10
+ export * from "./utils.js";
@@ -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