@pi-unipi/unipi 3.0.0-alpha.4 → 3.0.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +1 -4
- package/package.json +21 -23
- package/packages/ask-user/package.json +2 -2
- package/packages/autocomplete/package.json +1 -1
- package/packages/autocomplete/src/constants.ts +15 -13
- package/packages/autocomplete/src/sorting.ts +8 -0
- package/packages/background-tasks/package.json +2 -2
- package/packages/btw/package.json +2 -2
- package/packages/compactor/package.json +3 -3
- package/packages/core/constants.ts +4 -23
- package/packages/core/events.ts +0 -53
- package/packages/core/index.ts +2 -0
- package/packages/core/model-cache.ts +81 -7
- package/packages/core/package.json +2 -2
- package/packages/core/src/jev/chatter.ts +24 -0
- package/packages/core/src/package-colors.ts +2 -0
- package/packages/core/src/settings/catalog.ts +39 -15
- package/packages/core/src/settings/hub.ts +44 -10
- package/packages/core/src/settings/open.ts +49 -0
- package/packages/core/src/settings/schema.ts +8 -4
- package/packages/footer/package.json +3 -3
- package/packages/fusion/package.json +3 -3
- package/packages/fusion/src/picker.ts +36 -12
- package/packages/info-screen/package.json +2 -2
- package/packages/input-shortcuts/package.json +2 -2
- package/packages/kanboard/package.json +7 -7
- package/packages/long-horizon/package.json +2 -2
- package/packages/mcp/package.json +2 -2
- package/packages/memory/package.json +3 -3
- package/packages/notify/package.json +2 -2
- package/packages/skill-registry/README.md +55 -16
- package/packages/skill-registry/index.ts +223 -0
- package/packages/skill-registry/package.json +20 -4
- package/packages/skill-registry/src/editor.ts +208 -0
- package/packages/skill-registry/src/judge.ts +293 -0
- package/packages/skill-registry/src/registry.ts +98 -0
- package/packages/skill-registry/src/settings.ts +258 -0
- package/packages/skill-registry/src/vault.ts +80 -0
- package/packages/subagents/README.md +0 -1
- package/packages/subagents/package.json +2 -2
- package/packages/subagents/src/index.ts +0 -6
- package/packages/unipi/bundled.js +20556 -20048
- package/packages/unipi/index.ts +2 -7
- package/packages/updater/package.json +2 -2
- package/packages/utility/README.md +67 -69
- package/packages/utility/package.json +2 -2
- package/packages/utility/skills/image/SKILL.md +37 -0
- package/packages/utility/skills/utility/SKILL.md +17 -60
- package/packages/utility/src/answer/extract.ts +128 -0
- package/packages/utility/src/answer/index.ts +213 -0
- package/packages/utility/src/answer/reply.ts +133 -0
- package/packages/utility/src/answer/web.ts +167 -0
- package/packages/utility/src/attach/detect.ts +163 -0
- package/packages/utility/src/attach/index.ts +184 -0
- package/packages/utility/src/commands.ts +38 -147
- package/packages/utility/src/diagnostics/engine.ts +50 -5
- package/packages/utility/src/image/index.ts +33 -0
- package/packages/utility/src/image/models.ts +221 -0
- package/packages/{image/src → utility/src/image}/recognize.ts +2 -2
- package/packages/utility/src/image/settings.ts +178 -0
- package/packages/{image/src/image-source.ts → utility/src/image/source.ts} +1 -1
- package/packages/utility/src/image/tools.ts +168 -0
- package/packages/utility/src/image/transports.ts +186 -0
- package/packages/utility/src/index.ts +47 -389
- package/packages/utility/src/lifecycle/cleanup.ts +116 -311
- package/packages/utility/src/rename/gate.ts +102 -0
- package/packages/utility/src/rename/index.ts +191 -0
- package/packages/utility/src/rename/session.ts +170 -0
- package/packages/utility/src/render/parse.ts +156 -0
- package/packages/utility/src/render/pi-settings.ts +38 -0
- package/packages/utility/src/render/tools.ts +316 -0
- package/packages/utility/src/settings.ts +163 -231
- package/packages/utility/src/types.ts +1 -222
- package/packages/watchdog/index.ts +0 -1
- package/packages/watchdog/package.json +3 -3
- package/packages/web-api/package.json +2 -2
- package/packages/workflow/package.json +2 -2
- package/packages/workflow/src/permission/decide.ts +1 -1
- package/packages/image/README.md +0 -99
- package/packages/image/package.json +0 -61
- package/packages/image/skills/image/SKILL.md +0 -76
- package/packages/image/src/generate.ts +0 -256
- package/packages/image/src/index.ts +0 -135
- package/packages/image/src/models.ts +0 -519
- package/packages/image/src/openai-images-api.ts +0 -282
- package/packages/image/src/register-providers.ts +0 -209
- package/packages/image/src/settings.ts +0 -173
- package/packages/image/src/tools.ts +0 -326
- package/packages/subagents/src/badge-session.ts +0 -46
- package/packages/subagents/src/badge.ts +0 -43
- package/packages/utility/src/analytics/collector.ts +0 -293
- package/packages/utility/src/info-screen.ts +0 -80
- package/packages/utility/src/lifecycle/process.ts +0 -162
- package/packages/utility/src/prefix-cache.ts +0 -263
- package/packages/utility/src/skill-discovery.ts +0 -542
- package/packages/utility/src/tools/env.ts +0 -113
- package/packages/utility/src/tui/name-badge-state.ts +0 -315
- package/packages/utility/src/tui/name-badge.ts +0 -109
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,37 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [3.0.0-alpha.5] — 2026-09-28
|
|
10
|
+
|
|
11
|
+
### Breaking Changes
|
|
12
|
+
|
|
13
|
+
- **BREAKING: `@pi-unipi/image` removed.** Image generation, editing and recognition now live in `@pi-unipi/utility` (same `image` settings namespace, so existing configs keep working). **Migration path:** nothing to do with the umbrella package; if you installed `@pi-unipi/image` on its own, remove it and use `@pi-unipi/utility`.
|
|
14
|
+
- **BREAKING: utility slimmed.** Removed `/unipi:reload` (use pi's `/reload`), `/unipi:status`, `/unipi:env`, `/unipi:prefix-cache`, the agent tools `ctx_env` and `set_session_name`, the top name-badge bar, the analytics collector and the process-lifecycle signal handlers. **Migration path:** `/unipi:doctor` covers the health checks; sessions are named automatically (below) or with pi's `/name`. Old `badge.*` settings carry over to `rename.*`.
|
|
15
|
+
- **BREAKING: skill exposure moved** from `utility.skills` to the new `skills` namespace (`@pi-unipi/skill-registry`). Migrated automatically on first read.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- `utility`: `/unipi:retry`, an alias of `/unipi:continue`.
|
|
20
|
+
- `utility`: **automatic session naming.** After each round, jev checks whether the round (your message plus what the agent did) established a subject and, for a named session, whether it moved to a different task; a throwaway session with a single `rename_session` tool writes the name. Greetings never rename; names set with `/name` are never overwritten; Herdr pane/tab sync kept.
|
|
21
|
+
- `utility`: **`/unipi:answer`** — answer the last reply without scrolling: `reply` (default: the reply scrolls above a fixed input box, like `/unipi:btw`), `questions` (one answer per question, Q/A template) or `web` (local form; over SSH it prints the `ssh -L` forward). A hint above the editor says when a reply asks questions.
|
|
22
|
+
- `utility`: **pasted images and files** become `[Image #N]` / `[File #N]` attachments with a chip row above the editor and inline previews in Kitty, Ghostty, iTerm2 and WezTerm; images are sent to the model as images.
|
|
23
|
+
- `utility`: **image tools** `image_generate`, `image_edit` (new) and `image_recognize`, with OpenRouter, fal and custom-endpoint routes, a key per provider, and model pickers filtered by input/output modality. Default model FLUX.2 [klein] 4B.
|
|
24
|
+
- `utility`: **response formatting** — Settings → Utility → Response formatting: `simple` (one line per tool), `regular` (pi's own) or `advanced` (highlighted commands incl. embedded heredoc/`-c` code, tinted syntax-highlighted diffs, test summaries, exit lines).
|
|
25
|
+
- `utility`: `/unipi:settings <search>` opens the hub filtered; typing `/settings` lists `/unipi:settings` first.
|
|
26
|
+
- `skill-registry`: now a real extension. **Skill settings…** grid (`/unipi:skills` → Skill settings…): per skill Enabled / Discoverable / Must show, per global or project scope, plus a skill vault at `~/.unipi/skill-vault` whose skills stay off until a scope turns them on (skill proxy, off by default).
|
|
27
|
+
- `core`: the shared model cache (`~/.unipi/config/models-cache.json`) records input/output modalities; the settings hub pickers and kanboard read it.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- `skill-registry`: skill judging keeps skills named in the request, lists hidden skills by name in the system prompt, waits for the first real request instead of freezing on a greeting, and caps generic workflow skills.
|
|
32
|
+
- `fusion`: `/unipi:model` lists only your preset lead/sidekick models; typing searches the whole catalogue (also inside the lead/sidekick dropdowns).
|
|
33
|
+
- `utility`: `/unipi:cleanup` only removes files on an explicit list, previews them and asks first; v2 memory backups can never be removed. `/unipi:doctor` checks the model cache, the Decision Model key and skill exposure.
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- `image`: generation failed for most users (only a pi-ai OpenRouter route with a key pi often couldn't see) and failures were reported to the agent as successes.
|
|
38
|
+
- `core`: capability-filtered model pickers hide entries with no declared input again.
|
|
39
|
+
|
|
9
40
|
## [3.0.0-alpha.4] — 2026-09-28
|
|
10
41
|
|
|
11
42
|
### Breaking Changes
|
package/README.md
CHANGED
|
@@ -33,7 +33,6 @@ pi install npm:@pi-unipi/unipi
|
|
|
33
33
|
|
|
34
34
|
**[Web API](./packages/web-api/README.md)** — Web search, page reading, content summarization. Defaults to [wigolo](https://github.com/KnockOutEZ/wigolo), a local-first engine with multi-engine search and on-device reranking — $0/query, no API key. Plus a smart-fetch engine with browser-grade TLS fingerprinting. Paid providers as fallbacks, and auto-selection falls through when a provider is unavailable.
|
|
35
35
|
|
|
36
|
-
**[Image](./packages/image/README.md)** — Generate images from a text prompt and analyze existing ones. 34 image models, plus vision analysis on any model that accepts image input, with a customizable system prompt.
|
|
37
36
|
|
|
38
37
|
**[MCP](./packages/mcp/README.md)** — Browse 7,800+ MCP servers, add them interactively. Tools from servers register automatically as Pi tools.
|
|
39
38
|
|
|
@@ -116,14 +115,12 @@ Coexists triggers enhance behavior when packages are installed together. Workflo
|
|
|
116
115
|
| `spawn_helper` / `get_helper_result` | subagents | Parallel agents |
|
|
117
116
|
| `memory_store` / `memory_search` / `memory_delete` | memory | Memory CRUD |
|
|
118
117
|
| `web_search` / `multi_web_content_read` / `web_llm_summarize` | web-api | Web research |
|
|
119
|
-
| `image_generate` / `image_recognize` |
|
|
118
|
+
| `image_generate` / `image_edit` / `image_recognize` | utility | Image generation, editing and vision (recognize hides while the session model has vision) |
|
|
120
119
|
| `notify_user` | notify | Push notifications |
|
|
121
120
|
| `sidekick` / `read_subagent` | fusion | Delegate to the persistent sidekick and collect its report |
|
|
122
121
|
| `bg_run` / `bg_status` / `bg_logs` / `bg_kill` / `bg_delegate` / `bg_result` | background-tasks | Long-running commands and background delegate agents |
|
|
123
122
|
| `ask_user` | ask-user | User input |
|
|
124
123
|
| `session_recall` / `context_budget` | compactor | Context management |
|
|
125
|
-
| `ctx_env` | utility | Environment info |
|
|
126
|
-
| `set_session_name` | utility | Session name for badge |
|
|
127
124
|
|
|
128
125
|
## Development
|
|
129
126
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/unipi",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.5",
|
|
4
4
|
"description": "All-in-one extension suite for Pi coding agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -70,7 +70,6 @@
|
|
|
70
70
|
"packages/notify/skills",
|
|
71
71
|
"packages/kanboard/skills",
|
|
72
72
|
"packages/updater/skills",
|
|
73
|
-
"packages/image/skills",
|
|
74
73
|
"packages/subagents/skills"
|
|
75
74
|
],
|
|
76
75
|
"prompts": [
|
|
@@ -84,27 +83,26 @@
|
|
|
84
83
|
"typebox": "^1.1.38"
|
|
85
84
|
},
|
|
86
85
|
"dependencies": {
|
|
87
|
-
"@pi-unipi/ask-user": "3.0.0-alpha.
|
|
88
|
-
"@pi-unipi/background-tasks": "3.0.0-alpha.
|
|
89
|
-
"@pi-unipi/btw": "3.0.0-alpha.
|
|
90
|
-
"@pi-unipi/command-enchantment": "3.0.0-alpha.
|
|
91
|
-
"@pi-unipi/compactor": "3.0.0-alpha.
|
|
92
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
93
|
-
"@pi-unipi/footer": "3.0.0-alpha.
|
|
94
|
-
"@pi-unipi/
|
|
95
|
-
"@pi-unipi/
|
|
96
|
-
"@pi-unipi/
|
|
97
|
-
"@pi-unipi/
|
|
98
|
-
"@pi-unipi/
|
|
99
|
-
"@pi-unipi/
|
|
100
|
-
"@pi-unipi/
|
|
101
|
-
"@pi-unipi/
|
|
102
|
-
"@pi-unipi/
|
|
103
|
-
"@pi-unipi/
|
|
104
|
-
"@pi-unipi/
|
|
105
|
-
"@pi-unipi/
|
|
106
|
-
"@pi-unipi/
|
|
107
|
-
"@pi-unipi/workflow": "3.0.0-alpha.4"
|
|
86
|
+
"@pi-unipi/ask-user": "3.0.0-alpha.5",
|
|
87
|
+
"@pi-unipi/background-tasks": "3.0.0-alpha.5",
|
|
88
|
+
"@pi-unipi/btw": "3.0.0-alpha.5",
|
|
89
|
+
"@pi-unipi/command-enchantment": "3.0.0-alpha.5",
|
|
90
|
+
"@pi-unipi/compactor": "3.0.0-alpha.5",
|
|
91
|
+
"@pi-unipi/core": "3.0.0-alpha.5",
|
|
92
|
+
"@pi-unipi/footer": "3.0.0-alpha.5",
|
|
93
|
+
"@pi-unipi/fusion": "3.0.0-alpha.5",
|
|
94
|
+
"@pi-unipi/info-screen": "3.0.0-alpha.5",
|
|
95
|
+
"@pi-unipi/input-shortcuts": "3.0.0-alpha.5",
|
|
96
|
+
"@pi-unipi/kanboard": "3.0.0-alpha.5",
|
|
97
|
+
"@pi-unipi/mcp": "3.0.0-alpha.5",
|
|
98
|
+
"@pi-unipi/memory": "3.0.0-alpha.5",
|
|
99
|
+
"@pi-unipi/notify": "3.0.0-alpha.5",
|
|
100
|
+
"@pi-unipi/skill-registry": "3.0.0-alpha.5",
|
|
101
|
+
"@pi-unipi/subagents": "3.0.0-alpha.5",
|
|
102
|
+
"@pi-unipi/updater": "3.0.0-alpha.5",
|
|
103
|
+
"@pi-unipi/utility": "3.0.0-alpha.5",
|
|
104
|
+
"@pi-unipi/web-api": "3.0.0-alpha.5",
|
|
105
|
+
"@pi-unipi/workflow": "3.0.0-alpha.5"
|
|
108
106
|
},
|
|
109
107
|
"devDependencies": {
|
|
110
108
|
"@earendil-works/pi-agent-core": "^0.87.1",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/ask-user",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.5",
|
|
4
4
|
"description": "Structured user input tool for Pi coding agent — single-select, multi-select, freeform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
43
|
+
"@pi-unipi/core": "3.0.0-alpha.5"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
46
|
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
@@ -19,6 +19,7 @@ export const PACKAGE_ORDER: string[] = [
|
|
|
19
19
|
"btw",
|
|
20
20
|
"mcp",
|
|
21
21
|
"utility",
|
|
22
|
+
"skill-registry",
|
|
22
23
|
"ask-user",
|
|
23
24
|
"info",
|
|
24
25
|
"web-api",
|
|
@@ -41,8 +42,6 @@ export const COMMAND_REGISTRY: Record<string, string> = {
|
|
|
41
42
|
"unipi:plan": "workflow",
|
|
42
43
|
"unipi:permission": "workflow",
|
|
43
44
|
|
|
44
|
-
"unipi:prefix-cache": "utility",
|
|
45
|
-
|
|
46
45
|
// long-horizon (4 commands)
|
|
47
46
|
"unipi:goal": "long-horizon",
|
|
48
47
|
"unipi:ralph": "long-horizon",
|
|
@@ -68,13 +67,15 @@ export const COMMAND_REGISTRY: Record<string, string> = {
|
|
|
68
67
|
// mcp (5 commands)
|
|
69
68
|
"unipi:mcp-status": "mcp",
|
|
70
69
|
|
|
71
|
-
// utility
|
|
70
|
+
// utility
|
|
72
71
|
"unipi:continue": "utility",
|
|
73
|
-
"unipi:
|
|
74
|
-
"unipi:status": "utility",
|
|
72
|
+
"unipi:retry": "utility",
|
|
75
73
|
"unipi:cleanup": "utility",
|
|
76
|
-
"unipi:env": "utility",
|
|
77
74
|
"unipi:doctor": "utility",
|
|
75
|
+
"unipi:answer": "utility",
|
|
76
|
+
|
|
77
|
+
// skill-registry
|
|
78
|
+
"unipi:skills": "skill-registry",
|
|
78
79
|
|
|
79
80
|
// ask-user (1 command)
|
|
80
81
|
|
|
@@ -134,7 +135,6 @@ export const COMMAND_REGISTRY: Record<string, string> = {
|
|
|
134
135
|
export const COMMAND_DESCRIPTIONS: Record<string, string> = {
|
|
135
136
|
"unipi:plan": "Plan mode — investigate read-only, then approve a plan",
|
|
136
137
|
"unipi:permission": "Permission mode — ask · auto (jev-judged) · full",
|
|
137
|
-
"unipi:prefix-cache": "Show privacy-safe provider prefix-cache diagnostics",
|
|
138
138
|
|
|
139
139
|
"unipi:goal": "One objective until verifiably true · medium complexity · pareto cost/success",
|
|
140
140
|
"unipi:ralph": "Checklist grind over iterations · enumerable chores · low cost, solid success",
|
|
@@ -156,12 +156,13 @@ export const COMMAND_DESCRIPTIONS: Record<string, string> = {
|
|
|
156
156
|
|
|
157
157
|
"unipi:mcp-status": "Show MCP server status",
|
|
158
158
|
|
|
159
|
-
"unipi:continue": "Continue the
|
|
160
|
-
"unipi:
|
|
161
|
-
"unipi:
|
|
162
|
-
"unipi:
|
|
163
|
-
"unipi:
|
|
164
|
-
"unipi:
|
|
159
|
+
"unipi:continue": "Continue from where the agent stopped (/unipi:retry)",
|
|
160
|
+
"unipi:retry": "Retry the last turn (alias of /unipi:continue)",
|
|
161
|
+
"unipi:cleanup": "Remove stale UniPi temp files and leftovers (preview first)",
|
|
162
|
+
"unipi:doctor": "Check UniPi's runtime: config, model cache, Decision Model, skills",
|
|
163
|
+
"unipi:answer": "Answer the last reply — fixed input under the scrollable reply, per question, or web form",
|
|
164
|
+
"unipi:skills": "Manage skills — on/off per project, listed or not, the skill vault",
|
|
165
|
+
|
|
165
166
|
"unipi:kanboard": "Kanboard — capture tasks, run them, open the board",
|
|
166
167
|
"unipi:kanboard-add": "Kanboard — capture a task into Backlog",
|
|
167
168
|
"unipi:kanboard-do": "Kanboard — let the agent work the board for a turn",
|
|
@@ -207,6 +208,7 @@ export const PACKAGE_LABELS: Record<string, string> = {
|
|
|
207
208
|
btw: "btw",
|
|
208
209
|
mcp: "mcp",
|
|
209
210
|
utility: "utility",
|
|
211
|
+
"skill-registry": "skills",
|
|
210
212
|
"ask-user": "ask-user",
|
|
211
213
|
info: "info",
|
|
212
214
|
"web-api": "web-api",
|
|
@@ -16,6 +16,12 @@ export interface TaggedItem {
|
|
|
16
16
|
|
|
17
17
|
// ─── 4-tier priority ─────────────────────────────────────────────────
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* UniPi commands that supersede a same-named pi built-in: typing the bare
|
|
21
|
+
* name ranks the unipi command FIRST (`/settings` → `/unipi:settings`).
|
|
22
|
+
*/
|
|
23
|
+
export const PREFERRED_OVER_BUILTIN = new Set(["settings"]);
|
|
24
|
+
|
|
19
25
|
/**
|
|
20
26
|
* Compute the match-quality tier for an autocomplete item.
|
|
21
27
|
*
|
|
@@ -38,6 +44,8 @@ export function crossItemPriority(
|
|
|
38
44
|
|
|
39
45
|
const q = query.toLowerCase();
|
|
40
46
|
|
|
47
|
+
// Tier -1: a unipi command that supersedes the same-named built-in
|
|
48
|
+
if (isUnipi && short === q && PREFERRED_OVER_BUILTIN.has(q)) return -1;
|
|
41
49
|
// Tier 0: exact full-value match
|
|
42
50
|
if (full === q) return 0;
|
|
43
51
|
// Tier 1: unipi short-name exact match
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/background-tasks",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.5",
|
|
4
4
|
"description": "Background tasks for UniPi — durable shell jobs and delegated background agents with a footer dock",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@earendil-works/pi-ai": "^0.87.1",
|
|
13
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
13
|
+
"@pi-unipi/core": "3.0.0-alpha.5",
|
|
14
14
|
"turndown": "^7.2.4"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/btw",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.5",
|
|
4
4
|
"description": "A pi extension for parallel side conversations with /unipi:btw — part of the Unipi suite",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "extensions/btw.ts",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@earendil-works/pi-tui": "^0.87.1"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
40
|
+
"@pi-unipi/core": "3.0.0-alpha.5"
|
|
41
41
|
},
|
|
42
42
|
"pi": {
|
|
43
43
|
"extensions": [
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/compactor",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.5",
|
|
4
4
|
"description": "Compaction for Pi — lossless zero-LLM or model summaries, rebuilt from full history, with session recall",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@pi-unipi/core": "3.0.0-alpha.
|
|
37
|
-
"@pi-unipi/info-screen": "3.0.0-alpha.
|
|
36
|
+
"@pi-unipi/core": "3.0.0-alpha.5",
|
|
37
|
+
"@pi-unipi/info-screen": "3.0.0-alpha.5",
|
|
38
38
|
"@earendil-works/pi-agent-core": "^0.87.1"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
@@ -37,8 +37,8 @@ export const MODULES = {
|
|
|
37
37
|
FOOTER: "@pi-unipi/footer",
|
|
38
38
|
UPDATER: "@pi-unipi/updater",
|
|
39
39
|
INPUT_SHORTCUTS: "@pi-unipi/input-shortcuts",
|
|
40
|
-
IMAGE: "@pi-unipi/image",
|
|
41
40
|
WATCHDOG: "@pi-unipi/watchdog",
|
|
41
|
+
SKILL_REGISTRY: "@pi-unipi/skill-registry",
|
|
42
42
|
} as const;
|
|
43
43
|
|
|
44
44
|
/** Workflow command names — plan mode + permission modes */
|
|
@@ -104,30 +104,10 @@ export const RALPH_STATUS_ICONS = {
|
|
|
104
104
|
/** Utility command names */
|
|
105
105
|
export const UTILITY_COMMANDS = {
|
|
106
106
|
CONTINUE: "continue",
|
|
107
|
-
|
|
108
|
-
STATUS: "status",
|
|
107
|
+
RETRY: "retry",
|
|
109
108
|
CLEANUP: "cleanup",
|
|
110
|
-
ENV: "env",
|
|
111
109
|
DOCTOR: "doctor",
|
|
112
|
-
|
|
113
|
-
} as const;
|
|
114
|
-
|
|
115
|
-
/** Utility tool names */
|
|
116
|
-
export const UTILITY_TOOLS = {
|
|
117
|
-
CONTINUE: "continue_task",
|
|
118
|
-
BATCH: "ctx_batch",
|
|
119
|
-
ENV: "ctx_env",
|
|
120
|
-
SET_SESSION_NAME: "set_session_name",
|
|
121
|
-
} as const;
|
|
122
|
-
|
|
123
|
-
/** Badge config path */
|
|
124
|
-
export const BADGE_CONFIG_FILE = ".unipi/config/badge.json" as const;
|
|
125
|
-
|
|
126
|
-
/** Utility directory paths */
|
|
127
|
-
export const UTILITY_DIRS = {
|
|
128
|
-
CACHE: "~/.unipi/cache",
|
|
129
|
-
ANALYTICS: "~/.unipi/analytics",
|
|
130
|
-
TEMP: "/tmp/unipi",
|
|
110
|
+
ANSWER: "answer",
|
|
131
111
|
} as const;
|
|
132
112
|
|
|
133
113
|
/** Ask-user tool names */
|
|
@@ -138,6 +118,7 @@ export const ASK_USER_TOOLS = {
|
|
|
138
118
|
/** Image tool names */
|
|
139
119
|
export const IMAGE_TOOLS = {
|
|
140
120
|
GENERATE: "image_generate",
|
|
121
|
+
EDIT: "image_edit",
|
|
141
122
|
RECOGNIZE: "image_recognize",
|
|
142
123
|
} as const;
|
|
143
124
|
|
package/packages/core/events.ts
CHANGED
|
@@ -35,8 +35,6 @@ export const UNIPI_EVENTS = {
|
|
|
35
35
|
LONG_HORIZON_TODO_UPDATED: "unipi:long-horizon:todo:updated",
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
/** Info screen group registered */
|
|
39
|
-
INFO_GROUP_REGISTERED: "unipi:info:group:registered",
|
|
40
38
|
/** Info screen data updated */
|
|
41
39
|
INFO_DATA_UPDATED: "unipi:info:data:updated",
|
|
42
40
|
|
|
@@ -64,19 +62,10 @@ export const UNIPI_EVENTS = {
|
|
|
64
62
|
COMPACTOR_COMPACTED: "unipi:compactor:compacted",
|
|
65
63
|
/** @deprecated Footer reads live Pi session data; retained for compatibility. */
|
|
66
64
|
COMPACTOR_STATS_UPDATED: "unipi:compactor:stats:updated",
|
|
67
|
-
/** Utility module cleanup completed */
|
|
68
|
-
UTILITY_CLEANUP_DONE: "unipi:utility:cleanup:done",
|
|
69
|
-
/** Utility diagnostics started */
|
|
70
|
-
UTILITY_DIAGNOSTICS_START: "unipi:utility:diagnostics:start",
|
|
71
|
-
/** Utility diagnostics completed */
|
|
72
|
-
UTILITY_DIAGNOSTICS_DONE: "unipi:utility:diagnostics:done",
|
|
73
65
|
|
|
74
66
|
/** Notification sent */
|
|
75
67
|
NOTIFICATION_SENT: "unipi:notify:sent",
|
|
76
68
|
|
|
77
|
-
/** Badge generation requested (from kanboard or other module) */
|
|
78
|
-
BADGE_GENERATE_REQUEST: "unipi:badge:generate:request",
|
|
79
|
-
|
|
80
69
|
/** Agent asked user a question (ask_user tool invoked) */
|
|
81
70
|
ASK_USER_PROMPT: "unipi:ask-user:prompt",
|
|
82
71
|
|
|
@@ -178,15 +167,6 @@ export interface UnipiMemoryConsolidatedEvent {
|
|
|
178
167
|
projectName: string;
|
|
179
168
|
}
|
|
180
169
|
|
|
181
|
-
/** Payload for INFO_GROUP_REGISTERED */
|
|
182
|
-
export interface UnipiInfoGroupEvent {
|
|
183
|
-
/** Group id */
|
|
184
|
-
groupId: string;
|
|
185
|
-
/** Group display name */
|
|
186
|
-
groupName: string;
|
|
187
|
-
/** Module that registered the group */
|
|
188
|
-
module: string;
|
|
189
|
-
}
|
|
190
170
|
|
|
191
171
|
/** Payload for INFO_DATA_UPDATED */
|
|
192
172
|
export interface UnipiInfoDataEvent {
|
|
@@ -252,38 +232,9 @@ export interface UnipiCompactorStatsEvent {
|
|
|
252
232
|
searchQueries: number;
|
|
253
233
|
}
|
|
254
234
|
|
|
255
|
-
/** Payload for UTILITY_CLEANUP_START / UTILITY_CLEANUP_DONE */
|
|
256
|
-
export interface UnipiUtilityCleanupEvent {
|
|
257
|
-
/** Whether this is a dry run */
|
|
258
|
-
dryRun: boolean;
|
|
259
|
-
/** Categories being cleaned */
|
|
260
|
-
categories: string[];
|
|
261
|
-
/** Results (present on DONE) */
|
|
262
|
-
results?: Array<{
|
|
263
|
-
category: string;
|
|
264
|
-
removed: number;
|
|
265
|
-
bytesFreed: number;
|
|
266
|
-
}>;
|
|
267
|
-
}
|
|
268
235
|
|
|
269
|
-
/** Payload for UTILITY_DIAGNOSTICS_START / UTILITY_DIAGNOSTICS_DONE */
|
|
270
|
-
export interface UnipiUtilityDiagnosticsEvent {
|
|
271
|
-
/** Overall health status */
|
|
272
|
-
overall: "healthy" | "warning" | "error" | "unknown";
|
|
273
|
-
/** Number of checks run */
|
|
274
|
-
checkCount: number;
|
|
275
|
-
/** Report (present on DONE) */
|
|
276
|
-
report?: unknown;
|
|
277
|
-
}
|
|
278
236
|
|
|
279
237
|
|
|
280
|
-
/** Payload for BADGE_GENERATE_REQUEST */
|
|
281
|
-
export interface UnipiBadgeGenerateRequestEvent {
|
|
282
|
-
/** Source of the request (e.g., "kanboard", "input-hook") */
|
|
283
|
-
source: string;
|
|
284
|
-
/** First user message for context (optional) */
|
|
285
|
-
conversationSummary?: string;
|
|
286
|
-
}
|
|
287
238
|
|
|
288
239
|
/** Payload for ASK_USER_PROMPT */
|
|
289
240
|
export interface UnipiAskUserPromptEvent {
|
|
@@ -361,17 +312,13 @@ export type UnipiEventPayload =
|
|
|
361
312
|
| UnipiMemoryStoredEvent
|
|
362
313
|
| UnipiMemoryDeletedEvent
|
|
363
314
|
| UnipiMemoryConsolidatedEvent
|
|
364
|
-
| UnipiInfoGroupEvent
|
|
365
315
|
| UnipiInfoDataEvent
|
|
366
316
|
| UnipiMcpServerEvent
|
|
367
317
|
| UnipiMcpToolsEvent
|
|
368
318
|
| UnipiMcpCatalogSyncedEvent
|
|
369
319
|
| UnipiCompactionEvent
|
|
370
320
|
| UnipiCompactorStatsEvent
|
|
371
|
-
| UnipiUtilityCleanupEvent
|
|
372
|
-
| UnipiUtilityDiagnosticsEvent
|
|
373
321
|
| UnipiNotificationSentEvent
|
|
374
|
-
| UnipiBadgeGenerateRequestEvent
|
|
375
322
|
| UnipiAskUserPromptEvent
|
|
376
323
|
| UnipiUpdateCheckEvent
|
|
377
324
|
| UnipiUpdateAvailableEvent
|
package/packages/core/index.ts
CHANGED
|
@@ -26,12 +26,14 @@ export * from "./src/tui/kit.js";
|
|
|
26
26
|
export * from "./src/tui/progress.js";
|
|
27
27
|
export * from "./src/jev/client.js";
|
|
28
28
|
export * from "./src/jev/settings.js";
|
|
29
|
+
export * from "./src/jev/chatter.js";
|
|
29
30
|
export * from "./src/workspace/state-migration.js";
|
|
30
31
|
// v3 settings engine + migration (canonical ~/.unipi/config layout)
|
|
31
32
|
export * from "./src/settings/paths.js";
|
|
32
33
|
export * from "./src/settings/engine.js";
|
|
33
34
|
export * from "./src/settings/schema.js";
|
|
34
35
|
export { SettingsHub, type SettingsHubDeps } from "./src/settings/hub.js";
|
|
36
|
+
export { openSettingsHub } from "./src/settings/open.js";
|
|
35
37
|
export * from "./src/settings/catalog.js";
|
|
36
38
|
export * from "./command-runner.js";
|
|
37
39
|
export * from "./compaction-context.js";
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @pi-unipi/core — Model Cache
|
|
3
3
|
*
|
|
4
|
-
* File-based model list cache at ~/.unipi/config/models-cache.json
|
|
5
|
-
*
|
|
6
|
-
* without needing ctx.modelRegistry
|
|
4
|
+
* File-based model list cache at ~/.unipi/config/models-cache.json — the one
|
|
5
|
+
* catalog every unipi surface reads (settings hub pickers, kanboard, image
|
|
6
|
+
* pickers) without needing ctx.modelRegistry. Written by utility on every
|
|
7
|
+
* session start from pi's live registry (models with credentials), plus the
|
|
8
|
+
* image-generation models pi-ai publishes separately.
|
|
7
9
|
*/
|
|
8
10
|
|
|
9
11
|
import * as fs from "node:fs";
|
|
@@ -18,10 +20,12 @@ function cacheDir(): string {
|
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
/** Resolve the model cache file path at call time. */
|
|
21
|
-
function
|
|
23
|
+
export function modelCachePath(): string {
|
|
22
24
|
return path.join(cacheDir(), "models-cache.json");
|
|
23
25
|
}
|
|
24
26
|
|
|
27
|
+
export type Modality = "text" | "image";
|
|
28
|
+
|
|
25
29
|
/** A single cached model entry */
|
|
26
30
|
export interface CachedModel {
|
|
27
31
|
/** Model provider (e.g. "openai", "anthropic") */
|
|
@@ -30,6 +34,14 @@ export interface CachedModel {
|
|
|
30
34
|
id: string;
|
|
31
35
|
/** Optional display name */
|
|
32
36
|
name?: string;
|
|
37
|
+
/** Input modalities. Absent in pre-v3 caches → treat as ["text"]. */
|
|
38
|
+
input?: Modality[];
|
|
39
|
+
/** Output modalities. Chat models → ["text"]; image generators include "image". */
|
|
40
|
+
output?: Modality[];
|
|
41
|
+
/** "chat" = pi chat registry, "images" = pi-ai images collection / generator. */
|
|
42
|
+
kind?: "chat" | "images";
|
|
43
|
+
contextWindow?: number;
|
|
44
|
+
reasoning?: boolean;
|
|
33
45
|
}
|
|
34
46
|
|
|
35
47
|
/** The full model cache structure */
|
|
@@ -40,13 +52,64 @@ export interface ModelCache {
|
|
|
40
52
|
models: CachedModel[];
|
|
41
53
|
}
|
|
42
54
|
|
|
55
|
+
/** `provider/id` reference for a cached model. */
|
|
56
|
+
export function modelRef(model: Pick<CachedModel, "provider" | "id">): string {
|
|
57
|
+
return `${model.provider}/${model.id}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function modelInputs(model: CachedModel): Modality[] {
|
|
61
|
+
return model.input?.length ? model.input : ["text"];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function modelOutputs(model: CachedModel): Modality[] {
|
|
65
|
+
return model.output?.length ? model.output : ["text"];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Filter by modality. `input` lists what the model must accept (all of them),
|
|
70
|
+
* `output` what it must produce (any of them).
|
|
71
|
+
*/
|
|
72
|
+
export function filterModels(
|
|
73
|
+
models: readonly CachedModel[],
|
|
74
|
+
want: { input?: Modality[]; output?: Modality[] },
|
|
75
|
+
): CachedModel[] {
|
|
76
|
+
return models.filter((m) => {
|
|
77
|
+
const inputs = modelInputs(m);
|
|
78
|
+
const outputs = modelOutputs(m);
|
|
79
|
+
if (want.input && !want.input.every((i) => inputs.includes(i))) return false;
|
|
80
|
+
if (want.output && !want.output.some((o) => outputs.includes(o))) return false;
|
|
81
|
+
return true;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Map pi registry models (chat) to cache entries. Tolerates partial shapes. */
|
|
86
|
+
export function chatModelsToCache(models: readonly unknown[]): CachedModel[] {
|
|
87
|
+
const out: CachedModel[] = [];
|
|
88
|
+
for (const raw of models) {
|
|
89
|
+
const m = raw as { provider?: unknown; id?: unknown; name?: unknown; input?: unknown; contextWindow?: unknown; reasoning?: unknown };
|
|
90
|
+
if (typeof m?.provider !== "string" || typeof m?.id !== "string") continue;
|
|
91
|
+
const input = Array.isArray(m.input) ? (m.input.filter((x) => x === "text" || x === "image") as Modality[]) : ["text" as const];
|
|
92
|
+
out.push({
|
|
93
|
+
provider: m.provider,
|
|
94
|
+
id: m.id,
|
|
95
|
+
...(typeof m.name === "string" ? { name: m.name } : {}),
|
|
96
|
+
input: input.length ? input : ["text"],
|
|
97
|
+
output: ["text"],
|
|
98
|
+
kind: "chat",
|
|
99
|
+
...(typeof m.contextWindow === "number" ? { contextWindow: m.contextWindow } : {}),
|
|
100
|
+
...(typeof m.reasoning === "boolean" ? { reasoning: m.reasoning } : {}),
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
|
|
43
106
|
/**
|
|
44
107
|
* Read cached model list from disk.
|
|
45
108
|
* Returns empty array if no cache file exists or it's malformed.
|
|
46
109
|
*/
|
|
47
110
|
export function readModelCache(): CachedModel[] {
|
|
48
111
|
try {
|
|
49
|
-
const file =
|
|
112
|
+
const file = modelCachePath();
|
|
50
113
|
if (!fs.existsSync(file)) return [];
|
|
51
114
|
const parsed = JSON.parse(fs.readFileSync(file, "utf-8"));
|
|
52
115
|
return Array.isArray(parsed.models) ? parsed.models : [];
|
|
@@ -58,6 +121,8 @@ export function readModelCache(): CachedModel[] {
|
|
|
58
121
|
/**
|
|
59
122
|
* Write model list to cache file.
|
|
60
123
|
* Creates directory if needed. Best effort — silently ignores errors.
|
|
124
|
+
* Entries are de-duplicated by `provider/id` (first wins) and sorted, so the
|
|
125
|
+
* file is stable across sessions with the same catalog.
|
|
61
126
|
*/
|
|
62
127
|
export function writeModelCache(models: CachedModel[]): void {
|
|
63
128
|
try {
|
|
@@ -65,11 +130,20 @@ export function writeModelCache(models: CachedModel[]): void {
|
|
|
65
130
|
if (!fs.existsSync(dir)) {
|
|
66
131
|
fs.mkdirSync(dir, { recursive: true });
|
|
67
132
|
}
|
|
133
|
+
const seen = new Set<string>();
|
|
134
|
+
const unique = models.filter((m) => {
|
|
135
|
+
const key = modelRef(m);
|
|
136
|
+
if (seen.has(key)) return false;
|
|
137
|
+
seen.add(key);
|
|
138
|
+
return true;
|
|
139
|
+
}).sort((a, b) => modelRef(a).localeCompare(modelRef(b)));
|
|
68
140
|
const cache: ModelCache = {
|
|
69
141
|
updatedAt: new Date().toISOString(),
|
|
70
|
-
models,
|
|
142
|
+
models: unique,
|
|
71
143
|
};
|
|
72
|
-
|
|
144
|
+
const tmp = `${modelCachePath()}.${process.pid}.tmp`;
|
|
145
|
+
fs.writeFileSync(tmp, JSON.stringify(cache, null, 2) + "\n", "utf-8");
|
|
146
|
+
fs.renameSync(tmp, modelCachePath());
|
|
73
147
|
} catch {
|
|
74
148
|
// Best effort — cache is optional
|
|
75
149
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/core",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.5",
|
|
4
4
|
"description": "Shared utilities, event types, and constants for Unipi extension suite",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -41,6 +41,6 @@
|
|
|
41
41
|
"themes": []
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
|
-
"test": "npx tsx --test *.test.ts"
|
|
44
|
+
"test": "npx tsx --test *.test.ts src/*/__tests__/*.test.ts"
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chatter detection shared by jev consumers (auto-rename, skill judging):
|
|
3
|
+
* greetings, thanks, acknowledgements and bare "continue"-style nudges carry
|
|
4
|
+
* no subject, so no decision should be made from them.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const CHATTER = new RegExp(
|
|
8
|
+
"^(?:" + [
|
|
9
|
+
"h(?:i|ello|ey|owdy)(?: there)?", "yo", "sup", "good (?:morning|afternoon|evening)",
|
|
10
|
+
"thanks?(?: you)?(?: so much)?", "thx", "ty", "cheers", "nice", "great", "cool", "perfect", "awesome",
|
|
11
|
+
"ok(?:ay)?", "k", "yes", "yep", "yeah", "no", "nope", "sure", "lgtm", "sounds good", "go(?: on| ahead)?",
|
|
12
|
+
"continue", "proceed", "retry", "again", "do it", "next", "done",
|
|
13
|
+
].join("|") + ")[\\s.!?,]*$",
|
|
14
|
+
"i",
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
/** True for messages with no subject of their own (no jev call needed). */
|
|
18
|
+
export function isChatter(text: string): boolean {
|
|
19
|
+
const t = text.trim();
|
|
20
|
+
if (t.length < 3) return true;
|
|
21
|
+
if (t.startsWith("/")) return true;
|
|
22
|
+
return CHATTER.test(t);
|
|
23
|
+
}
|
|
24
|
+
|