@gonrocca/zero-pi 0.1.18 → 0.1.19
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/extensions/zero-models.ts +8 -24
- package/package.json +1 -2
- package/extensions/opencode-models.ts +0 -111
|
@@ -21,7 +21,6 @@ import { join } from "node:path";
|
|
|
21
21
|
|
|
22
22
|
import { readAutotuneMode, type AutotuneMode } from "./autotune.ts";
|
|
23
23
|
import type { AutotunePending } from "./autotune-extension.ts";
|
|
24
|
-
import { discoverModels } from "./opencode-models.ts";
|
|
25
24
|
|
|
26
25
|
/** The SDD phases, in pipeline order. */
|
|
27
26
|
export const PHASES = ["explore", "plan", "build", "veredicto"] as const;
|
|
@@ -214,45 +213,30 @@ const CUSTOM_PROVIDER = "— otro provider (escribir) —";
|
|
|
214
213
|
/**
|
|
215
214
|
* Group models by provider for the picker.
|
|
216
215
|
*
|
|
217
|
-
* The
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
216
|
+
* The source is pi's own model registry — `getAll()` returns every model from
|
|
217
|
+
* every provider the user is authenticated for (`anthropic`, `openai-codex`,
|
|
218
|
+
* `opencode-go`, …), each with the exact provider id and model id pi resolves
|
|
219
|
+
* at runtime. Using pi's registry — rather than a foreign catalog like
|
|
220
|
+
* OpenCode's — guarantees the names written to `~/.pi/zero.json` are names pi
|
|
221
|
+
* actually understands, so a configured phase model never fails to resolve.
|
|
222
222
|
*/
|
|
223
223
|
function providerGroups(registry: PiModelRegistry | undefined): Map<string, string[]> {
|
|
224
|
-
try {
|
|
225
|
-
const discovered = discoverModels().filter((m) => m.toolCall);
|
|
226
|
-
if (discovered.length > 0) return groupByProvider(discovered);
|
|
227
|
-
} catch {
|
|
228
|
-
/* fall through to pi's registry */
|
|
229
|
-
}
|
|
230
224
|
if (registry && typeof registry.getAll === "function") {
|
|
231
225
|
try {
|
|
232
226
|
const all = registry.getAll();
|
|
233
227
|
if (all && all.length > 0) return groupByProvider(all);
|
|
234
228
|
} catch {
|
|
235
|
-
/* fall through */
|
|
229
|
+
/* fall through to an empty map */
|
|
236
230
|
}
|
|
237
231
|
}
|
|
238
232
|
return new Map();
|
|
239
233
|
}
|
|
240
234
|
|
|
241
|
-
/**
|
|
242
|
-
* Find the provider that owns a model id — checked against OpenCode's catalog
|
|
243
|
-
* first, then pi's own registry.
|
|
244
|
-
*/
|
|
235
|
+
/** Find the provider that owns a model id, per pi's own model registry. */
|
|
245
236
|
function resolveProvider(
|
|
246
237
|
registry: PiModelRegistry | undefined,
|
|
247
238
|
modelId: string,
|
|
248
239
|
): string | undefined {
|
|
249
|
-
try {
|
|
250
|
-
for (const m of discoverModels()) {
|
|
251
|
-
if (m.id === modelId) return m.provider;
|
|
252
|
-
}
|
|
253
|
-
} catch {
|
|
254
|
-
/* ignore */
|
|
255
|
-
}
|
|
256
240
|
if (registry && typeof registry.getAll === "function") {
|
|
257
241
|
try {
|
|
258
242
|
for (const m of registry.getAll()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gonrocca/zero-pi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"description": "zero-pi — an installable layer for pi (pi.dev): the zero spec-driven development workflow, skill auto-learning, and an animated ZERO startup banner. Adds capability to pi without modifying pi.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -44,7 +44,6 @@
|
|
|
44
44
|
"extensions/sdd-agents.ts",
|
|
45
45
|
"extensions/conversation-resume.ts",
|
|
46
46
|
"extensions/zero-models.ts",
|
|
47
|
-
"extensions/opencode-models.ts",
|
|
48
47
|
"extensions/autotune.ts",
|
|
49
48
|
"extensions/autotune-extension.ts",
|
|
50
49
|
"extensions/spec-merge.ts",
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
// zero-pi — OpenCode model-catalog discovery.
|
|
2
|
-
//
|
|
3
|
-
// Surfaces the model providers a user can run by cross-referencing OpenCode's
|
|
4
|
-
// model catalog cache with the user's OpenCode auth file. This is the same
|
|
5
|
-
// approach the `zero` installer's model picker uses, so `/zero-models` offers
|
|
6
|
-
// the same providers — opencode-go, openai (codex/gpt), anthropic, … — as the
|
|
7
|
-
// installer, instead of a hardcoded Claude list.
|
|
8
|
-
//
|
|
9
|
-
// Sources, under the user's home (ZERO_HOME-overridable for tests):
|
|
10
|
-
// ~/.cache/opencode/models.json — the full provider/model catalog
|
|
11
|
-
// ~/.local/share/opencode/auth.json — the providers the user authenticated
|
|
12
|
-
//
|
|
13
|
-
// Discovery is total: a missing or corrupt file yields an empty list, so a
|
|
14
|
-
// user without OpenCode simply falls back to pi's own model registry.
|
|
15
|
-
|
|
16
|
-
import { readFileSync } from "node:fs";
|
|
17
|
-
import { homedir } from "node:os";
|
|
18
|
-
import { join } from "node:path";
|
|
19
|
-
|
|
20
|
-
/** A model discovered from OpenCode's catalog. */
|
|
21
|
-
export interface DiscoveredModel {
|
|
22
|
-
/** The provider id, e.g. `opencode-go`, `openai`, `anthropic`. */
|
|
23
|
-
provider: string;
|
|
24
|
-
/** The model id, e.g. `gpt-5-codex`. */
|
|
25
|
-
id: string;
|
|
26
|
-
/** The human-readable model name. */
|
|
27
|
-
name: string;
|
|
28
|
-
/** Whether the model supports tool calls — required for the SDD phases. */
|
|
29
|
-
toolCall: boolean;
|
|
30
|
-
/** Whether the model exposes a reasoning-effort setting. */
|
|
31
|
-
reasoning: boolean;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** The home directory discovery resolves OpenCode paths against. */
|
|
35
|
-
function discoveryHome(): string {
|
|
36
|
-
const override = process.env.ZERO_HOME;
|
|
37
|
-
return typeof override === "string" && override.trim() !== "" ? override : homedir();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** True for a plain (non-array) object. */
|
|
41
|
-
function isObject(value: unknown): value is Record<string, unknown> {
|
|
42
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** Read and parse a JSON file; returns null on any failure. */
|
|
46
|
-
function readJson(path: string): unknown {
|
|
47
|
-
try {
|
|
48
|
-
return JSON.parse(readFileSync(path, "utf8")) as unknown;
|
|
49
|
-
} catch {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Extract a provider's models from its OpenCode catalog entry.
|
|
56
|
-
*
|
|
57
|
-
* Exported for tests.
|
|
58
|
-
*/
|
|
59
|
-
export function extractModels(
|
|
60
|
-
providerId: string,
|
|
61
|
-
entry: Record<string, unknown>,
|
|
62
|
-
): DiscoveredModel[] {
|
|
63
|
-
const raw = entry.models;
|
|
64
|
-
if (!isObject(raw)) return [];
|
|
65
|
-
|
|
66
|
-
const models: DiscoveredModel[] = [];
|
|
67
|
-
for (const [id, model] of Object.entries(raw)) {
|
|
68
|
-
if (!isObject(model)) continue;
|
|
69
|
-
models.push({
|
|
70
|
-
provider: providerId,
|
|
71
|
-
id,
|
|
72
|
-
name: typeof model.name === "string" ? model.name : id,
|
|
73
|
-
toolCall: model.tool_call === true,
|
|
74
|
-
reasoning: model.reasoning === true,
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
return models;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Discover every model the user can run, flattened across all OpenCode-
|
|
82
|
-
* authenticated providers.
|
|
83
|
-
*
|
|
84
|
-
* `catalogJson` and `authJson` are injectable for tests; in normal use they
|
|
85
|
-
* are read from OpenCode's cache and auth files on disk. The result is empty
|
|
86
|
-
* when either source is absent or malformed.
|
|
87
|
-
*/
|
|
88
|
-
export function discoverModels(
|
|
89
|
-
catalogJson?: unknown,
|
|
90
|
-
authJson?: unknown,
|
|
91
|
-
): DiscoveredModel[] {
|
|
92
|
-
// Only touch disk when an argument is genuinely absent — an explicit value
|
|
93
|
-
// (including `null`) is used as given, so tests never read real files.
|
|
94
|
-
const auth =
|
|
95
|
-
authJson === undefined
|
|
96
|
-
? readJson(join(discoveryHome(), ".local", "share", "opencode", "auth.json"))
|
|
97
|
-
: authJson;
|
|
98
|
-
const catalog =
|
|
99
|
-
catalogJson === undefined
|
|
100
|
-
? readJson(join(discoveryHome(), ".cache", "opencode", "models.json"))
|
|
101
|
-
: catalogJson;
|
|
102
|
-
if (!isObject(auth) || !isObject(catalog)) return [];
|
|
103
|
-
|
|
104
|
-
const models: DiscoveredModel[] = [];
|
|
105
|
-
for (const providerId of Object.keys(auth)) {
|
|
106
|
-
const entry = catalog[providerId];
|
|
107
|
-
if (!isObject(entry)) continue;
|
|
108
|
-
models.push(...extractModels(providerId, entry));
|
|
109
|
-
}
|
|
110
|
-
return models;
|
|
111
|
-
}
|