@gonrocca/zero-pi 0.1.18 → 0.1.20
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/prompts/forge.md +6 -0
- package/prompts/phases/build.md +2 -0
- package/prompts/phases/explore.md +2 -0
- package/prompts/phases/plan.md +2 -0
- package/prompts/phases/veredicto.md +2 -0
- 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.20",
|
|
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",
|
package/prompts/forge.md
CHANGED
|
@@ -14,4 +14,10 @@ claim success unless veredicto returned `pasa`.
|
|
|
14
14
|
If the request begins with `--continue [slug]`, resume that unfinished run from
|
|
15
15
|
its `.sdd/<slug>/` artifacts instead of starting fresh.
|
|
16
16
|
|
|
17
|
+
**Work quietly.** Emit one short status line per phase (`explore → …`, the
|
|
18
|
+
verdict, the round count) — no step-by-step narration, no reasoning out loud,
|
|
19
|
+
and do not echo tool output or agent listings back into the chat. The four
|
|
20
|
+
`zero-*` sub-agents already exist; delegate to them directly without running a
|
|
21
|
+
`subagent` listing. The user wants progress and the final verdict, not a log.
|
|
22
|
+
|
|
17
23
|
Feature request: $ARGUMENTS
|
package/prompts/phases/build.md
CHANGED
|
@@ -18,3 +18,5 @@ change within the plan's scope — do not expand it on your own initiative.
|
|
|
18
18
|
|
|
19
19
|
Run the test suite and make it pass before reporting the phase complete. Report
|
|
20
20
|
what you changed so the veredicto phase has something concrete to review.
|
|
21
|
+
|
|
22
|
+
**Work quietly.** Report only your phase's outcome — concise findings, plan, result, or verdict. No step-by-step narration, no reasoning out loud, no echoing tool output.
|
|
@@ -20,3 +20,5 @@ what is relevant to the request, and what to watch out for.
|
|
|
20
20
|
If the orchestrator includes prior-run memory in your brief, use it: past runs
|
|
21
21
|
record what already broke in this code and which plans were sent back. Fold the
|
|
22
22
|
relevant points into the findings under a "Prior runs" heading.
|
|
23
|
+
|
|
24
|
+
**Work quietly.** Report only your phase's outcome — concise findings, plan, result, or verdict. No step-by-step narration, no reasoning out loud, no echoing tool output.
|
package/prompts/phases/plan.md
CHANGED
|
@@ -80,3 +80,5 @@ means the same number on every run.
|
|
|
80
80
|
the tasks above it), the **bold total** computed as the literal sum of the
|
|
81
81
|
per-task estimates, and the over-budget exceptions list — state "none" when
|
|
82
82
|
there are no exceptions.
|
|
83
|
+
|
|
84
|
+
**Work quietly.** Report only your phase's outcome — concise findings, plan, result, or verdict. No step-by-step narration, no reasoning out loud, no echoing tool output.
|
|
@@ -28,3 +28,5 @@ Never return `pasa` unless the evidence supports it.
|
|
|
28
28
|
State the verdict's reasoning concretely — the specific defects for `corregir`,
|
|
29
29
|
the specific plan flaw for `replantear`. The orchestrator persists that
|
|
30
30
|
reasoning to the run's memory trace, so future runs depend on it being precise.
|
|
31
|
+
|
|
32
|
+
**Work quietly.** Report only your phase's outcome — concise findings, plan, result, or verdict. No step-by-step narration, no reasoning out loud, no echoing tool output.
|
|
@@ -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
|
-
}
|