@oh-my-pi/pi-coding-agent 15.12.3 → 15.12.4
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 +43 -1
- package/dist/cli.js +1120 -870
- package/dist/types/autoresearch/tools/init-experiment.d.ts +1 -1
- package/dist/types/autoresearch/tools/log-experiment.d.ts +1 -1
- package/dist/types/autoresearch/tools/run-experiment.d.ts +1 -1
- package/dist/types/autoresearch/tools/update-notes.d.ts +1 -1
- package/dist/types/cli/args.d.ts +0 -1
- package/dist/types/cli/models-cli.d.ts +49 -0
- package/dist/types/commands/launch.d.ts +0 -3
- package/dist/types/commands/models.d.ts +33 -0
- package/dist/types/commands/token.d.ts +25 -0
- package/dist/types/commit/agentic/tools/analyze-file.d.ts +1 -1
- package/dist/types/commit/agentic/tools/git-file-diff.d.ts +1 -1
- package/dist/types/commit/agentic/tools/git-hunk.d.ts +1 -1
- package/dist/types/commit/agentic/tools/git-overview.d.ts +1 -1
- package/dist/types/commit/agentic/tools/propose-changelog.d.ts +1 -1
- package/dist/types/commit/agentic/tools/propose-commit.d.ts +1 -1
- package/dist/types/commit/agentic/tools/recent-commits.d.ts +1 -1
- package/dist/types/commit/agentic/tools/schemas.d.ts +1 -1
- package/dist/types/commit/agentic/tools/split-commit.d.ts +1 -1
- package/dist/types/commit/changelog/generate.d.ts +1 -1
- package/dist/types/commit/shared-llm.d.ts +1 -1
- package/dist/types/config/model-registry.d.ts +7 -0
- package/dist/types/config/models-config-schema.d.ts +1 -1
- package/dist/types/config/settings-schema.d.ts +20 -0
- package/dist/types/edit/hashline/params.d.ts +1 -1
- package/dist/types/edit/modes/apply-patch.d.ts +1 -1
- package/dist/types/edit/modes/patch.d.ts +1 -1
- package/dist/types/edit/modes/replace.d.ts +1 -1
- package/dist/types/extensibility/custom-commands/types.d.ts +2 -2
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
- package/dist/types/extensibility/extensions/types.d.ts +2 -2
- package/dist/types/extensibility/hooks/types.d.ts +2 -2
- package/dist/types/goals/tools/goal-tool.d.ts +1 -1
- package/dist/types/lsp/types.d.ts +1 -1
- package/dist/types/mcp/manager.d.ts +8 -0
- package/dist/types/mnemopi/config.d.ts +28 -0
- package/dist/types/modes/acp/acp-agent.d.ts +1 -2
- package/dist/types/modes/components/index.d.ts +1 -0
- package/dist/types/modes/components/logout-account-selector.d.ts +8 -0
- package/dist/types/modes/components/status-line/component.d.ts +9 -5
- package/dist/types/modes/components/status-line/types.d.ts +2 -1
- package/dist/types/modes/controllers/event-controller.d.ts +0 -17
- package/dist/types/modes/interactive-mode.d.ts +0 -3
- package/dist/types/modes/types.d.ts +0 -5
- package/dist/types/session/agent-session.d.ts +14 -33
- package/dist/types/session/agent-storage.d.ts +2 -1
- package/dist/types/session/indexed-session-storage.d.ts +1 -0
- package/dist/types/session/messages.d.ts +8 -10
- package/dist/types/session/session-manager.d.ts +15 -0
- package/dist/types/session/session-storage.d.ts +5 -0
- package/dist/types/slash-commands/helpers/logout.d.ts +15 -0
- package/dist/types/task/types.d.ts +1 -1
- package/dist/types/tools/ask.d.ts +1 -1
- package/dist/types/tools/ast-edit.d.ts +1 -1
- package/dist/types/tools/ast-grep.d.ts +1 -1
- package/dist/types/tools/bash.d.ts +1 -1
- package/dist/types/tools/browser/cmux/cmux-tab.d.ts +202 -0
- package/dist/types/tools/browser/cmux/rpc.d.ts +70 -0
- package/dist/types/tools/browser/cmux/socket-client.d.ts +19 -0
- package/dist/types/tools/browser/registry.d.ts +16 -3
- package/dist/types/tools/browser/render.d.ts +2 -0
- package/dist/types/tools/browser/tab-protocol.d.ts +2 -0
- package/dist/types/tools/browser/tab-supervisor.d.ts +16 -4
- package/dist/types/tools/browser.d.ts +3 -1
- package/dist/types/tools/checkpoint.d.ts +1 -1
- package/dist/types/tools/debug.d.ts +1 -1
- package/dist/types/tools/eval.d.ts +1 -1
- package/dist/types/tools/find.d.ts +1 -1
- package/dist/types/tools/gh.d.ts +1 -1
- package/dist/types/tools/image-gen.d.ts +1 -1
- package/dist/types/tools/index.d.ts +3 -1
- package/dist/types/tools/inspect-image.d.ts +1 -1
- package/dist/types/tools/irc.d.ts +1 -1
- package/dist/types/tools/job.d.ts +1 -1
- package/dist/types/tools/memory-edit.d.ts +1 -1
- package/dist/types/tools/memory-recall.d.ts +1 -1
- package/dist/types/tools/memory-reflect.d.ts +1 -1
- package/dist/types/tools/memory-retain.d.ts +1 -1
- package/dist/types/tools/read.d.ts +1 -1
- package/dist/types/tools/render-mermaid.d.ts +1 -1
- package/dist/types/tools/resolve.d.ts +1 -1
- package/dist/types/tools/review.d.ts +1 -1
- package/dist/types/tools/search-tool-bm25.d.ts +1 -1
- package/dist/types/tools/search.d.ts +1 -1
- package/dist/types/tools/ssh.d.ts +1 -1
- package/dist/types/tools/todo.d.ts +1 -1
- package/dist/types/tools/tts.d.ts +1 -1
- package/dist/types/tools/write.d.ts +1 -1
- package/dist/types/utils/clipboard.d.ts +4 -3
- package/dist/types/utils/image-loading.d.ts +18 -1
- package/dist/types/utils/thinking-display.d.ts +17 -0
- package/dist/types/web/search/index.d.ts +1 -1
- package/package.json +14 -14
- package/src/autoresearch/storage.ts +2 -1
- package/src/autoresearch/tools/init-experiment.ts +1 -1
- package/src/autoresearch/tools/log-experiment.ts +1 -1
- package/src/autoresearch/tools/run-experiment.ts +1 -1
- package/src/autoresearch/tools/update-notes.ts +1 -1
- package/src/cli/args.ts +0 -8
- package/src/cli/auth-gateway-cli.ts +1 -1
- package/src/cli/bench-cli.ts +1 -1
- package/src/cli/dry-balance-cli.ts +1 -1
- package/src/cli/models-cli.ts +427 -0
- package/src/cli-commands.ts +2 -0
- package/src/collab/host.ts +9 -12
- package/src/commands/launch.ts +0 -3
- package/src/commands/models.ts +61 -0
- package/src/commands/token.ts +89 -0
- package/src/commit/agentic/tools/analyze-file.ts +1 -1
- package/src/commit/agentic/tools/git-file-diff.ts +1 -1
- package/src/commit/agentic/tools/git-hunk.ts +1 -1
- package/src/commit/agentic/tools/git-overview.ts +1 -1
- package/src/commit/agentic/tools/propose-changelog.ts +1 -1
- package/src/commit/agentic/tools/propose-commit.ts +1 -1
- package/src/commit/agentic/tools/recent-commits.ts +1 -1
- package/src/commit/agentic/tools/schemas.ts +1 -1
- package/src/commit/agentic/tools/split-commit.ts +1 -1
- package/src/commit/analysis/summary.ts +1 -1
- package/src/commit/changelog/generate.ts +1 -1
- package/src/commit/shared-llm.ts +1 -1
- package/src/config/model-registry.ts +15 -12
- package/src/config/model-resolver.ts +2 -2
- package/src/config/models-config-schema.ts +1 -1
- package/src/config/settings-schema.ts +18 -0
- package/src/edit/hashline/params.ts +1 -1
- package/src/edit/modes/apply-patch.ts +1 -1
- package/src/edit/modes/patch.ts +1 -1
- package/src/edit/modes/replace.ts +1 -1
- package/src/eval/agent-bridge.ts +1 -1
- package/src/eval/completion-bridge.ts +1 -1
- package/src/export/html/template.js +24 -2
- package/src/export/html/tool-views.generated.js +2 -2
- package/src/extensibility/custom-commands/loader.ts +1 -1
- package/src/extensibility/custom-commands/types.ts +2 -2
- package/src/extensibility/custom-tools/loader.ts +1 -1
- package/src/extensibility/custom-tools/types.ts +2 -2
- package/src/extensibility/extensions/loader.ts +2 -2
- package/src/extensibility/extensions/types.ts +2 -2
- package/src/extensibility/hooks/loader.ts +1 -1
- package/src/extensibility/hooks/types.ts +2 -2
- package/src/extensibility/skills.ts +18 -3
- package/src/goals/tools/goal-tool.ts +1 -1
- package/src/internal-urls/docs-index.generated.ts +5 -2
- package/src/lsp/types.ts +1 -1
- package/src/main.ts +0 -25
- package/src/mcp/config-writer.ts +7 -3
- package/src/mcp/manager.ts +11 -0
- package/src/memories/index.ts +3 -1
- package/src/memories/storage.ts +2 -1
- package/src/mnemopi/config.ts +95 -11
- package/src/modes/acp/acp-agent.ts +5 -48
- package/src/modes/acp/acp-event-mapper.ts +5 -1
- package/src/modes/components/agent-hub.ts +2 -1
- package/src/modes/components/assistant-message.ts +8 -7
- package/src/modes/components/index.ts +1 -0
- package/src/modes/components/logout-account-selector.ts +130 -0
- package/src/modes/components/mcp-add-wizard.ts +1 -1
- package/src/modes/components/model-selector.ts +2 -2
- package/src/modes/components/status-line/component.ts +54 -157
- package/src/modes/components/status-line/segments.ts +1 -1
- package/src/modes/components/status-line/types.ts +2 -1
- package/src/modes/controllers/command-controller.ts +0 -12
- package/src/modes/controllers/event-controller.ts +23 -62
- package/src/modes/controllers/input-controller.ts +53 -30
- package/src/modes/controllers/mcp-command-controller.ts +44 -3
- package/src/modes/controllers/selector-controller.ts +56 -10
- package/src/modes/controllers/streaming-reveal.ts +4 -3
- package/src/modes/interactive-mode.ts +2 -8
- package/src/modes/theme/theme.ts +1 -1
- package/src/modes/types.ts +0 -5
- package/src/modes/utils/ui-helpers.ts +2 -1
- package/src/prompts/system/empty-stop-retry.md +4 -6
- package/src/sdk.ts +15 -19
- package/src/session/agent-session.ts +125 -234
- package/src/session/agent-storage.ts +18 -9
- package/src/session/history-storage.ts +2 -1
- package/src/session/indexed-session-storage.ts +7 -0
- package/src/session/messages.ts +9 -11
- package/src/session/session-dump-format.ts +4 -2
- package/src/session/session-manager.ts +116 -0
- package/src/session/session-storage.ts +20 -0
- package/src/slash-commands/builtin-registry.ts +15 -1
- package/src/slash-commands/helpers/logout.ts +88 -0
- package/src/task/types.ts +1 -1
- package/src/tools/ask.ts +1 -1
- package/src/tools/ast-edit.ts +1 -1
- package/src/tools/ast-grep.ts +1 -1
- package/src/tools/bash.ts +1 -1
- package/src/tools/browser/cmux/cmux-tab.ts +1264 -0
- package/src/tools/browser/cmux/rpc.ts +156 -0
- package/src/tools/browser/cmux/socket-client.ts +309 -0
- package/src/tools/browser/registry.ts +37 -3
- package/src/tools/browser/render.ts +6 -1
- package/src/tools/browser/tab-protocol.ts +2 -0
- package/src/tools/browser/tab-supervisor.ts +189 -18
- package/src/tools/browser/tab-worker.ts +1 -1
- package/src/tools/browser.ts +16 -1
- package/src/tools/checkpoint.ts +1 -1
- package/src/tools/debug.ts +1 -1
- package/src/tools/eval.ts +11 -6
- package/src/tools/fetch.ts +13 -2
- package/src/tools/find.ts +1 -1
- package/src/tools/gh.ts +1 -1
- package/src/tools/github-cache.ts +2 -1
- package/src/tools/image-gen.ts +1 -1
- package/src/tools/index.ts +3 -1
- package/src/tools/inspect-image.ts +3 -1
- package/src/tools/irc.ts +1 -1
- package/src/tools/job.ts +1 -1
- package/src/tools/memory-edit.ts +1 -1
- package/src/tools/memory-recall.ts +1 -1
- package/src/tools/memory-reflect.ts +1 -1
- package/src/tools/memory-retain.ts +1 -1
- package/src/tools/read.ts +8 -2
- package/src/tools/render-mermaid.ts +1 -1
- package/src/tools/report-tool-issue.ts +3 -2
- package/src/tools/resolve.ts +1 -1
- package/src/tools/review.ts +1 -1
- package/src/tools/search-tool-bm25.ts +1 -1
- package/src/tools/search.ts +1 -1
- package/src/tools/ssh.ts +1 -1
- package/src/tools/todo.ts +1 -1
- package/src/tools/tts.ts +1 -1
- package/src/tools/write.ts +1 -1
- package/src/utils/clipboard.ts +35 -18
- package/src/utils/image-loading.ts +35 -4
- package/src/utils/thinking-display.ts +37 -0
- package/src/web/search/index.ts +1 -1
- package/dist/types/cli/list-models.d.ts +0 -30
- package/src/cli/list-models.ts +0 -194
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `omp models` — list, search, and refresh available models.
|
|
3
|
+
*
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* - `ls` (default): list every available model with a canonical + provider view.
|
|
6
|
+
* - `find <substring>`: list models whose provider, id, or name contains the substring.
|
|
7
|
+
* - `refresh`: force an online catalog re-fetch (ignoring the model cache TTL),
|
|
8
|
+
* then list. This is the supported replacement for `rm -rf ~/.omp/models.db`
|
|
9
|
+
* when a provider ships a new model that the 24h cache has not picked up yet.
|
|
10
|
+
*
|
|
11
|
+
* `ls`/`find` use the cache when fresh (`online-if-uncached`); only `refresh`
|
|
12
|
+
* forces the network (`online`).
|
|
13
|
+
*/
|
|
14
|
+
import type { Api, Effort, Model } from "@oh-my-pi/pi-ai";
|
|
15
|
+
import { getSupportedEfforts } from "@oh-my-pi/pi-catalog/model-thinking";
|
|
16
|
+
import { formatNumber, getProjectDir } from "@oh-my-pi/pi-utils";
|
|
17
|
+
import chalk from "chalk";
|
|
18
|
+
import { ModelRegistry } from "../config/model-registry";
|
|
19
|
+
import { Settings } from "../config/settings";
|
|
20
|
+
import { discoverAndLoadExtensions, loadExtensions } from "../extensibility/extensions";
|
|
21
|
+
import { discoverAuthStorage } from "../sdk";
|
|
22
|
+
import { EventBus } from "../utils/event-bus";
|
|
23
|
+
|
|
24
|
+
export type ModelsAction = "ls" | "find" | "refresh" | "canonical";
|
|
25
|
+
|
|
26
|
+
export interface ModelsCommandArgs {
|
|
27
|
+
action: ModelsAction;
|
|
28
|
+
/** Search substring for `find`, or optional filter for `ls`. */
|
|
29
|
+
pattern?: string;
|
|
30
|
+
flags: {
|
|
31
|
+
json?: boolean;
|
|
32
|
+
/** CLI `-e <path>` extension paths to load before listing (issue #905). */
|
|
33
|
+
extensions?: string[];
|
|
34
|
+
/** Skip extension discovery; only load explicit `extensions`. */
|
|
35
|
+
noExtensions?: boolean;
|
|
36
|
+
/** Extra `config.yml` overlays to apply for this invocation. */
|
|
37
|
+
config?: string[];
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Known action keywords. Any other first token (e.g. `openai-codex`) is treated
|
|
43
|
+
* as a provider/substring filter for the default `ls` view, so every provider
|
|
44
|
+
* name doubles as an `omp models <provider>` shortcut.
|
|
45
|
+
*/
|
|
46
|
+
const KNOWN_ACTIONS: Record<string, ModelsAction> = {
|
|
47
|
+
ls: "ls",
|
|
48
|
+
list: "ls",
|
|
49
|
+
find: "find",
|
|
50
|
+
refresh: "refresh",
|
|
51
|
+
canonical: "canonical",
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/** Resolve the two positional args into an action + filter (provider names fall through to `ls`). */
|
|
55
|
+
export function resolveModelsArgs(
|
|
56
|
+
first: string | undefined,
|
|
57
|
+
second: string | undefined,
|
|
58
|
+
): { action: ModelsAction; pattern: string | undefined } {
|
|
59
|
+
const known = first === undefined ? undefined : KNOWN_ACTIONS[first];
|
|
60
|
+
if (known) {
|
|
61
|
+
return { action: known, pattern: second };
|
|
62
|
+
}
|
|
63
|
+
return { action: "ls", pattern: first };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
interface ModelJson {
|
|
67
|
+
provider: string;
|
|
68
|
+
id: string;
|
|
69
|
+
selector: string;
|
|
70
|
+
name: string;
|
|
71
|
+
contextWindow: number | null;
|
|
72
|
+
maxTokens: number | null;
|
|
73
|
+
reasoning: boolean;
|
|
74
|
+
/** Supported thinking efforts when the model thinks, otherwise null. */
|
|
75
|
+
thinking: readonly Effort[] | null;
|
|
76
|
+
input: ("text" | "image")[];
|
|
77
|
+
cost: Model<Api>["cost"];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface CanonicalJson {
|
|
81
|
+
id: string;
|
|
82
|
+
selected: string;
|
|
83
|
+
variants: number;
|
|
84
|
+
contextWindow: number | null;
|
|
85
|
+
maxTokens: number | null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
interface ModelsJson {
|
|
89
|
+
models: ModelJson[];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
interface CanonicalModelsJson {
|
|
93
|
+
canonical: CanonicalJson[];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function writeLine(line = ""): void {
|
|
97
|
+
process.stdout.write(`${line}\n`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function formatLimit(n: number | null): string {
|
|
101
|
+
return n === null ? "-" : formatNumber(n);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function byProviderThenId(left: Model<Api>, right: Model<Api>): number {
|
|
105
|
+
const providerCmp = left.provider.localeCompare(right.provider);
|
|
106
|
+
if (providerCmp !== 0) return providerCmp;
|
|
107
|
+
return left.id.localeCompare(right.id);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function toModelJson(model: Model<Api>): ModelJson {
|
|
111
|
+
return {
|
|
112
|
+
provider: model.provider,
|
|
113
|
+
id: model.id,
|
|
114
|
+
selector: `${model.provider}/${model.id}`,
|
|
115
|
+
name: model.name,
|
|
116
|
+
contextWindow: model.contextWindow,
|
|
117
|
+
maxTokens: model.maxTokens,
|
|
118
|
+
reasoning: model.reasoning,
|
|
119
|
+
thinking: model.thinking ? getSupportedEfforts(model) : null,
|
|
120
|
+
input: model.input,
|
|
121
|
+
cost: model.cost,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
type ColumnAlign = "left" | "right";
|
|
126
|
+
|
|
127
|
+
interface BoxColumn {
|
|
128
|
+
header: string;
|
|
129
|
+
align?: ColumnAlign;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Right- or left-pad a plain (ANSI-free) cell to `width` display columns. */
|
|
133
|
+
function padCell(text: string, width: number, align: ColumnAlign = "left"): string {
|
|
134
|
+
const space = width - Bun.stringWidth(text);
|
|
135
|
+
if (space <= 0) return text;
|
|
136
|
+
const fill = " ".repeat(space);
|
|
137
|
+
return align === "right" ? fill + text : text + fill;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Render `rows` as a box-drawing table. Cells must be plain text (no ANSI); the
|
|
142
|
+
* header row is bolded and the borders dimmed (both no-ops on non-TTY output).
|
|
143
|
+
*/
|
|
144
|
+
function boxTable(columns: BoxColumn[], rows: string[][]): string[] {
|
|
145
|
+
const widths = columns.map((column, index) =>
|
|
146
|
+
Math.max(Bun.stringWidth(column.header), ...rows.map(row => Bun.stringWidth(row[index] ?? ""))),
|
|
147
|
+
);
|
|
148
|
+
const bar = chalk.dim("│");
|
|
149
|
+
const segments = widths.map(width => "─".repeat(width + 2));
|
|
150
|
+
const renderRow = (cells: string[], bold: boolean): string => {
|
|
151
|
+
const padded = columns.map((column, index) => {
|
|
152
|
+
const cell = padCell(cells[index] ?? "", widths[index]!, column.align);
|
|
153
|
+
return bold ? chalk.bold(cell) : cell;
|
|
154
|
+
});
|
|
155
|
+
return `${bar} ${padded.join(` ${bar} `)} ${bar}`;
|
|
156
|
+
};
|
|
157
|
+
const lines = [chalk.dim(`┌${segments.join("┬")}┐`)];
|
|
158
|
+
lines.push(
|
|
159
|
+
renderRow(
|
|
160
|
+
columns.map(column => column.header),
|
|
161
|
+
true,
|
|
162
|
+
),
|
|
163
|
+
);
|
|
164
|
+
lines.push(chalk.dim(`├${segments.join("┼")}┤`));
|
|
165
|
+
for (const row of rows) {
|
|
166
|
+
lines.push(renderRow(row, false));
|
|
167
|
+
}
|
|
168
|
+
lines.push(chalk.dim(`└${segments.join("┴")}┘`));
|
|
169
|
+
return lines;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** `omp models ls`/`find`: provider-grouped listing (one box table per provider). */
|
|
173
|
+
function renderProviderModels(
|
|
174
|
+
modelRegistry: ModelRegistry,
|
|
175
|
+
action: ModelsAction,
|
|
176
|
+
pattern: string | undefined,
|
|
177
|
+
json: boolean,
|
|
178
|
+
): void {
|
|
179
|
+
const available = modelRegistry.getAvailable();
|
|
180
|
+
const needle = pattern?.toLowerCase();
|
|
181
|
+
let filtered = available;
|
|
182
|
+
|
|
183
|
+
if (needle) {
|
|
184
|
+
let exactFound = false;
|
|
185
|
+
if (action !== "find") {
|
|
186
|
+
const exact = available.filter(m => m.provider.toLowerCase() === needle);
|
|
187
|
+
if (exact.length > 0) {
|
|
188
|
+
filtered = exact;
|
|
189
|
+
exactFound = true;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (!exactFound) {
|
|
193
|
+
filtered = available.filter(
|
|
194
|
+
model =>
|
|
195
|
+
model.id.toLowerCase().includes(needle) ||
|
|
196
|
+
model.provider.toLowerCase().includes(needle) ||
|
|
197
|
+
`${model.provider}/${model.id}`.toLowerCase().includes(needle) ||
|
|
198
|
+
model.name.toLowerCase().includes(needle),
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (json) {
|
|
204
|
+
const output: ModelsJson = { models: filtered.slice().sort(byProviderThenId).map(toModelJson) };
|
|
205
|
+
writeLine(JSON.stringify(output));
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (available.length === 0) {
|
|
210
|
+
writeLine("No models available. Set API keys in environment variables.");
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (filtered.length === 0) {
|
|
214
|
+
writeLine(`No models matching "${pattern}"`);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// One section per provider: bold heading + a box table of that provider's models.
|
|
219
|
+
const byProvider = new Map<string, Model<Api>[]>();
|
|
220
|
+
for (const model of filtered.slice().sort(byProviderThenId)) {
|
|
221
|
+
let group = byProvider.get(model.provider);
|
|
222
|
+
if (!group) {
|
|
223
|
+
group = [];
|
|
224
|
+
byProvider.set(model.provider, group);
|
|
225
|
+
}
|
|
226
|
+
group.push(model);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
let firstProvider = true;
|
|
230
|
+
for (const [provider, models] of byProvider) {
|
|
231
|
+
if (!firstProvider) writeLine();
|
|
232
|
+
firstProvider = false;
|
|
233
|
+
writeLine(`${chalk.bold.cyan(provider)} ${chalk.dim(`(${models.length})`)}`);
|
|
234
|
+
const rows = models.map(model => [
|
|
235
|
+
model.id,
|
|
236
|
+
formatLimit(model.contextWindow),
|
|
237
|
+
formatLimit(model.maxTokens),
|
|
238
|
+
model.thinking ? getSupportedEfforts(model).join(",") : model.reasoning ? "yes" : "-",
|
|
239
|
+
model.input.includes("image") ? "yes" : "no",
|
|
240
|
+
]);
|
|
241
|
+
for (const line of boxTable(
|
|
242
|
+
[
|
|
243
|
+
{ header: "model" },
|
|
244
|
+
{ header: "context", align: "right" },
|
|
245
|
+
{ header: "max-out", align: "right" },
|
|
246
|
+
{ header: "thinking" },
|
|
247
|
+
{ header: "images" },
|
|
248
|
+
],
|
|
249
|
+
rows,
|
|
250
|
+
)) {
|
|
251
|
+
writeLine(line);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** `omp models canonical`: the coalesced canonical view (one row per canonical id). */
|
|
257
|
+
function renderCanonicalModels(modelRegistry: ModelRegistry, pattern: string | undefined, json: boolean): void {
|
|
258
|
+
const selections = modelRegistry.getCanonicalModelSelections({ availableOnly: true });
|
|
259
|
+
const needle = pattern?.toLowerCase();
|
|
260
|
+
const filtered = needle
|
|
261
|
+
? selections.filter(
|
|
262
|
+
({ record, model }) =>
|
|
263
|
+
record.id.toLowerCase().includes(needle) ||
|
|
264
|
+
`${model.provider}/${model.id}`.toLowerCase().includes(needle),
|
|
265
|
+
)
|
|
266
|
+
: selections;
|
|
267
|
+
|
|
268
|
+
if (json) {
|
|
269
|
+
const output: CanonicalModelsJson = {
|
|
270
|
+
canonical: filtered
|
|
271
|
+
.map(({ record, model }) => ({
|
|
272
|
+
id: record.id,
|
|
273
|
+
selected: `${model.provider}/${model.id}`,
|
|
274
|
+
variants: record.variants.length,
|
|
275
|
+
contextWindow: model.contextWindow,
|
|
276
|
+
maxTokens: model.maxTokens,
|
|
277
|
+
}))
|
|
278
|
+
.sort((left, right) => left.id.localeCompare(right.id)),
|
|
279
|
+
};
|
|
280
|
+
writeLine(JSON.stringify(output));
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (selections.length === 0) {
|
|
285
|
+
writeLine("No models available. Set API keys in environment variables.");
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (filtered.length === 0) {
|
|
289
|
+
writeLine(`No canonical models matching "${pattern}"`);
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const rows = filtered
|
|
294
|
+
.slice()
|
|
295
|
+
.sort((left, right) => left.record.id.localeCompare(right.record.id))
|
|
296
|
+
.map(({ record, model }) => [
|
|
297
|
+
record.id,
|
|
298
|
+
`${model.provider}/${model.id}`,
|
|
299
|
+
String(record.variants.length),
|
|
300
|
+
formatLimit(model.contextWindow),
|
|
301
|
+
formatLimit(model.maxTokens),
|
|
302
|
+
]);
|
|
303
|
+
for (const line of boxTable(
|
|
304
|
+
[
|
|
305
|
+
{ header: "canonical" },
|
|
306
|
+
{ header: "selected" },
|
|
307
|
+
{ header: "variants", align: "right" },
|
|
308
|
+
{ header: "context", align: "right" },
|
|
309
|
+
{ header: "max-out", align: "right" },
|
|
310
|
+
],
|
|
311
|
+
rows,
|
|
312
|
+
)) {
|
|
313
|
+
writeLine(line);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Options for {@link runModelsListing}: render the catalog from a caller-supplied
|
|
319
|
+
* registry. Loads extensions (CLI `-e` paths and configured `settings.extensions`)
|
|
320
|
+
* and discovers their providers before rendering so extension-contributed models
|
|
321
|
+
* appear (issue #905). The caller is responsible for refreshing built-in providers.
|
|
322
|
+
*/
|
|
323
|
+
export interface RunModelsListingOptions {
|
|
324
|
+
modelRegistry: ModelRegistry;
|
|
325
|
+
cwd: string;
|
|
326
|
+
action?: ModelsAction;
|
|
327
|
+
pattern?: string;
|
|
328
|
+
json?: boolean;
|
|
329
|
+
/** CLI-supplied extension paths (e.g. from `-e <path>`). */
|
|
330
|
+
additionalExtensionPaths?: string[];
|
|
331
|
+
/** Extension paths configured under `extensions:` in user settings. */
|
|
332
|
+
settingsExtensions?: string[];
|
|
333
|
+
/** Disabled extension ids from settings (`disabledExtensions`). */
|
|
334
|
+
disabledExtensionIds?: string[];
|
|
335
|
+
/** When true, skip discovery and only load `additionalExtensionPaths`. */
|
|
336
|
+
disableExtensionDiscovery?: boolean;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export async function runModelsListing(options: RunModelsListingOptions): Promise<void> {
|
|
340
|
+
const {
|
|
341
|
+
modelRegistry,
|
|
342
|
+
cwd,
|
|
343
|
+
action = "ls",
|
|
344
|
+
pattern,
|
|
345
|
+
json = false,
|
|
346
|
+
additionalExtensionPaths = [],
|
|
347
|
+
settingsExtensions = [],
|
|
348
|
+
disabledExtensionIds = [],
|
|
349
|
+
disableExtensionDiscovery = false,
|
|
350
|
+
} = options;
|
|
351
|
+
|
|
352
|
+
const eventBus = new EventBus();
|
|
353
|
+
const extensionsResult = disableExtensionDiscovery
|
|
354
|
+
? await loadExtensions(additionalExtensionPaths, cwd, eventBus)
|
|
355
|
+
: await discoverAndLoadExtensions(
|
|
356
|
+
[...additionalExtensionPaths, ...settingsExtensions],
|
|
357
|
+
cwd,
|
|
358
|
+
eventBus,
|
|
359
|
+
disabledExtensionIds,
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
for (const { path: extPath, error } of extensionsResult.errors) {
|
|
363
|
+
process.stderr.write(`Failed to load extension: ${extPath}: ${error}\n`);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// Mirror sdk.ts: drain pending provider registrations into the registry.
|
|
367
|
+
const activeSources = extensionsResult.extensions.map(extension => extension.path);
|
|
368
|
+
modelRegistry.syncExtensionSources(activeSources);
|
|
369
|
+
for (const sourceId of new Set(activeSources)) {
|
|
370
|
+
modelRegistry.clearSourceRegistrations(sourceId);
|
|
371
|
+
}
|
|
372
|
+
for (const { name, config, sourceId } of extensionsResult.runtime.pendingProviderRegistrations) {
|
|
373
|
+
modelRegistry.registerProvider(name, config, sourceId);
|
|
374
|
+
}
|
|
375
|
+
extensionsResult.runtime.pendingProviderRegistrations = [];
|
|
376
|
+
// Discover runtime (extension) provider catalogs now that they are registered.
|
|
377
|
+
await modelRegistry.refreshRuntimeProviders(action === "refresh" ? "online" : "online-if-uncached");
|
|
378
|
+
|
|
379
|
+
if (action === "canonical") {
|
|
380
|
+
renderCanonicalModels(modelRegistry, pattern, json);
|
|
381
|
+
} else {
|
|
382
|
+
renderProviderModels(modelRegistry, action, pattern, json);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Entry point for the standalone `omp models` command: bootstraps auth storage,
|
|
388
|
+
* settings, and the model registry, force/cache-refreshes built-in providers per
|
|
389
|
+
* the chosen action, then delegates to {@link runModelsListing}.
|
|
390
|
+
*/
|
|
391
|
+
export async function runModelsCommand(command: ModelsCommandArgs): Promise<void> {
|
|
392
|
+
const { action, pattern } = command;
|
|
393
|
+
const json = command.flags.json ?? false;
|
|
394
|
+
|
|
395
|
+
if (action === "find" && (!pattern || pattern.trim().length === 0)) {
|
|
396
|
+
process.stderr.write("`omp models find` requires a search substring, e.g. `omp models find minimax`\n");
|
|
397
|
+
process.exitCode = 1;
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const cwd = getProjectDir();
|
|
402
|
+
const authStorage = await discoverAuthStorage();
|
|
403
|
+
try {
|
|
404
|
+
const settings = await Settings.init({ cwd, configFiles: command.flags.config });
|
|
405
|
+
const modelRegistry = new ModelRegistry(authStorage);
|
|
406
|
+
|
|
407
|
+
if (action === "refresh" && !json && process.stderr.isTTY) {
|
|
408
|
+
process.stderr.write("Refreshing models from all providers…\n");
|
|
409
|
+
}
|
|
410
|
+
await modelRegistry.refresh(action === "refresh" ? "online" : "online-if-uncached");
|
|
411
|
+
|
|
412
|
+
const cliExtensionPaths = command.flags.noExtensions ? [] : (command.flags.extensions ?? []);
|
|
413
|
+
await runModelsListing({
|
|
414
|
+
modelRegistry,
|
|
415
|
+
cwd,
|
|
416
|
+
action,
|
|
417
|
+
pattern,
|
|
418
|
+
json,
|
|
419
|
+
additionalExtensionPaths: cliExtensionPaths,
|
|
420
|
+
settingsExtensions: settings.get("extensions") ?? [],
|
|
421
|
+
disabledExtensionIds: settings.get("disabledExtensions") ?? [],
|
|
422
|
+
disableExtensionDiscovery: Boolean(command.flags.noExtensions),
|
|
423
|
+
});
|
|
424
|
+
} finally {
|
|
425
|
+
authStorage.close();
|
|
426
|
+
}
|
|
427
|
+
}
|
package/src/cli-commands.ts
CHANGED
|
@@ -27,6 +27,7 @@ export const commands: CommandEntry[] = [
|
|
|
27
27
|
{ name: "grievances", load: () => import("./commands/grievances").then(m => m.default) },
|
|
28
28
|
{ name: "install", load: () => import("./commands/install").then(m => m.default) },
|
|
29
29
|
{ name: "join", load: () => import("./commands/join").then(m => m.default) },
|
|
30
|
+
{ name: "models", load: () => import("./commands/models").then(m => m.default) },
|
|
30
31
|
{ name: "plugin", load: () => import("./commands/plugin").then(m => m.default) },
|
|
31
32
|
{ name: "setup", load: () => import("./commands/setup").then(m => m.default) },
|
|
32
33
|
{ name: "shell", load: () => import("./commands/shell").then(m => m.default) },
|
|
@@ -36,6 +37,7 @@ export const commands: CommandEntry[] = [
|
|
|
36
37
|
{ name: "update", load: () => import("./commands/update").then(m => m.default) },
|
|
37
38
|
{ name: "usage", load: () => import("./commands/usage").then(m => m.default) },
|
|
38
39
|
{ name: "tiny-models", load: () => import("./commands/tiny-models").then(m => m.default) },
|
|
40
|
+
{ name: "token", load: () => import("./commands/token").then(m => m.default) },
|
|
39
41
|
{ name: "worktree", load: () => import("./commands/worktree").then(m => m.default), aliases: ["wt"] },
|
|
40
42
|
{ name: "search", load: () => import("./commands/web-search").then(m => m.default), aliases: ["q"] },
|
|
41
43
|
];
|
package/src/collab/host.ts
CHANGED
|
@@ -365,13 +365,8 @@ export class CollabHost {
|
|
|
365
365
|
const name = peer.name;
|
|
366
366
|
const content: string | (TextContent | ImageContent)[] =
|
|
367
367
|
images && images.length > 0 ? [{ type: "text", text }, ...images] : text;
|
|
368
|
-
const details: CollabPromptDetails
|
|
368
|
+
const details: CollabPromptDetails = { from: name };
|
|
369
369
|
if (this.#ctx.session.isStreaming) {
|
|
370
|
-
// Mid-turn guest prompts are steered: register the pending-display twin
|
|
371
|
-
// so queuedMessageCount reflects the queued steer (host pending bar +
|
|
372
|
-
// guests' "queued ×N" badge). The tag dequeues the entry when the agent
|
|
373
|
-
// consumes the message (mirrors the skill-prompt path).
|
|
374
|
-
details.__pendingDisplayTag = this.#ctx.session.enqueueCustomMessageDisplay(text, "steer");
|
|
375
370
|
this.#ctx.updatePendingMessagesDisplay();
|
|
376
371
|
this.#ctx.ui.requestRender();
|
|
377
372
|
this.#scheduleStateBroadcast();
|
|
@@ -385,7 +380,7 @@ export class CollabHost {
|
|
|
385
380
|
details,
|
|
386
381
|
attribution: "user",
|
|
387
382
|
},
|
|
388
|
-
{ streamingBehavior: "steer" },
|
|
383
|
+
{ streamingBehavior: "steer", queueChipText: text },
|
|
389
384
|
)
|
|
390
385
|
.catch(err => {
|
|
391
386
|
logger.warn("collab guest prompt failed", { error: String(err) });
|
|
@@ -416,21 +411,23 @@ export class CollabHost {
|
|
|
416
411
|
|
|
417
412
|
#buildState(): CollabSessionState {
|
|
418
413
|
const session = this.#ctx.session;
|
|
419
|
-
// Context numbers come from the status line's breakdown
|
|
420
|
-
//
|
|
421
|
-
//
|
|
414
|
+
// Context numbers come from the status line's memoized breakdown so guests
|
|
415
|
+
// render exactly the same anchored, provider-real count the host's own
|
|
416
|
+
// status line shows.
|
|
422
417
|
const breakdown = this.#ctx.statusLine.getCachedContextBreakdown();
|
|
418
|
+
const tokens = breakdown.usedTokens;
|
|
423
419
|
return {
|
|
424
420
|
isStreaming: session.isStreaming,
|
|
421
|
+
isAborting: session.isAborting,
|
|
425
422
|
queuedMessageCount: session.queuedMessageCount,
|
|
426
423
|
sessionName: session.sessionName,
|
|
427
424
|
cwd: this.#ctx.sessionManager.getCwd(),
|
|
428
425
|
model: session.model,
|
|
429
426
|
thinkingLevel: session.thinkingLevel,
|
|
430
427
|
contextUsage: {
|
|
431
|
-
tokens
|
|
428
|
+
tokens,
|
|
432
429
|
contextWindow: breakdown.contextWindow,
|
|
433
|
-
percent: breakdown.contextWindow > 0 ? (
|
|
430
|
+
percent: tokens !== null && breakdown.contextWindow > 0 ? (tokens / breakdown.contextWindow) * 100 : null,
|
|
434
431
|
},
|
|
435
432
|
participants: this.participants,
|
|
436
433
|
};
|
package/src/commands/launch.ts
CHANGED
|
@@ -124,9 +124,6 @@ export default class Index extends Command {
|
|
|
124
124
|
export: Flags.string({
|
|
125
125
|
description: "Export session file to HTML and exit",
|
|
126
126
|
}),
|
|
127
|
-
"list-models": Flags.string({
|
|
128
|
-
description: "List available models (with optional fuzzy search)",
|
|
129
|
-
}),
|
|
130
127
|
"no-title": Flags.boolean({
|
|
131
128
|
description: "Disable title auto-generation",
|
|
132
129
|
}),
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List, search, and refresh available models.
|
|
3
|
+
*/
|
|
4
|
+
import { APP_NAME } from "@oh-my-pi/pi-utils";
|
|
5
|
+
import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
|
|
6
|
+
import { resolveModelsArgs, runModelsCommand } from "../cli/models-cli";
|
|
7
|
+
|
|
8
|
+
export default class Models extends Command {
|
|
9
|
+
static description = "List, search, and refresh available models";
|
|
10
|
+
|
|
11
|
+
static args = {
|
|
12
|
+
action: Args.string({
|
|
13
|
+
description: "ls (default) | find | refresh | canonical | <provider>",
|
|
14
|
+
required: false,
|
|
15
|
+
}),
|
|
16
|
+
pattern: Args.string({
|
|
17
|
+
description: "Filter/search substring, or provider name (required for find)",
|
|
18
|
+
required: false,
|
|
19
|
+
}),
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
static flags = {
|
|
23
|
+
json: Flags.boolean({ description: "Output JSON" }),
|
|
24
|
+
extension: Flags.string({
|
|
25
|
+
char: "e",
|
|
26
|
+
description: "Load an extension file before listing (repeatable)",
|
|
27
|
+
multiple: true,
|
|
28
|
+
}),
|
|
29
|
+
"no-extensions": Flags.boolean({
|
|
30
|
+
description: "Disable extension discovery (explicit -e paths still work)",
|
|
31
|
+
}),
|
|
32
|
+
config: Flags.string({
|
|
33
|
+
description: "Load an extra config.yml-style overlay for this run (repeatable)",
|
|
34
|
+
multiple: true,
|
|
35
|
+
}),
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
static examples = [
|
|
39
|
+
`# List every available model, grouped by provider\n ${APP_NAME} models`,
|
|
40
|
+
`# List one provider's models (any provider name works)\n ${APP_NAME} models openai-codex`,
|
|
41
|
+
`# Find models by substring\n ${APP_NAME} models find minimax`,
|
|
42
|
+
`# Force a fresh catalog fetch (replaces rm -rf ~/.omp/models.db)\n ${APP_NAME} models refresh`,
|
|
43
|
+
`# Show the coalesced canonical model view\n ${APP_NAME} models canonical`,
|
|
44
|
+
`# Machine-readable output\n ${APP_NAME} models --json`,
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
async run(): Promise<void> {
|
|
48
|
+
const { args, flags } = await this.parse(Models);
|
|
49
|
+
const { action, pattern } = resolveModelsArgs(args.action, args.pattern);
|
|
50
|
+
await runModelsCommand({
|
|
51
|
+
action,
|
|
52
|
+
pattern,
|
|
53
|
+
flags: {
|
|
54
|
+
json: flags.json,
|
|
55
|
+
extensions: flags.extension,
|
|
56
|
+
noExtensions: flags["no-extensions"],
|
|
57
|
+
config: flags.config,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get the API key or OAuth token for a provider.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { PROVIDER_REGISTRY } from "@oh-my-pi/pi-ai";
|
|
6
|
+
import { Args, Command, Flags } from "@oh-my-pi/pi-utils/cli";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import { isAuthenticated, ModelRegistry } from "../config/model-registry";
|
|
9
|
+
import { discoverAuthStorage } from "../sdk";
|
|
10
|
+
|
|
11
|
+
export default class Token extends Command {
|
|
12
|
+
static description = "Get the API key or OAuth token for a provider";
|
|
13
|
+
|
|
14
|
+
static args = {
|
|
15
|
+
provider: Args.string({
|
|
16
|
+
description: "Provider ID (e.g. anthropic, openai)",
|
|
17
|
+
required: true,
|
|
18
|
+
}),
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
static flags = {
|
|
22
|
+
raw: Flags.boolean({
|
|
23
|
+
description: "Output the raw credential value without parsing nested JSON structures",
|
|
24
|
+
default: false,
|
|
25
|
+
}),
|
|
26
|
+
"force-refresh": Flags.boolean({
|
|
27
|
+
description: "Force refresh the OAuth token even if it has not expired",
|
|
28
|
+
default: false,
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
static examples = [
|
|
33
|
+
"# Get API key for Anthropic\n omp token anthropic",
|
|
34
|
+
"# Get raw Copilot credential JSON\n omp token github-copilot --raw",
|
|
35
|
+
"# Force refresh and get Gemini CLI token\n omp token google-gemini-cli --force-refresh",
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
async run(): Promise<void> {
|
|
39
|
+
const { args, flags } = await this.parse(Token);
|
|
40
|
+
const providerName = args.provider ?? "";
|
|
41
|
+
const provider = providerName.toLowerCase();
|
|
42
|
+
|
|
43
|
+
const authStorage = await discoverAuthStorage();
|
|
44
|
+
const modelRegistry = new ModelRegistry(authStorage);
|
|
45
|
+
|
|
46
|
+
// Resolve the API key / token
|
|
47
|
+
const apiKey = await modelRegistry.getApiKeyForProvider(provider, undefined, {
|
|
48
|
+
forceRefresh: flags["force-refresh"],
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (!isAuthenticated(apiKey)) {
|
|
52
|
+
// Find all active/configured providers
|
|
53
|
+
const activeProviders = new Set<string>();
|
|
54
|
+
for (const p of PROVIDER_REGISTRY) {
|
|
55
|
+
if (authStorage.hasAuth(p.id)) {
|
|
56
|
+
activeProviders.add(p.id);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const all = authStorage.getAll();
|
|
60
|
+
for (const p in all) {
|
|
61
|
+
if (authStorage.hasAuth(p)) {
|
|
62
|
+
activeProviders.add(p);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const msg = `No active credential found for provider "${providerName}".`;
|
|
67
|
+
process.stderr.write(`${chalk.red(msg)}\n`);
|
|
68
|
+
if (activeProviders.size > 0) {
|
|
69
|
+
process.stderr.write(`Configured providers: ${Array.from(activeProviders).sort().join(", ")}\n`);
|
|
70
|
+
}
|
|
71
|
+
process.exitCode = 1;
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (!flags.raw) {
|
|
76
|
+
try {
|
|
77
|
+
const parsed = JSON.parse(apiKey);
|
|
78
|
+
if (parsed && typeof parsed === "object" && typeof parsed.token === "string") {
|
|
79
|
+
process.stdout.write(`${parsed.token}\n`);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
} catch {
|
|
83
|
+
// Not a JSON string, print as-is
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
process.stdout.write(`${apiKey}\n`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
2
|
-
import
|
|
2
|
+
import { z } from "zod/v4";
|
|
3
3
|
import analyzeFilePrompt from "../../../commit/agentic/prompts/analyze-file.md" with { type: "text" };
|
|
4
4
|
import type { CommitAgentState } from "../../../commit/agentic/state";
|
|
5
5
|
import type { NumstatEntry } from "../../../commit/types";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { z } from "zod/v4";
|
|
2
2
|
import type { CommitAgentState, GitOverviewSnapshot } from "../../../commit/agentic/state";
|
|
3
3
|
import { extractScopeCandidates } from "../../../commit/analysis/scope";
|
|
4
4
|
import type { CustomTool } from "../../../extensibility/custom-tools/types";
|