@victor-software-house/pi-openai-proxy 4.3.1 → 4.4.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/dist/config.d.mts +1 -59
- package/dist/exposure.d.mts +1 -1
- package/dist/schema-BTAG6Urs.d.mts +61 -0
- package/dist/sync-zed.d.mts +53 -0
- package/dist/sync-zed.mjs +152 -0
- package/extensions/proxy.ts +49 -1
- package/package.json +6 -1
package/dist/config.d.mts
CHANGED
|
@@ -1,61 +1,3 @@
|
|
|
1
1
|
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Proxy configuration schema -- single source of truth.
|
|
5
|
-
*
|
|
6
|
-
* Used by both the proxy server and the pi extension.
|
|
7
|
-
* The server reads the JSON config file as defaults, with env vars and CLI args as overrides.
|
|
8
|
-
* The pi extension reads and writes the JSON config file via the /proxy config panel.
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* How public model IDs are generated from canonical provider/model-id pairs.
|
|
12
|
-
*
|
|
13
|
-
* - "collision-prefixed": prefix only providers in conflict groups that share a raw model ID
|
|
14
|
-
* - "universal": expose raw model IDs only; duplicates are a config error
|
|
15
|
-
* - "always-prefixed": always expose <prefix>/<model-id> for every model
|
|
16
|
-
*/
|
|
17
|
-
type PublicModelIdMode = "collision-prefixed" | "universal" | "always-prefixed";
|
|
18
|
-
/**
|
|
19
|
-
* Which models are exposed on the public HTTP API.
|
|
20
|
-
*
|
|
21
|
-
* - "all": every available model
|
|
22
|
-
* - "scoped": all available models from selected providers only
|
|
23
|
-
* - "custom": explicit allowlist of canonical model IDs
|
|
24
|
-
*/
|
|
25
|
-
type ModelExposureMode = "all" | "scoped" | "custom";
|
|
26
|
-
interface ProxyConfig {
|
|
27
|
-
/** Bind address. Default: "127.0.0.1" */
|
|
28
|
-
readonly host: string;
|
|
29
|
-
/** Listen port. Default: 4141 */
|
|
30
|
-
readonly port: number;
|
|
31
|
-
/** Bearer token for proxy auth. Empty string = disabled. */
|
|
32
|
-
readonly authToken: string;
|
|
33
|
-
/** Allow remote image URL fetching. Default: false */
|
|
34
|
-
readonly remoteImages: boolean;
|
|
35
|
-
/** Max request body in MB. Default: 50 */
|
|
36
|
-
readonly maxBodySizeMb: number;
|
|
37
|
-
/** Upstream timeout in seconds. Default: 120 */
|
|
38
|
-
readonly upstreamTimeoutSec: number;
|
|
39
|
-
/** "detached" = background daemon, "session" = dies with pi session. Default: "detached" */
|
|
40
|
-
readonly lifetime: "detached" | "session";
|
|
41
|
-
/** How public model IDs are generated. Default: "collision-prefixed" */
|
|
42
|
-
readonly publicModelIdMode: PublicModelIdMode;
|
|
43
|
-
/** Which models are exposed. Default: "all" */
|
|
44
|
-
readonly modelExposureMode: ModelExposureMode;
|
|
45
|
-
/** Provider keys to expose when modelExposureMode is "scoped". */
|
|
46
|
-
readonly scopedProviders: readonly string[];
|
|
47
|
-
/** Canonical model IDs to expose when modelExposureMode is "custom". */
|
|
48
|
-
readonly customModels: readonly string[];
|
|
49
|
-
/** Provider key -> custom public prefix label. Default prefix = provider key. */
|
|
50
|
-
readonly providerPrefixes: Readonly<Record<string, string>>;
|
|
51
|
-
}
|
|
52
|
-
declare const DEFAULT_CONFIG: Readonly<ProxyConfig>;
|
|
53
|
-
declare function isPublicModelIdMode(value: string): value is PublicModelIdMode;
|
|
54
|
-
declare function isModelExposureMode(value: string): value is ModelExposureMode;
|
|
55
|
-
declare function normalizeConfig(raw: unknown): ProxyConfig;
|
|
56
|
-
declare function getConfigPath(): string;
|
|
57
|
-
declare function loadConfigFromFile(): ProxyConfig;
|
|
58
|
-
declare function saveConfigToFile(config: ProxyConfig): void;
|
|
59
|
-
declare function configToEnv(config: ProxyConfig): Record<string, string>;
|
|
60
|
-
//#endregion
|
|
2
|
+
import { a as configToEnv, c as isPublicModelIdMode, d as saveConfigToFile, i as PublicModelIdMode, l as loadConfigFromFile, n as ModelExposureMode, o as getConfigPath, r as ProxyConfig, s as isModelExposureMode, t as DEFAULT_CONFIG, u as normalizeConfig } from "./schema-BTAG6Urs.mjs";
|
|
61
3
|
export { DEFAULT_CONFIG, ModelExposureMode, ProxyConfig, PublicModelIdMode, configToEnv, getConfigPath, isModelExposureMode, isPublicModelIdMode, loadConfigFromFile, normalizeConfig, saveConfigToFile };
|
package/dist/exposure.d.mts
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/config/schema.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Proxy configuration schema -- single source of truth.
|
|
5
|
+
*
|
|
6
|
+
* Used by both the proxy server and the pi extension.
|
|
7
|
+
* The server reads the JSON config file as defaults, with env vars and CLI args as overrides.
|
|
8
|
+
* The pi extension reads and writes the JSON config file via the /proxy config panel.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* How public model IDs are generated from canonical provider/model-id pairs.
|
|
12
|
+
*
|
|
13
|
+
* - "collision-prefixed": prefix only providers in conflict groups that share a raw model ID
|
|
14
|
+
* - "universal": expose raw model IDs only; duplicates are a config error
|
|
15
|
+
* - "always-prefixed": always expose <prefix>/<model-id> for every model
|
|
16
|
+
*/
|
|
17
|
+
type PublicModelIdMode = "collision-prefixed" | "universal" | "always-prefixed";
|
|
18
|
+
/**
|
|
19
|
+
* Which models are exposed on the public HTTP API.
|
|
20
|
+
*
|
|
21
|
+
* - "all": every available model
|
|
22
|
+
* - "scoped": all available models from selected providers only
|
|
23
|
+
* - "custom": explicit allowlist of canonical model IDs
|
|
24
|
+
*/
|
|
25
|
+
type ModelExposureMode = "all" | "scoped" | "custom";
|
|
26
|
+
interface ProxyConfig {
|
|
27
|
+
/** Bind address. Default: "127.0.0.1" */
|
|
28
|
+
readonly host: string;
|
|
29
|
+
/** Listen port. Default: 4141 */
|
|
30
|
+
readonly port: number;
|
|
31
|
+
/** Bearer token for proxy auth. Empty string = disabled. */
|
|
32
|
+
readonly authToken: string;
|
|
33
|
+
/** Allow remote image URL fetching. Default: false */
|
|
34
|
+
readonly remoteImages: boolean;
|
|
35
|
+
/** Max request body in MB. Default: 50 */
|
|
36
|
+
readonly maxBodySizeMb: number;
|
|
37
|
+
/** Upstream timeout in seconds. Default: 120 */
|
|
38
|
+
readonly upstreamTimeoutSec: number;
|
|
39
|
+
/** "detached" = background daemon, "session" = dies with pi session. Default: "detached" */
|
|
40
|
+
readonly lifetime: "detached" | "session";
|
|
41
|
+
/** How public model IDs are generated. Default: "collision-prefixed" */
|
|
42
|
+
readonly publicModelIdMode: PublicModelIdMode;
|
|
43
|
+
/** Which models are exposed. Default: "all" */
|
|
44
|
+
readonly modelExposureMode: ModelExposureMode;
|
|
45
|
+
/** Provider keys to expose when modelExposureMode is "scoped". */
|
|
46
|
+
readonly scopedProviders: readonly string[];
|
|
47
|
+
/** Canonical model IDs to expose when modelExposureMode is "custom". */
|
|
48
|
+
readonly customModels: readonly string[];
|
|
49
|
+
/** Provider key -> custom public prefix label. Default prefix = provider key. */
|
|
50
|
+
readonly providerPrefixes: Readonly<Record<string, string>>;
|
|
51
|
+
}
|
|
52
|
+
declare const DEFAULT_CONFIG: Readonly<ProxyConfig>;
|
|
53
|
+
declare function isPublicModelIdMode(value: string): value is PublicModelIdMode;
|
|
54
|
+
declare function isModelExposureMode(value: string): value is ModelExposureMode;
|
|
55
|
+
declare function normalizeConfig(raw: unknown): ProxyConfig;
|
|
56
|
+
declare function getConfigPath(): string;
|
|
57
|
+
declare function loadConfigFromFile(): ProxyConfig;
|
|
58
|
+
declare function saveConfigToFile(config: ProxyConfig): void;
|
|
59
|
+
declare function configToEnv(config: ProxyConfig): Record<string, string>;
|
|
60
|
+
//#endregion
|
|
61
|
+
export { configToEnv as a, isPublicModelIdMode as c, saveConfigToFile as d, PublicModelIdMode as i, loadConfigFromFile as l, ModelExposureMode as n, getConfigPath as o, ProxyConfig as r, isModelExposureMode as s, DEFAULT_CONFIG as t, normalizeConfig as u };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
|
|
2
|
+
import { ExposedModel } from "./exposure.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/sync/zed.d.ts
|
|
5
|
+
interface ZedAvailableModel {
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly display_name: string;
|
|
8
|
+
readonly max_tokens: number;
|
|
9
|
+
readonly max_output_tokens: number;
|
|
10
|
+
readonly capabilities: {
|
|
11
|
+
readonly tools: boolean;
|
|
12
|
+
readonly images: boolean;
|
|
13
|
+
readonly parallel_tool_calls: boolean;
|
|
14
|
+
readonly prompt_cache_key: boolean;
|
|
15
|
+
readonly chat_completions: boolean;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
interface ZedSyncOptions {
|
|
19
|
+
/** Provider label in Zed settings (e.g. "Pi Proxy"). */
|
|
20
|
+
readonly providerName: string;
|
|
21
|
+
/** API URL written into the provider block. */
|
|
22
|
+
readonly apiUrl: string;
|
|
23
|
+
/** Preview changes without writing to disk. */
|
|
24
|
+
readonly dryRun: boolean;
|
|
25
|
+
}
|
|
26
|
+
interface ZedSyncResult {
|
|
27
|
+
readonly ok: boolean;
|
|
28
|
+
readonly configPath: string;
|
|
29
|
+
readonly added: number;
|
|
30
|
+
readonly removed: number;
|
|
31
|
+
readonly unchanged: number;
|
|
32
|
+
readonly summary: string;
|
|
33
|
+
readonly error?: string | undefined;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Resolve Zed's global settings.json path.
|
|
37
|
+
*
|
|
38
|
+
* Resolution order:
|
|
39
|
+
* 1. CUSTOM_DATA_DIR env var (Zed's own override)
|
|
40
|
+
* 2. ~/.config/zed/settings.json (macOS + Linux standard)
|
|
41
|
+
* 3. $XDG_CONFIG_HOME/zed/settings.json (Linux XDG)
|
|
42
|
+
*/
|
|
43
|
+
declare function findZedSettings(): string | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Map an ExposedModel to Zed's available_models entry.
|
|
46
|
+
*/
|
|
47
|
+
declare function toZedModel(exposed: ExposedModel): ZedAvailableModel;
|
|
48
|
+
/**
|
|
49
|
+
* Sync exposed models into Zed's settings.json.
|
|
50
|
+
*/
|
|
51
|
+
declare function syncToZed(exposedModels: readonly ExposedModel[], options: ZedSyncOptions): ZedSyncResult;
|
|
52
|
+
//#endregion
|
|
53
|
+
export { ZedAvailableModel, ZedSyncOptions, ZedSyncResult, findZedSettings, syncToZed, toZedModel };
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { applyEdits, modify, parse } from "jsonc-parser";
|
|
5
|
+
//#region src/sync/zed.ts
|
|
6
|
+
/**
|
|
7
|
+
* Zed settings.json model sync.
|
|
8
|
+
*
|
|
9
|
+
* Discovers Zed's settings file, maps exposed proxy models to Zed's
|
|
10
|
+
* openai_compatible available_models shape, and writes them back using
|
|
11
|
+
* jsonc-parser's modify() to preserve comments and formatting.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Resolve Zed's global settings.json path.
|
|
15
|
+
*
|
|
16
|
+
* Resolution order:
|
|
17
|
+
* 1. CUSTOM_DATA_DIR env var (Zed's own override)
|
|
18
|
+
* 2. ~/.config/zed/settings.json (macOS + Linux standard)
|
|
19
|
+
* 3. $XDG_CONFIG_HOME/zed/settings.json (Linux XDG)
|
|
20
|
+
*/
|
|
21
|
+
function findZedSettings() {
|
|
22
|
+
const customDir = process.env.CUSTOM_DATA_DIR;
|
|
23
|
+
if (customDir !== void 0 && customDir.length > 0) {
|
|
24
|
+
const p = resolve(customDir, "settings.json");
|
|
25
|
+
if (existsSync(p)) return p;
|
|
26
|
+
}
|
|
27
|
+
const home = process.env.HOME;
|
|
28
|
+
if (home !== void 0 && home.length > 0) {
|
|
29
|
+
const p = resolve(home, ".config", "zed", "settings.json");
|
|
30
|
+
if (existsSync(p)) return p;
|
|
31
|
+
}
|
|
32
|
+
const xdg = process.env.XDG_CONFIG_HOME;
|
|
33
|
+
if (xdg !== void 0 && xdg.length > 0) {
|
|
34
|
+
const p = resolve(xdg, "zed", "settings.json");
|
|
35
|
+
if (existsSync(p)) return p;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Map an ExposedModel to Zed's available_models entry.
|
|
40
|
+
*/
|
|
41
|
+
function toZedModel(exposed) {
|
|
42
|
+
const model = exposed.model;
|
|
43
|
+
return {
|
|
44
|
+
name: exposed.publicId,
|
|
45
|
+
display_name: model.name,
|
|
46
|
+
max_tokens: model.contextWindow,
|
|
47
|
+
max_output_tokens: model.maxTokens,
|
|
48
|
+
capabilities: {
|
|
49
|
+
tools: true,
|
|
50
|
+
images: model.input.includes("image"),
|
|
51
|
+
parallel_tool_calls: false,
|
|
52
|
+
prompt_cache_key: false,
|
|
53
|
+
chat_completions: true
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const MODIFY_OPTIONS = {
|
|
58
|
+
isArrayInsertion: false,
|
|
59
|
+
formattingOptions: {
|
|
60
|
+
tabSize: 2,
|
|
61
|
+
insertSpaces: true,
|
|
62
|
+
eol: "\n"
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
function isRecord(value) {
|
|
66
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Read the current available_models for a provider from Zed settings.
|
|
70
|
+
* Returns the parsed model names, or an empty array if the path does not exist.
|
|
71
|
+
*/
|
|
72
|
+
function readCurrentModelNames(text, providerName) {
|
|
73
|
+
const root = parse(text);
|
|
74
|
+
if (!isRecord(root)) return [];
|
|
75
|
+
const langModels = root["language_models"];
|
|
76
|
+
if (!isRecord(langModels)) return [];
|
|
77
|
+
const compat = langModels["openai_compatible"];
|
|
78
|
+
if (!isRecord(compat)) return [];
|
|
79
|
+
const provider = compat[providerName];
|
|
80
|
+
if (!isRecord(provider)) return [];
|
|
81
|
+
const models = provider["available_models"];
|
|
82
|
+
if (!Array.isArray(models)) return [];
|
|
83
|
+
const names = [];
|
|
84
|
+
for (const entry of models) if (isRecord(entry)) {
|
|
85
|
+
const name = entry["name"];
|
|
86
|
+
if (typeof name === "string") names.push(name);
|
|
87
|
+
}
|
|
88
|
+
return names;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Apply the full provider block (api_url + available_models) to the JSONC text.
|
|
92
|
+
* Returns the new text with edits applied.
|
|
93
|
+
*/
|
|
94
|
+
function applyProviderBlock(text, providerName, apiUrl, models) {
|
|
95
|
+
return applyEdits(text, modify(text, [
|
|
96
|
+
"language_models",
|
|
97
|
+
"openai_compatible",
|
|
98
|
+
providerName
|
|
99
|
+
], {
|
|
100
|
+
api_url: apiUrl,
|
|
101
|
+
available_models: models
|
|
102
|
+
}, MODIFY_OPTIONS));
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Sync exposed models into Zed's settings.json.
|
|
106
|
+
*/
|
|
107
|
+
function syncToZed(exposedModels, options) {
|
|
108
|
+
const configPath = findZedSettings();
|
|
109
|
+
if (configPath === void 0) return {
|
|
110
|
+
ok: false,
|
|
111
|
+
configPath: "",
|
|
112
|
+
added: 0,
|
|
113
|
+
removed: 0,
|
|
114
|
+
unchanged: 0,
|
|
115
|
+
summary: "",
|
|
116
|
+
error: "Zed settings.json not found. Checked ~/.config/zed/settings.json and $XDG_CONFIG_HOME/zed/settings.json"
|
|
117
|
+
};
|
|
118
|
+
const originalText = readFileSync(configPath, "utf-8");
|
|
119
|
+
const currentNames = new Set(readCurrentModelNames(originalText, options.providerName));
|
|
120
|
+
const zedModels = exposedModels.map(toZedModel);
|
|
121
|
+
const newNames = new Set(zedModels.map((m) => m.name));
|
|
122
|
+
let added = 0;
|
|
123
|
+
let removed = 0;
|
|
124
|
+
let unchanged = 0;
|
|
125
|
+
for (const name of newNames) if (currentNames.has(name)) unchanged += 1;
|
|
126
|
+
else added += 1;
|
|
127
|
+
for (const name of currentNames) if (!newNames.has(name)) removed += 1;
|
|
128
|
+
const parts = [];
|
|
129
|
+
if (added > 0) parts.push(`${String(added)} added`);
|
|
130
|
+
if (removed > 0) parts.push(`${String(removed)} removed`);
|
|
131
|
+
if (unchanged > 0) parts.push(`${String(unchanged)} unchanged`);
|
|
132
|
+
const summary = parts.length > 0 ? parts.join(", ") : "no changes";
|
|
133
|
+
if (options.dryRun) return {
|
|
134
|
+
ok: true,
|
|
135
|
+
configPath,
|
|
136
|
+
added,
|
|
137
|
+
removed,
|
|
138
|
+
unchanged,
|
|
139
|
+
summary: `[dry-run] ${summary}`
|
|
140
|
+
};
|
|
141
|
+
writeFileSync(configPath, applyProviderBlock(originalText, options.providerName, options.apiUrl, zedModels), "utf-8");
|
|
142
|
+
return {
|
|
143
|
+
ok: true,
|
|
144
|
+
configPath,
|
|
145
|
+
added,
|
|
146
|
+
removed,
|
|
147
|
+
unchanged,
|
|
148
|
+
summary
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
//#endregion
|
|
152
|
+
export { findZedSettings, syncToZed, toZedModel };
|
package/extensions/proxy.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* /proxy status Show proxy status
|
|
9
9
|
* /proxy verify Validate model exposure config against available models
|
|
10
10
|
* /proxy models List all exposed models with their public IDs
|
|
11
|
+
* /proxy zed-sync Sync exposed models to Zed settings.json (--dry-run)
|
|
11
12
|
* /proxy config Open settings panel (alias)
|
|
12
13
|
* /proxy show Summarize current config and exposure policy
|
|
13
14
|
* /proxy path Show config file location
|
|
@@ -56,6 +57,8 @@ import {
|
|
|
56
57
|
type ModelExposureConfig,
|
|
57
58
|
} from "@victor-software-house/pi-openai-proxy/exposure";
|
|
58
59
|
|
|
60
|
+
import { syncToZed, type ZedSyncOptions } from "@victor-software-house/pi-openai-proxy/sync/zed";
|
|
61
|
+
|
|
59
62
|
// ---------------------------------------------------------------------------
|
|
60
63
|
// Runtime status
|
|
61
64
|
// ---------------------------------------------------------------------------
|
|
@@ -140,13 +143,15 @@ export default function proxyExtension(pi: ExtensionAPI): void {
|
|
|
140
143
|
"status",
|
|
141
144
|
"verify",
|
|
142
145
|
"models",
|
|
146
|
+
"zed-sync",
|
|
143
147
|
"config",
|
|
144
148
|
"show",
|
|
145
149
|
"path",
|
|
146
150
|
"reset",
|
|
147
151
|
"help",
|
|
148
152
|
];
|
|
149
|
-
const USAGE =
|
|
153
|
+
const USAGE =
|
|
154
|
+
"/proxy [start|stop|restart|status|verify|models|zed-sync|config|show|path|reset|help]";
|
|
150
155
|
|
|
151
156
|
pi.registerCommand("proxy", {
|
|
152
157
|
description: "Manage the OpenAI-compatible proxy",
|
|
@@ -179,6 +184,9 @@ export default function proxyExtension(pi: ExtensionAPI): void {
|
|
|
179
184
|
case "models":
|
|
180
185
|
showModels(ctx);
|
|
181
186
|
return;
|
|
187
|
+
case "zed-sync":
|
|
188
|
+
handleZedSync(ctx, args);
|
|
189
|
+
return;
|
|
182
190
|
case "show":
|
|
183
191
|
showConfig(ctx);
|
|
184
192
|
return;
|
|
@@ -577,6 +585,46 @@ export default function proxyExtension(pi: ExtensionAPI): void {
|
|
|
577
585
|
}
|
|
578
586
|
}
|
|
579
587
|
|
|
588
|
+
// --- Zed sync ---
|
|
589
|
+
|
|
590
|
+
function handleZedSync(ctx: ExtensionContext, args: string): void {
|
|
591
|
+
config = loadConfigFromFile();
|
|
592
|
+
|
|
593
|
+
const dryRun = args.includes("--dry-run");
|
|
594
|
+
|
|
595
|
+
// Compute exposed models (same as /proxy models)
|
|
596
|
+
const available = getAvailableModels();
|
|
597
|
+
const allModels = getAllRegisteredModels();
|
|
598
|
+
const outcome = computeModelExposure(available, allModels, buildExposureConfig());
|
|
599
|
+
if (!outcome.ok) {
|
|
600
|
+
ctx.ui.notify(`Model exposure error: ${outcome.message}`, "error");
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
if (outcome.models.length === 0) {
|
|
605
|
+
ctx.ui.notify("No models exposed. Nothing to sync.", "warning");
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const syncOptions: ZedSyncOptions = {
|
|
610
|
+
providerName: "Pi Proxy",
|
|
611
|
+
apiUrl: `http://${config.host}:${String(config.port)}/v1`,
|
|
612
|
+
dryRun,
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
const result = syncToZed(outcome.models, syncOptions);
|
|
616
|
+
|
|
617
|
+
if (!result.ok) {
|
|
618
|
+
ctx.ui.notify(result.error ?? "Zed sync failed", "error");
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
const msg = dryRun
|
|
623
|
+
? `Zed sync dry-run: ${result.summary}\n${result.configPath}`
|
|
624
|
+
: `Zed sync complete: ${result.summary}\n${result.configPath}`;
|
|
625
|
+
ctx.ui.notify(msg, "info");
|
|
626
|
+
}
|
|
627
|
+
|
|
580
628
|
async function waitForReady(timeoutMs: number): Promise<RuntimeStatus> {
|
|
581
629
|
const start = Date.now();
|
|
582
630
|
const interval = 300;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@victor-software-house/pi-openai-proxy",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.1",
|
|
4
4
|
"description": "OpenAI-compatible HTTP proxy for pi's multi-provider model registry",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Victor Software House",
|
|
@@ -41,6 +41,10 @@
|
|
|
41
41
|
"./exposure": {
|
|
42
42
|
"import": "./dist/exposure.mjs",
|
|
43
43
|
"types": "./dist/exposure.d.mts"
|
|
44
|
+
},
|
|
45
|
+
"./sync/zed": {
|
|
46
|
+
"import": "./dist/sync-zed.mjs",
|
|
47
|
+
"types": "./dist/sync-zed.d.mts"
|
|
44
48
|
}
|
|
45
49
|
},
|
|
46
50
|
"main": "dist/index.mjs",
|
|
@@ -73,6 +77,7 @@
|
|
|
73
77
|
"@sinclair/typebox": "^0.34.0",
|
|
74
78
|
"citty": "^0.1.6",
|
|
75
79
|
"hono": "^4.12.8",
|
|
80
|
+
"jsonc-parser": "^3.3.1",
|
|
76
81
|
"zod": "^4.3.6"
|
|
77
82
|
},
|
|
78
83
|
"devDependencies": {
|