@pi-unipi/unipi 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/package.json +21 -21
- package/packages/ask-user/package.json +2 -2
- package/packages/autocomplete/package.json +1 -1
- package/packages/btw/package.json +2 -2
- package/packages/cocoindex/package.json +2 -2
- package/packages/compactor/package.json +3 -3
- package/packages/core/package.json +1 -1
- package/packages/footer/package.json +2 -2
- package/packages/image/package.json +2 -2
- package/packages/image/src/generate.ts +34 -15
- package/packages/image/src/index.ts +8 -0
- package/packages/image/src/models.ts +28 -0
- package/packages/image/src/openai-images-api.ts +282 -0
- package/packages/image/src/register-providers.ts +220 -0
- package/packages/image/src/tools.ts +37 -6
- package/packages/image/src/tui/settings-dialog.ts +6 -1
- package/packages/info-screen/package.json +2 -2
- package/packages/input-shortcuts/package.json +2 -2
- package/packages/kanboard/package.json +2 -2
- package/packages/mcp/package.json +2 -2
- package/packages/memory/package.json +3 -3
- package/packages/milestone/package.json +2 -2
- package/packages/notify/package.json +2 -2
- package/packages/ralph/package.json +3 -3
- package/packages/subagents/package.json +4 -4
- package/packages/unipi/bundled.js +291 -17
- package/packages/updater/package.json +2 -2
- package/packages/utility/package.json +2 -2
- package/packages/web-api/package.json +2 -2
- package/packages/workflow/package.json +2 -2
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pi-unipi/image — Bridge pi's chat providers into pi-ai's images collection
|
|
3
|
+
*
|
|
4
|
+
* pi-ai ships exactly one image provider (openrouter), so out of the box image
|
|
5
|
+
* generation demands an OpenRouter account even when the user has half a dozen
|
|
6
|
+
* other providers configured. pi's own registry knows those providers and their
|
|
7
|
+
* credentials, so we re-register each one as an *images* provider backed by the
|
|
8
|
+
* single generic OpenAI-compatible adapter.
|
|
9
|
+
*
|
|
10
|
+
* The result: any OpenAI-compatible provider the user configures in pi can
|
|
11
|
+
* generate and edit images with no image-specific setup, and no per-provider
|
|
12
|
+
* code here.
|
|
13
|
+
*
|
|
14
|
+
* ## Why capability detection stays heuristic
|
|
15
|
+
* pi's model registry cannot tell us which models emit images.
|
|
16
|
+
* `provider-composer.ts` builds each registered model from an explicit field
|
|
17
|
+
* list — `{id, name, api, provider, baseUrl, reasoning, input, cost,
|
|
18
|
+
* contextWindow, maxTokens, headers, compat}` — so an extension that attaches
|
|
19
|
+
* `output: ["image"]` has it silently dropped. `ProviderModelConfig` has no
|
|
20
|
+
* `output` field at all. Hence `looksLikeImageGenerator()` name-matching, plus
|
|
21
|
+
* explicit "provider/model-id" entry as the always-available escape hatch.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import * as imagesApi from "./openai-images-api.js";
|
|
25
|
+
import {
|
|
26
|
+
getImagesModels,
|
|
27
|
+
listRegistryImageGenModels,
|
|
28
|
+
type ChatModelRegistry,
|
|
29
|
+
type ImageGenModel,
|
|
30
|
+
} from "./models.js";
|
|
31
|
+
|
|
32
|
+
/** pi-ai's `createImagesProvider`, kept structural to avoid type coupling. */
|
|
33
|
+
interface CreateImagesProviderFn {
|
|
34
|
+
(input: {
|
|
35
|
+
id: string;
|
|
36
|
+
name?: string;
|
|
37
|
+
auth: unknown;
|
|
38
|
+
models: readonly ImageGenModel[];
|
|
39
|
+
api: unknown;
|
|
40
|
+
}): unknown;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** The subset of a registry provider we need. */
|
|
44
|
+
interface ProviderLike {
|
|
45
|
+
id: string;
|
|
46
|
+
name?: string;
|
|
47
|
+
baseUrl?: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let registered = false;
|
|
51
|
+
|
|
52
|
+
/** Reset registration state. Test-only. */
|
|
53
|
+
export function __resetRegistrationForTests(): void {
|
|
54
|
+
registered = false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Group discovered generator models by provider, attaching the provider's
|
|
59
|
+
* baseUrl so the adapter knows where to POST.
|
|
60
|
+
*/
|
|
61
|
+
export function groupModelsByProvider(
|
|
62
|
+
models: ImageGenModel[],
|
|
63
|
+
baseUrlFor: (provider: string) => string | undefined,
|
|
64
|
+
): Map<string, { baseUrl: string; models: ImageGenModel[] }> {
|
|
65
|
+
const grouped = new Map<string, { baseUrl: string; models: ImageGenModel[] }>();
|
|
66
|
+
|
|
67
|
+
for (const model of models) {
|
|
68
|
+
const baseUrl = model.baseUrl ?? baseUrlFor(model.provider);
|
|
69
|
+
// Without an endpoint the adapter cannot issue a request; skip rather than
|
|
70
|
+
// register a provider that is guaranteed to fail.
|
|
71
|
+
if (!baseUrl) continue;
|
|
72
|
+
|
|
73
|
+
let entry = grouped.get(model.provider);
|
|
74
|
+
if (!entry) {
|
|
75
|
+
entry = { baseUrl, models: [] };
|
|
76
|
+
grouped.set(model.provider, entry);
|
|
77
|
+
}
|
|
78
|
+
entry.models.push({ ...model, baseUrl });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return grouped;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Read a provider's baseUrl out of pi's registry. */
|
|
85
|
+
function providerBaseUrlLookup(
|
|
86
|
+
registry: ChatModelRegistry,
|
|
87
|
+
): (provider: string) => string | undefined {
|
|
88
|
+
const cache = new Map<string, string | undefined>();
|
|
89
|
+
|
|
90
|
+
return (provider: string) => {
|
|
91
|
+
if (cache.has(provider)) return cache.get(provider);
|
|
92
|
+
|
|
93
|
+
let baseUrl: string | undefined;
|
|
94
|
+
try {
|
|
95
|
+
const models = (registry.getAvailable?.() ?? registry.getAll()) as Array<{
|
|
96
|
+
provider?: string;
|
|
97
|
+
baseUrl?: string;
|
|
98
|
+
}>;
|
|
99
|
+
baseUrl = models.find((m) => m?.provider === provider && m.baseUrl)?.baseUrl;
|
|
100
|
+
} catch {
|
|
101
|
+
baseUrl = undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
cache.set(provider, baseUrl);
|
|
105
|
+
return baseUrl;
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Register every pi provider that looks capable of image generation into
|
|
111
|
+
* pi-ai's images collection.
|
|
112
|
+
*
|
|
113
|
+
* Idempotent and best-effort: a failure here must never break the extension,
|
|
114
|
+
* since generation still works for pi-ai's built-in providers.
|
|
115
|
+
*
|
|
116
|
+
* @returns the provider ids registered.
|
|
117
|
+
*/
|
|
118
|
+
export async function registerRegistryImageProviders(
|
|
119
|
+
registry: ChatModelRegistry | undefined,
|
|
120
|
+
options?: { force?: boolean },
|
|
121
|
+
): Promise<string[]> {
|
|
122
|
+
if (!registry) return [];
|
|
123
|
+
if (registered && !options?.force) return [];
|
|
124
|
+
|
|
125
|
+
const images = await getImagesModels();
|
|
126
|
+
if (!images) return [];
|
|
127
|
+
|
|
128
|
+
// `setProvider` is on MutableImagesModels; the built-in collection provides
|
|
129
|
+
// it, but guard in case a future pi-ai hands back an immutable one.
|
|
130
|
+
const mutable = images as unknown as {
|
|
131
|
+
setProvider?: (provider: unknown) => void;
|
|
132
|
+
getProvider?: (id: string) => unknown;
|
|
133
|
+
};
|
|
134
|
+
if (typeof mutable.setProvider !== "function") return [];
|
|
135
|
+
|
|
136
|
+
let createImagesProvider: CreateImagesProviderFn;
|
|
137
|
+
try {
|
|
138
|
+
const mod = (await import("@earendil-works/pi-ai")) as unknown as {
|
|
139
|
+
createImagesProvider?: CreateImagesProviderFn;
|
|
140
|
+
};
|
|
141
|
+
if (typeof mod.createImagesProvider !== "function") return [];
|
|
142
|
+
createImagesProvider = mod.createImagesProvider;
|
|
143
|
+
} catch {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const discovered = listRegistryImageGenModels(registry);
|
|
148
|
+
if (discovered.length === 0) {
|
|
149
|
+
registered = true;
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const grouped = groupModelsByProvider(discovered, providerBaseUrlLookup(registry));
|
|
154
|
+
const added: string[] = [];
|
|
155
|
+
|
|
156
|
+
for (const [providerId, { models }] of grouped) {
|
|
157
|
+
// Never shadow a provider pi-ai serves natively — its own implementation
|
|
158
|
+
// is better informed than our generic adapter.
|
|
159
|
+
try {
|
|
160
|
+
if (mutable.getProvider?.(providerId)) continue;
|
|
161
|
+
} catch {
|
|
162
|
+
// Treat a lookup failure as "not present" and attempt registration.
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
const provider = createImagesProvider({
|
|
167
|
+
id: providerId,
|
|
168
|
+
name: providerId,
|
|
169
|
+
models,
|
|
170
|
+
api: imagesApi,
|
|
171
|
+
auth: {
|
|
172
|
+
apiKey: {
|
|
173
|
+
name: `${providerId} API key`,
|
|
174
|
+
// Resolve through pi's own auth storage so the user never logs in
|
|
175
|
+
// twice. `resolve` MUST return an AuthResult (`{ auth: {...} }`);
|
|
176
|
+
// returning a bare key fails silently at request time.
|
|
177
|
+
resolve: async () => {
|
|
178
|
+
const key = await resolveProviderKey(registry, providerId);
|
|
179
|
+
return key ? { auth: { apiKey: key }, source: `pi:${providerId}` } : undefined;
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
mutable.setProvider(provider);
|
|
186
|
+
added.push(providerId);
|
|
187
|
+
} catch {
|
|
188
|
+
// One bad provider must not stop the rest.
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
registered = true;
|
|
193
|
+
return added;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Resolve a provider key from pi's auth storage, falling back to the env. */
|
|
197
|
+
async function resolveProviderKey(
|
|
198
|
+
registry: ChatModelRegistry,
|
|
199
|
+
provider: string,
|
|
200
|
+
): Promise<string | undefined> {
|
|
201
|
+
try {
|
|
202
|
+
const key = await registry.getApiKeyForProvider?.(provider);
|
|
203
|
+
if (key) return key;
|
|
204
|
+
} catch {
|
|
205
|
+
// Fall through to the environment.
|
|
206
|
+
}
|
|
207
|
+
const envName = `${provider.toUpperCase().replace(/[^A-Z0-9]/g, "_")}_API_KEY`;
|
|
208
|
+
return process.env[envName] || undefined;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/** Provider ids pi-ai can currently generate with, after registration. */
|
|
212
|
+
export function registeredProviderIds(images: {
|
|
213
|
+
getProviders?: () => ReadonlyArray<{ id: string }>;
|
|
214
|
+
}): string[] {
|
|
215
|
+
try {
|
|
216
|
+
return (images.getProviders?.() ?? []).map((p) => p.id);
|
|
217
|
+
} catch {
|
|
218
|
+
return [];
|
|
219
|
+
}
|
|
220
|
+
}
|
|
@@ -12,7 +12,9 @@ import { IMAGE_TOOLS } from "@pi-unipi/core";
|
|
|
12
12
|
|
|
13
13
|
import { generateImage } from "./generate.js";
|
|
14
14
|
import { loadImage } from "./image-source.js";
|
|
15
|
+
import { registerRegistryImageProviders } from "./register-providers.js";
|
|
15
16
|
import {
|
|
17
|
+
findProviderBaseUrl,
|
|
16
18
|
formatModelRef,
|
|
17
19
|
listAllImageGenModels,
|
|
18
20
|
resolveImageGenModel,
|
|
@@ -84,12 +86,15 @@ function registerGenerateTool(pi: ExtensionAPI): void {
|
|
|
84
86
|
name: IMAGE_TOOLS.GENERATE,
|
|
85
87
|
label: "Generate Image",
|
|
86
88
|
description:
|
|
87
|
-
"Generate an image from a text prompt
|
|
88
|
-
"
|
|
89
|
+
"Generate an image from a text prompt, or edit an existing image by " +
|
|
90
|
+
"passing `image`. The result is returned inline and, when enabled, saved to disk.",
|
|
89
91
|
promptSnippet: "Generate an image from a text prompt.",
|
|
90
92
|
promptGuidelines: [
|
|
91
93
|
"Use image_generate to create images from a text description.",
|
|
92
94
|
"Write a detailed prompt — subject, style, composition and lighting all help.",
|
|
95
|
+
"Pass `image` to edit an existing image instead of generating a new one.",
|
|
96
|
+
"Editing regenerates the whole image, so unmentioned details may change.",
|
|
97
|
+
"Describe what you DO want; negation is unreliable in image models.",
|
|
93
98
|
"Omit model to use the one configured in /unipi:image-settings.",
|
|
94
99
|
"Generated images cost money per call; do not regenerate without being asked.",
|
|
95
100
|
],
|
|
@@ -97,6 +102,13 @@ function registerGenerateTool(pi: ExtensionAPI): void {
|
|
|
97
102
|
prompt: Type.String({
|
|
98
103
|
description: "Description of the image to generate. Be specific.",
|
|
99
104
|
}),
|
|
105
|
+
image: Type.Optional(
|
|
106
|
+
Type.String({
|
|
107
|
+
description:
|
|
108
|
+
"Source image to edit: a local file path, data: URL, or base64 data. " +
|
|
109
|
+
"When set, the model edits this image instead of generating from scratch.",
|
|
110
|
+
}),
|
|
111
|
+
),
|
|
100
112
|
model: Type.Optional(
|
|
101
113
|
Type.String({
|
|
102
114
|
description:
|
|
@@ -109,22 +121,41 @@ function registerGenerateTool(pi: ExtensionAPI): void {
|
|
|
109
121
|
try {
|
|
110
122
|
const config = loadConfig();
|
|
111
123
|
const registry = getRegistry(ctx);
|
|
124
|
+
// Bridge pi's own providers into pi-ai's images collection so the user
|
|
125
|
+
// is not forced onto OpenRouter. Idempotent and best-effort.
|
|
126
|
+
await registerRegistryImageProviders(registry);
|
|
112
127
|
// Include image models contributed by registered providers, so the
|
|
113
128
|
// tool can resolve anything the settings picker offers.
|
|
114
129
|
const models = await listAllImageGenModels(registry);
|
|
115
130
|
|
|
116
131
|
const requested = params.model?.trim() || config.generate.model;
|
|
117
|
-
const
|
|
118
|
-
if (typeof
|
|
132
|
+
const maybeResolved = resolveImageGenModel(requested, models);
|
|
133
|
+
if (typeof maybeResolved === "string") return errorResult(maybeResolved);
|
|
134
|
+
|
|
135
|
+
// A model may arrive without an endpoint — notably a user-typed
|
|
136
|
+
// "provider/model-id", accepted at face value. Fill it in from the
|
|
137
|
+
// registry so the adapter knows where to POST.
|
|
138
|
+
const registryBaseUrl = maybeResolved.baseUrl
|
|
139
|
+
? undefined
|
|
140
|
+
: findProviderBaseUrl(registry, maybeResolved.provider);
|
|
141
|
+
const resolved = registryBaseUrl
|
|
142
|
+
? { ...maybeResolved, baseUrl: registryBaseUrl }
|
|
143
|
+
: maybeResolved;
|
|
119
144
|
|
|
120
145
|
// pi-ai resolves image auth from its own credential store; only fall
|
|
121
146
|
// back to pi's chat-provider key when that comes up empty.
|
|
122
147
|
const fallbackKey = await resolveApiKey(registry, resolved.provider);
|
|
123
148
|
|
|
149
|
+
// An input image switches the request into edit mode.
|
|
150
|
+
const sourceImage = params.image?.trim()
|
|
151
|
+
? loadImage(params.image, ctx.cwd ?? process.cwd())
|
|
152
|
+
: undefined;
|
|
153
|
+
|
|
124
154
|
const result = await generateImage({
|
|
125
155
|
prompt: params.prompt,
|
|
126
156
|
model: resolved,
|
|
127
157
|
...(fallbackKey ? { apiKey: fallbackKey } : {}),
|
|
158
|
+
...(sourceImage ? { inputImage: sourceImage } : {}),
|
|
128
159
|
signal,
|
|
129
160
|
outputDir: config.generate.saveToDisk ? getOutputDir(config) : undefined,
|
|
130
161
|
});
|
|
@@ -134,8 +165,8 @@ function registerGenerateTool(pi: ExtensionAPI): void {
|
|
|
134
165
|
.filter((path): path is string => Boolean(path));
|
|
135
166
|
|
|
136
167
|
const summary = [
|
|
137
|
-
|
|
138
|
-
`with ${formatModelRef(resolved)}.`,
|
|
168
|
+
`${sourceImage ? "Edited" : "Generated"} ${result.images.length} ` +
|
|
169
|
+
`image${result.images.length === 1 ? "" : "s"} with ${formatModelRef(resolved)}.`,
|
|
139
170
|
saved.length > 0 ? `Saved to:\n${saved.map((p) => ` ${p}`).join("\n")}` : "",
|
|
140
171
|
config.generate.saveToDisk && saved.length === 0
|
|
141
172
|
? "Could not write to the output directory — returning the image inline only."
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
type ChatModelRegistry,
|
|
24
24
|
} from "../models.js";
|
|
25
25
|
import { ImageModelSelectorOverlay, type SelectableModel } from "./model-selector.js";
|
|
26
|
+
import { registerRegistryImageProviders } from "../register-providers.js";
|
|
26
27
|
|
|
27
28
|
const EXIT = "__exit__";
|
|
28
29
|
|
|
@@ -239,6 +240,10 @@ async function collectModels(
|
|
|
239
240
|
.modelRegistry;
|
|
240
241
|
|
|
241
242
|
if (kind === "generate") {
|
|
243
|
+
// Bridge pi's providers in first, so a model the user can actually run is
|
|
244
|
+
// not flagged "no image route" purely because we had not registered it yet.
|
|
245
|
+
await registerRegistryImageProviders(registry);
|
|
246
|
+
|
|
242
247
|
// Include models from providers registered by other extensions, not just
|
|
243
248
|
// pi-ai's built-in OpenRouter catalog.
|
|
244
249
|
const models = await listAllImageGenModels(registry);
|
|
@@ -253,7 +258,7 @@ async function collectModels(
|
|
|
253
258
|
// so flag them rather than letting the user pick a dead option.
|
|
254
259
|
unavailable:
|
|
255
260
|
generating.length > 0 && !generating.includes(m.provider)
|
|
256
|
-
? "
|
|
261
|
+
? "no image route"
|
|
257
262
|
: undefined,
|
|
258
263
|
}));
|
|
259
264
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/info-screen",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Dashboard and module registry for Unipi — configurable info overlay with tabbed groups",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@pi-unipi/core": "2.
|
|
36
|
+
"@pi-unipi/core": "2.4.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@earendil-works/pi-coding-agent": "^0.80.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/input-shortcuts",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
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",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@pi-unipi/core": "2.
|
|
36
|
+
"@pi-unipi/core": "2.4.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@earendil-works/pi-coding-agent": "^0.80.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/kanboard",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
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",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"access": "public"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@pi-unipi/core": "2.
|
|
42
|
+
"@pi-unipi/core": "2.4.0"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"@earendil-works/pi-coding-agent": "^0.80.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
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",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"README.md"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@pi-unipi/core": "2.
|
|
30
|
+
"@pi-unipi/core": "2.4.0"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"@earendil-works/pi-coding-agent": "^0.80.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/memory",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Persistent cross-session memory with MemPalace backend (auto-installed) and SQLite fallback for Pi coding agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"better-sqlite3": "^12.9.0",
|
|
44
44
|
"sqlite-vec": "^0.1.9",
|
|
45
45
|
"js-yaml": "^4.1.0",
|
|
46
|
-
"@pi-unipi/core": "2.
|
|
47
|
-
"@pi-unipi/info-screen": "2.
|
|
46
|
+
"@pi-unipi/core": "2.4.0",
|
|
47
|
+
"@pi-unipi/info-screen": "2.4.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"@earendil-works/pi-coding-agent": "^0.80.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/milestone",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Lifecycle layer for project-level goals — MILESTONES.md tracking, session hooks, auto-sync",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@pi-unipi/core": "2.
|
|
32
|
+
"@pi-unipi/core": "2.4.0"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"@earendil-works/pi-coding-agent": "^0.80.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/notify",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Cross-platform notification extension for Pi — native OS, Gotify, and Telegram notifications for agent lifecycle events",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@pi-unipi/core": "2.
|
|
37
|
+
"@pi-unipi/core": "2.4.0",
|
|
38
38
|
"node-notifier": "^10.0.1"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/ralph",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Long-running iterative development loops for Pi coding agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"access": "public"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@pi-unipi/core": "2.
|
|
31
|
-
"@pi-unipi/info-screen": "2.
|
|
30
|
+
"@pi-unipi/core": "2.4.0",
|
|
31
|
+
"@pi-unipi/info-screen": "2.4.0"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
34
|
"@earendil-works/pi-ai": "^0.80.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-unipi/subagents",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Subagents for UniPi — parallel execution, file locking, workflow integration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"test": "npx tsx --test src/__tests__/*.test.ts"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@pi-unipi/core": "2.
|
|
21
|
-
"@pi-unipi/workflow": "2.
|
|
22
|
-
"@pi-unipi/info-screen": "2.
|
|
20
|
+
"@pi-unipi/core": "2.4.0",
|
|
21
|
+
"@pi-unipi/workflow": "2.4.0",
|
|
22
|
+
"@pi-unipi/info-screen": "2.4.0",
|
|
23
23
|
"@earendil-works/pi-agent-core": "^0.80.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|