@entelligentsia/forgecli 0.8.4 → 0.9.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/CHANGELOG.md +61 -0
- package/README.md +165 -2
- package/dist/bin/argv.d.ts +2 -2
- package/dist/bin/argv.js +17 -0
- package/dist/bin/argv.js.map +1 -1
- package/dist/bin/config.d.ts +69 -0
- package/dist/bin/config.js +315 -0
- package/dist/bin/config.js.map +1 -0
- package/dist/bin/doctor.d.ts +1 -0
- package/dist/bin/doctor.js +12 -0
- package/dist/bin/doctor.js.map +1 -1
- package/dist/bin/forge.js +7 -0
- package/dist/bin/forge.js.map +1 -1
- package/dist/extensions/forgecli/config-command.d.ts +8 -0
- package/dist/extensions/forgecli/config-command.js +66 -0
- package/dist/extensions/forgecli/config-command.js.map +1 -0
- package/dist/extensions/forgecli/config-layer.d.ts +38 -0
- package/dist/extensions/forgecli/config-layer.js +68 -0
- package/dist/extensions/forgecli/config-layer.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/component.d.ts +35 -0
- package/dist/extensions/forgecli/config-tui/component.js +236 -0
- package/dist/extensions/forgecli/config-tui/component.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/handler.d.ts +40 -0
- package/dist/extensions/forgecli/config-tui/handler.js +240 -0
- package/dist/extensions/forgecli/config-tui/handler.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/index.d.ts +5 -0
- package/dist/extensions/forgecli/config-tui/index.js +5 -0
- package/dist/extensions/forgecli/config-tui/index.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/keys.d.ts +26 -0
- package/dist/extensions/forgecli/config-tui/keys.js +33 -0
- package/dist/extensions/forgecli/config-tui/keys.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/plugin-config-reader.d.ts +23 -0
- package/dist/extensions/forgecli/config-tui/plugin-config-reader.js +58 -0
- package/dist/extensions/forgecli/config-tui/plugin-config-reader.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/advanced-menu.d.ts +7 -0
- package/dist/extensions/forgecli/config-tui/screens/advanced-menu.js +83 -0
- package/dist/extensions/forgecli/config-tui/screens/advanced-menu.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/confirm-quit.d.ts +11 -0
- package/dist/extensions/forgecli/config-tui/screens/confirm-quit.js +54 -0
- package/dist/extensions/forgecli/config-tui/screens/confirm-quit.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/override-editor.d.ts +11 -0
- package/dist/extensions/forgecli/config-tui/screens/override-editor.js +233 -0
- package/dist/extensions/forgecli/config-tui/screens/override-editor.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/overrides-list-phases.d.ts +7 -0
- package/dist/extensions/forgecli/config-tui/screens/overrides-list-phases.js +91 -0
- package/dist/extensions/forgecli/config-tui/screens/overrides-list-phases.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/overrides-list.d.ts +7 -0
- package/dist/extensions/forgecli/config-tui/screens/overrides-list.js +71 -0
- package/dist/extensions/forgecli/config-tui/screens/overrides-list.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/persona-editor.d.ts +10 -0
- package/dist/extensions/forgecli/config-tui/screens/persona-editor.js +182 -0
- package/dist/extensions/forgecli/config-tui/screens/persona-editor.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/persona-picker.d.ts +7 -0
- package/dist/extensions/forgecli/config-tui/screens/persona-picker.js +76 -0
- package/dist/extensions/forgecli/config-tui/screens/persona-picker.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/personas-list.d.ts +7 -0
- package/dist/extensions/forgecli/config-tui/screens/personas-list.js +98 -0
- package/dist/extensions/forgecli/config-tui/screens/personas-list.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/shared.d.ts +29 -0
- package/dist/extensions/forgecli/config-tui/screens/shared.js +100 -0
- package/dist/extensions/forgecli/config-tui/screens/shared.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/show-resolved.d.ts +23 -0
- package/dist/extensions/forgecli/config-tui/screens/show-resolved.js +128 -0
- package/dist/extensions/forgecli/config-tui/screens/show-resolved.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/tier-menu.d.ts +7 -0
- package/dist/extensions/forgecli/config-tui/screens/tier-menu.js +135 -0
- package/dist/extensions/forgecli/config-tui/screens/tier-menu.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/tier-picker.d.ts +9 -0
- package/dist/extensions/forgecli/config-tui/screens/tier-picker.js +122 -0
- package/dist/extensions/forgecli/config-tui/screens/tier-picker.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens/types.d.ts +24 -0
- package/dist/extensions/forgecli/config-tui/screens/types.js +5 -0
- package/dist/extensions/forgecli/config-tui/screens/types.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/screens.d.ts +24 -0
- package/dist/extensions/forgecli/config-tui/screens.js +78 -0
- package/dist/extensions/forgecli/config-tui/screens.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state/buffer.d.ts +11 -0
- package/dist/extensions/forgecli/config-tui/state/buffer.js +91 -0
- package/dist/extensions/forgecli/config-tui/state/buffer.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state/constants.d.ts +4 -0
- package/dist/extensions/forgecli/config-tui/state/constants.js +14 -0
- package/dist/extensions/forgecli/config-tui/state/constants.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state/index.d.ts +6 -0
- package/dist/extensions/forgecli/config-tui/state/index.js +9 -0
- package/dist/extensions/forgecli/config-tui/state/index.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state/init.d.ts +2 -0
- package/dist/extensions/forgecli/config-tui/state/init.js +30 -0
- package/dist/extensions/forgecli/config-tui/state/init.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state/model.d.ts +192 -0
- package/dist/extensions/forgecli/config-tui/state/model.js +4 -0
- package/dist/extensions/forgecli/config-tui/state/model.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state/reducer.d.ts +2 -0
- package/dist/extensions/forgecli/config-tui/state/reducer.js +212 -0
- package/dist/extensions/forgecli/config-tui/state/reducer.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state/selectors.d.ts +91 -0
- package/dist/extensions/forgecli/config-tui/state/selectors.js +231 -0
- package/dist/extensions/forgecli/config-tui/state/selectors.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/state.d.ts +6 -0
- package/dist/extensions/forgecli/config-tui/state.js +11 -0
- package/dist/extensions/forgecli/config-tui/state.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/theme.d.ts +37 -0
- package/dist/extensions/forgecli/config-tui/theme.js +88 -0
- package/dist/extensions/forgecli/config-tui/theme.js.map +1 -0
- package/dist/extensions/forgecli/config-tui/tier-meta.d.ts +28 -0
- package/dist/extensions/forgecli/config-tui/tier-meta.js +69 -0
- package/dist/extensions/forgecli/config-tui/tier-meta.js.map +1 -0
- package/dist/extensions/forgecli/config-writer.d.ts +16 -0
- package/dist/extensions/forgecli/config-writer.js +63 -0
- package/dist/extensions/forgecli/config-writer.js.map +1 -0
- package/dist/extensions/forgecli/fix-bug.js +85 -1
- package/dist/extensions/forgecli/fix-bug.js.map +1 -1
- package/dist/extensions/forgecli/forge-cli-schema.json +54 -0
- package/dist/extensions/forgecli/forge-commands.js +3 -8
- package/dist/extensions/forgecli/forge-commands.js.map +1 -1
- package/dist/extensions/forgecli/forge-subagent.d.ts +13 -0
- package/dist/extensions/forgecli/forge-subagent.js +19 -0
- package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
- package/dist/extensions/forgecli/index.js +16 -0
- package/dist/extensions/forgecli/index.js.map +1 -1
- package/dist/extensions/forgecli/input-router.d.ts +33 -0
- package/dist/extensions/forgecli/input-router.js +133 -0
- package/dist/extensions/forgecli/input-router.js.map +1 -0
- package/dist/extensions/forgecli/model-resolver.d.ts +32 -0
- package/dist/extensions/forgecli/model-resolver.js +65 -0
- package/dist/extensions/forgecli/model-resolver.js.map +1 -0
- package/dist/extensions/forgecli/model-validator.d.ts +29 -0
- package/dist/extensions/forgecli/model-validator.js +107 -0
- package/dist/extensions/forgecli/model-validator.js.map +1 -0
- package/dist/extensions/forgecli/run-sprint.js +59 -0
- package/dist/extensions/forgecli/run-sprint.js.map +1 -1
- package/dist/extensions/forgecli/run-task.js +93 -1
- package/dist/extensions/forgecli/run-task.js.map +1 -1
- package/dist/extensions/forgecli/thread-switcher.js +5 -2
- package/dist/extensions/forgecli/thread-switcher.js.map +1 -1
- package/dist/extensions/forgecli/whats-new-widget.js +5 -2
- package/dist/extensions/forgecli/whats-new-widget.js.map +1 -1
- package/package.json +11 -3
- package/dist/extensions/forgecli/review-command.d.ts +0 -2
- package/dist/extensions/forgecli/review-command.js +0 -184
- package/dist/extensions/forgecli/review-command.js.map +0 -1
- package/dist/forge-payload/.tools/banners.cjs +0 -435
- package/dist/forge-payload/.tools/build-context-pack.cjs +0 -290
- package/dist/forge-payload/.tools/build-init-context.cjs +0 -322
- package/dist/forge-payload/.tools/build-overlay.cjs +0 -326
- package/dist/forge-payload/.tools/build-persona-pack.cjs +0 -226
- package/dist/forge-payload/.tools/collate.cjs +0 -1041
- package/dist/forge-payload/.tools/generation-manifest.cjs +0 -311
- package/dist/forge-payload/.tools/lib/forge-root.cjs +0 -59
- package/dist/forge-payload/.tools/lib/paths.cjs +0 -29
- package/dist/forge-payload/.tools/lib/pricing.cjs +0 -165
- package/dist/forge-payload/.tools/lib/project-root.cjs +0 -32
- package/dist/forge-payload/.tools/lib/result.js +0 -40
- package/dist/forge-payload/.tools/lib/store-facade.cjs +0 -162
- package/dist/forge-payload/.tools/lib/store-nlp.cjs +0 -250
- package/dist/forge-payload/.tools/lib/store-query-exec.cjs +0 -272
- package/dist/forge-payload/.tools/lib/validate.js +0 -141
- package/dist/forge-payload/.tools/manage-config.cjs +0 -340
- package/dist/forge-payload/.tools/manage-versions.cjs +0 -365
- package/dist/forge-payload/.tools/package.json +0 -3
- package/dist/forge-payload/.tools/parse-gates.cjs +0 -151
- package/dist/forge-payload/.tools/parse-verdict.cjs +0 -67
- package/dist/forge-payload/.tools/preflight-gate.cjs +0 -350
- package/dist/forge-payload/.tools/prompts/sprint-plan-prompt.md +0 -70
- package/dist/forge-payload/.tools/schemas/task-list.schema.json +0 -53
- package/dist/forge-payload/.tools/seed-store.cjs +0 -237
- package/dist/forge-payload/.tools/store-cli.cjs +0 -1226
- package/dist/forge-payload/.tools/store-query.cjs +0 -319
- package/dist/forge-payload/.tools/store.cjs +0 -315
- package/dist/forge-payload/.tools/substitute-placeholders.cjs +0 -625
- package/dist/forge-payload/.tools/validate-store.cjs +0 -593
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ConfigTuiState } from "../state/model.js";
|
|
2
|
+
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
/** Themed horizontal rule spanning the full width. */
|
|
4
|
+
export declare function rule(width: number, theme: Theme): string;
|
|
5
|
+
/**
|
|
6
|
+
* Compute a windowed slice of `items` around `cursor` so that long lists fit
|
|
7
|
+
* inside `maxRows`. Returns the visible items, their absolute start index,
|
|
8
|
+
* and scroll indicator counts. Default window: 10 rows.
|
|
9
|
+
*/
|
|
10
|
+
export declare function windowList<T>(items: T[], cursor: number, maxRows?: number): {
|
|
11
|
+
visible: T[];
|
|
12
|
+
start: number;
|
|
13
|
+
aboveCount: number;
|
|
14
|
+
belowCount: number;
|
|
15
|
+
};
|
|
16
|
+
export declare function authBadgeFor(state: ConfigTuiState, provider: string, theme: Theme): string;
|
|
17
|
+
export declare function authStatusLine(state: ConfigTuiState, theme: Theme): string;
|
|
18
|
+
export declare function resolvedSummary(state: ConfigTuiState, theme: Theme): string;
|
|
19
|
+
export declare function formatOverride(override: string | {
|
|
20
|
+
provider: string;
|
|
21
|
+
model: string;
|
|
22
|
+
} | undefined): string;
|
|
23
|
+
/** Render the four-rule cascade footer in plain English.
|
|
24
|
+
* This is the "How models get picked" section from Screen 3. */
|
|
25
|
+
export declare function cascadeFooter(width: number, theme: Theme): string[];
|
|
26
|
+
/** Render a tier badge like "Heavy", "Standard", "Light" in themed color. */
|
|
27
|
+
export declare function tierBadge(tier: "heavy" | "standard" | "light", theme: Theme): string;
|
|
28
|
+
/** Width-safe final guard: truncate every line to the given terminal width. */
|
|
29
|
+
export declare function safeLines(lines: string[], width: number): string[];
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// Shared screen rendering utilities — windowList, formatOverride, and themed helpers.
|
|
2
|
+
// Split from screens.ts (Phase 1). Phase 3: theming applied to all visible strings.
|
|
3
|
+
import { authBadge, muted, rule as themedRule, error as themedError, truncateLines } from "../theme.js";
|
|
4
|
+
/** Themed horizontal rule spanning the full width. */
|
|
5
|
+
export function rule(width, theme) {
|
|
6
|
+
return themedRule(width, theme);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Compute a windowed slice of `items` around `cursor` so that long lists fit
|
|
10
|
+
* inside `maxRows`. Returns the visible items, their absolute start index,
|
|
11
|
+
* and scroll indicator counts. Default window: 10 rows.
|
|
12
|
+
*/
|
|
13
|
+
export function windowList(items, cursor, maxRows = 10) {
|
|
14
|
+
if (items.length <= maxRows) {
|
|
15
|
+
return { visible: items, start: 0, aboveCount: 0, belowCount: 0 };
|
|
16
|
+
}
|
|
17
|
+
// Keep cursor in the middle when possible.
|
|
18
|
+
const half = Math.floor(maxRows / 2);
|
|
19
|
+
let start = Math.max(0, cursor - half);
|
|
20
|
+
if (start + maxRows > items.length)
|
|
21
|
+
start = items.length - maxRows;
|
|
22
|
+
return {
|
|
23
|
+
visible: items.slice(start, start + maxRows),
|
|
24
|
+
start,
|
|
25
|
+
aboveCount: start,
|
|
26
|
+
belowCount: items.length - start - maxRows,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function authBadgeFor(state, provider, theme) {
|
|
30
|
+
return authBadge(state.authenticatedProviders.includes(provider), theme);
|
|
31
|
+
}
|
|
32
|
+
export function authStatusLine(state, theme) {
|
|
33
|
+
// If auth discovery failed entirely, surface the error.
|
|
34
|
+
if (state.authError) {
|
|
35
|
+
return themedError(` Auth error ${state.authError}`, theme);
|
|
36
|
+
}
|
|
37
|
+
// Stable ordering: alphabetical by provider name.
|
|
38
|
+
const providers = [...new Set([
|
|
39
|
+
...state.authenticatedProviders,
|
|
40
|
+
...state.availableModels.map((m) => m.provider),
|
|
41
|
+
])].sort();
|
|
42
|
+
if (providers.length === 0)
|
|
43
|
+
return muted(" Auth status (no providers detected)", theme);
|
|
44
|
+
const cells = providers.map((p) => `${p} ${authBadgeFor(state, p, theme)}`);
|
|
45
|
+
return muted(` Auth status ${cells.join(" ")}`, theme);
|
|
46
|
+
}
|
|
47
|
+
export function resolvedSummary(state, theme) {
|
|
48
|
+
const personas = listResolvedPersonasInner(state);
|
|
49
|
+
if (personas.length === 0) {
|
|
50
|
+
return muted(" Resolved all personas inherit pi current model", theme);
|
|
51
|
+
}
|
|
52
|
+
const routable = personas.filter((p) => state.availableModels.some((m) => m.provider === p.provider && m.id === p.model)).length;
|
|
53
|
+
const total = personas.length;
|
|
54
|
+
return muted(` Resolved ${total} persona-model assignment${total === 1 ? "" : "s"} · ${routable} routable`, theme);
|
|
55
|
+
}
|
|
56
|
+
function listResolvedPersonasInner(state) {
|
|
57
|
+
const out = new Map();
|
|
58
|
+
const projectMap = state.buffer.project["persona-models"] ?? {};
|
|
59
|
+
const globalMap = state.buffer.global["persona-models"] ?? {};
|
|
60
|
+
for (const [persona, entry] of Object.entries(globalMap)) {
|
|
61
|
+
out.set(persona, { persona, provider: entry.provider, model: entry.model, source: "L1" });
|
|
62
|
+
}
|
|
63
|
+
for (const [persona, entry] of Object.entries(projectMap)) {
|
|
64
|
+
out.set(persona, { persona, provider: entry.provider, model: entry.model, source: "L2" });
|
|
65
|
+
}
|
|
66
|
+
return [...out.values()].sort((a, b) => a.persona.localeCompare(b.persona));
|
|
67
|
+
}
|
|
68
|
+
export function formatOverride(override) {
|
|
69
|
+
if (override === undefined)
|
|
70
|
+
return "(none)";
|
|
71
|
+
if (typeof override === "string")
|
|
72
|
+
return `"${override}"`;
|
|
73
|
+
return `{${override.provider}:${override.model}}`;
|
|
74
|
+
}
|
|
75
|
+
/** Render the four-rule cascade footer in plain English.
|
|
76
|
+
* This is the "How models get picked" section from Screen 3. */
|
|
77
|
+
export function cascadeFooter(width, theme) {
|
|
78
|
+
const m = (text) => theme.fg("muted", text);
|
|
79
|
+
const a = (text) => theme.fg("accent", text);
|
|
80
|
+
return [
|
|
81
|
+
"",
|
|
82
|
+
a("How models get picked"),
|
|
83
|
+
theme.fg("border", "─".repeat(Math.max(1, width))),
|
|
84
|
+
m("Each step's persona looks for an override at four levels (most specific wins):"),
|
|
85
|
+
m(" 1. A model set just for this step ") + a("(Step override)"),
|
|
86
|
+
m(" 2. A model set just for this persona ") + a("(Per-persona override)"),
|
|
87
|
+
m(" 3. The tier baseline you set above ") + a("(Heavy / Standard / Light)"),
|
|
88
|
+
m(" 4. Whatever model pi is currently running on ") + m("(falls back automatically)"),
|
|
89
|
+
];
|
|
90
|
+
}
|
|
91
|
+
/** Render a tier badge like "Heavy", "Standard", "Light" in themed color. */
|
|
92
|
+
export function tierBadge(tier, theme) {
|
|
93
|
+
const labels = { heavy: "Heavy", standard: "Standard", light: "Light" };
|
|
94
|
+
return theme.fg("accent", labels[tier] ?? tier);
|
|
95
|
+
}
|
|
96
|
+
/** Width-safe final guard: truncate every line to the given terminal width. */
|
|
97
|
+
export function safeLines(lines, width) {
|
|
98
|
+
return truncateLines(lines, width);
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/config-tui/screens/shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ConfigTuiState } from "../state/model.js";
|
|
2
|
+
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { InputResult, Screen } from "./types.js";
|
|
4
|
+
export interface ResolvedRow {
|
|
5
|
+
index: number;
|
|
6
|
+
role: string;
|
|
7
|
+
persona: string;
|
|
8
|
+
resolved: string;
|
|
9
|
+
source: string;
|
|
10
|
+
available: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Legacy compute helper — kept for backward compatibility in barrel re-export.
|
|
14
|
+
* Prefer getPhaseTable() for new code.
|
|
15
|
+
*/
|
|
16
|
+
export declare function computeResolvedRows(state: ConfigTuiState): Array<{
|
|
17
|
+
pipeline: string;
|
|
18
|
+
rows: ResolvedRow[];
|
|
19
|
+
}>;
|
|
20
|
+
export declare class ShowResolvedScreen implements Screen {
|
|
21
|
+
render(state: ConfigTuiState, width: number, theme: Theme): string[];
|
|
22
|
+
handleInput(data: string, state: ConfigTuiState): InputResult;
|
|
23
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// Show-resolved screen — "Show what runs at each step" (Screen 3).
|
|
2
|
+
// Phase C: rewritten to the phase-table format with emoji + persona names +
|
|
3
|
+
// plain-English tier-source labels + cascade footer.
|
|
4
|
+
// No more L1/L2 badges, no more "cascade" jargon.
|
|
5
|
+
import { Key, matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
6
|
+
import { getActiveView, getPhaseTable } from "../state/selectors.js";
|
|
7
|
+
import { PHASE_PERSONA_TABLE } from "../tier-meta.js";
|
|
8
|
+
import { resolveModelForPhase } from "../../model-resolver.js";
|
|
9
|
+
import { rule, windowList, safeLines, cascadeFooter } from "./shared.js";
|
|
10
|
+
import { padRight, accentBold, muted, cursor } from "../theme.js";
|
|
11
|
+
/**
|
|
12
|
+
* Legacy compute helper — kept for backward compatibility in barrel re-export.
|
|
13
|
+
* Prefer getPhaseTable() for new code.
|
|
14
|
+
*/
|
|
15
|
+
export function computeResolvedRows(state) {
|
|
16
|
+
const pipelineNames = state.pipelineCatalogue
|
|
17
|
+
? state.pipelineCatalogue
|
|
18
|
+
: ["default"];
|
|
19
|
+
return pipelineNames.map((pipeline) => ({
|
|
20
|
+
pipeline,
|
|
21
|
+
rows: PHASE_PERSONA_TABLE.map((phase, i) => {
|
|
22
|
+
const result = resolveModelForPhase(pipeline, phase.role, phase.personaNoun, {
|
|
23
|
+
...state.buffer.global,
|
|
24
|
+
...state.buffer.project,
|
|
25
|
+
_global: state.buffer.global,
|
|
26
|
+
_project: state.buffer.project,
|
|
27
|
+
});
|
|
28
|
+
const resolved = result.model
|
|
29
|
+
? `${result.model.provider}:${result.model.model}`
|
|
30
|
+
: "(inherit pi current)";
|
|
31
|
+
const available = result.model
|
|
32
|
+
? state.availableModels.some((m) => m.provider === result.model.provider && m.id === result.model.model)
|
|
33
|
+
: true;
|
|
34
|
+
return {
|
|
35
|
+
index: i,
|
|
36
|
+
role: phase.role,
|
|
37
|
+
persona: phase.personaNoun,
|
|
38
|
+
resolved,
|
|
39
|
+
source: result.source,
|
|
40
|
+
available,
|
|
41
|
+
};
|
|
42
|
+
}),
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Build a single table row with ANSI-safe column truncation.
|
|
47
|
+
* Each column value is padded or truncated to its allocated visible width.
|
|
48
|
+
* Truncated values have their trailing ANSI resets stripped (truncateToWidth
|
|
49
|
+
* appends \\x1b[0m to close styles; since we control the content, this is
|
|
50
|
+
* safe to strip).
|
|
51
|
+
*/
|
|
52
|
+
function buildRow(parts) {
|
|
53
|
+
return parts.map(({ text, width }) => {
|
|
54
|
+
const vis = visibleWidth(text);
|
|
55
|
+
if (vis > width) {
|
|
56
|
+
// Truncate and strip trailing ANSI reset that truncateToWidth adds
|
|
57
|
+
const raw = truncateToWidth(text, width, "");
|
|
58
|
+
return raw.replace(/\x1b\[0m$/, "");
|
|
59
|
+
}
|
|
60
|
+
// Pad with spaces to hit the target visible width
|
|
61
|
+
return text + " ".repeat(width - vis);
|
|
62
|
+
}).join(" ");
|
|
63
|
+
}
|
|
64
|
+
export class ShowResolvedScreen {
|
|
65
|
+
render(state, width, theme) {
|
|
66
|
+
const view = getActiveView(state);
|
|
67
|
+
if (view.kind !== "show-resolved") {
|
|
68
|
+
return ["(show-resolved called with wrong active view)"];
|
|
69
|
+
}
|
|
70
|
+
const lines = [];
|
|
71
|
+
// ── Column sizing ──────────────────────────────────────────────────
|
|
72
|
+
// Reserve enough room for source labels. Longest: "Falls back to pi current" = 24.
|
|
73
|
+
const minSource = 24;
|
|
74
|
+
const leading = 4; // " {cursor} "
|
|
75
|
+
const gap = 3; // 3 single-space gaps between 4 columns
|
|
76
|
+
// stepCol: longest step is "review-plan"/"review-code" = 11 vis
|
|
77
|
+
// Use 11 so model gets more room, and step names fit exactly.
|
|
78
|
+
const stepCol = 11;
|
|
79
|
+
// personaCol: emoji(2 vis) + space + name; names up to ~12 chars
|
|
80
|
+
// padOrTruncate handles overflow gracefully.
|
|
81
|
+
const personaCol = 14;
|
|
82
|
+
// modelCol: flexible; long models get truncated with visible ellipsis
|
|
83
|
+
const modelCol = Math.max(16, width - leading - gap - stepCol - personaCol - minSource);
|
|
84
|
+
// ── Title ───────────────────────────────────────────────────────────
|
|
85
|
+
lines.push(accentBold("forge config › current setup", theme));
|
|
86
|
+
lines.push(rule(width, theme));
|
|
87
|
+
// ── Column headers ─────────────────────────────────────────────────
|
|
88
|
+
lines.push(` ${muted(padRight("Step", stepCol), theme)} ${muted(padRight("Persona", personaCol), theme)} ${muted(padRight("Model", modelCol), theme)} ${muted("Source", theme)}`);
|
|
89
|
+
// ── Phase rows ─────────────────────────────────────────────────────
|
|
90
|
+
const rows = getPhaseTable(state);
|
|
91
|
+
const win = windowList(rows, view.cursor, 10);
|
|
92
|
+
if (win.aboveCount > 0)
|
|
93
|
+
lines.push(muted(` ↑ ${win.aboveCount} row(s) above`, theme));
|
|
94
|
+
for (let i = 0; i < win.visible.length; i++) {
|
|
95
|
+
const row = win.visible[i];
|
|
96
|
+
const absoluteIdx = win.start + i;
|
|
97
|
+
const cur = cursor(absoluteIdx === view.cursor, theme);
|
|
98
|
+
const rowStr = buildRow([
|
|
99
|
+
{ text: row.role, width: stepCol },
|
|
100
|
+
{ text: `${row.personaEmoji} ${row.persona}`, width: personaCol },
|
|
101
|
+
{ text: row.resolved, width: modelCol },
|
|
102
|
+
// Source column is the last column — no fixed width needed
|
|
103
|
+
]);
|
|
104
|
+
lines.push(` ${cur} ${rowStr} ${row.sourceLabel}`);
|
|
105
|
+
}
|
|
106
|
+
if (win.belowCount > 0)
|
|
107
|
+
lines.push(muted(` ↓ ${win.belowCount} row(s) below`, theme));
|
|
108
|
+
// ── Cascade footer ─────────────────────────────────────────────────
|
|
109
|
+
lines.push(...cascadeFooter(width, theme));
|
|
110
|
+
// ── Navigation ─────────────────────────────────────────────────────
|
|
111
|
+
lines.push("");
|
|
112
|
+
lines.push(muted(` ↑/↓ scroll esc back q quit`, theme));
|
|
113
|
+
return safeLines(lines, width);
|
|
114
|
+
}
|
|
115
|
+
handleInput(data, state) {
|
|
116
|
+
const view = getActiveView(state);
|
|
117
|
+
if (view.kind !== "show-resolved")
|
|
118
|
+
return { kind: "no-op" };
|
|
119
|
+
if (matchesKey(data, Key.up) || matchesKey(data, "k")) {
|
|
120
|
+
return { kind: "dispatch", action: { kind: "cursor-move", delta: -1 } };
|
|
121
|
+
}
|
|
122
|
+
if (matchesKey(data, Key.down) || matchesKey(data, "j")) {
|
|
123
|
+
return { kind: "dispatch", action: { kind: "cursor-move", delta: 1 } };
|
|
124
|
+
}
|
|
125
|
+
return { kind: "no-op" };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=show-resolved.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"show-resolved.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/config-tui/screens/show-resolved.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ConfigTuiState } from "../state/model.js";
|
|
2
|
+
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { InputResult, Screen } from "./types.js";
|
|
4
|
+
export declare class TierMenuScreen implements Screen {
|
|
5
|
+
render(state: ConfigTuiState, width: number, theme: Theme): string[];
|
|
6
|
+
handleInput(data: string, state: ConfigTuiState): InputResult;
|
|
7
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// Tier-menu screen — the new landing view for forge:config.
|
|
2
|
+
// Phase A: replaces top-menu as the default entry point.
|
|
3
|
+
// Shows three workload tiers (Heavy / Standard / Light) as primary CTAs,
|
|
4
|
+
// a scope toggle, and secondary navigation to show-resolved / advanced.
|
|
5
|
+
import { Key, matchesKey } from "@earendil-works/pi-tui";
|
|
6
|
+
import { getActiveView, getAllScopedTierAssignments } from "../state/selectors.js";
|
|
7
|
+
import { TIERS, TIER_LABELS, TIER_SUB_LABELS } from "../tier-meta.js";
|
|
8
|
+
import { rule, safeLines } from "./shared.js";
|
|
9
|
+
import { padRight, cursor, accentBold, accent, muted, warning, dirtyMarker } from "../theme.js";
|
|
10
|
+
/** Interactive row count: 3 tiers + show-resolved + advanced = 5. */
|
|
11
|
+
const ITEM_COUNT = 5;
|
|
12
|
+
export class TierMenuScreen {
|
|
13
|
+
render(state, width, theme) {
|
|
14
|
+
const view = getActiveView(state);
|
|
15
|
+
if (view.kind !== "tier-menu") {
|
|
16
|
+
return ["(tier-menu called with wrong active view)"];
|
|
17
|
+
}
|
|
18
|
+
const cursorIdx = view.cursor;
|
|
19
|
+
const lines = [];
|
|
20
|
+
// ── Header ─────────────────────────────────────────────────────────
|
|
21
|
+
lines.push(accentBold("forge config", theme));
|
|
22
|
+
lines.push(rule(width, theme));
|
|
23
|
+
// ── "Active right now" summary ─────────────────────────────────────
|
|
24
|
+
lines.push(muted("Active right now", theme));
|
|
25
|
+
const scopedAssignments = getAllScopedTierAssignments(state, state.scope);
|
|
26
|
+
for (const { tier, assignment } of scopedAssignments) {
|
|
27
|
+
const label = padRight(TIER_LABELS[tier], 10);
|
|
28
|
+
if (assignment.status === "set") {
|
|
29
|
+
const modelStr = `${assignment.provider}:${assignment.model}`;
|
|
30
|
+
const layerLabel = `(${assignment.layer})`;
|
|
31
|
+
lines.push(` ${label} ${modelStr} ${muted(layerLabel, theme)}`);
|
|
32
|
+
}
|
|
33
|
+
else if (assignment.status === "set-in-other-layer") {
|
|
34
|
+
const otherLabel = assignment.otherLayer === "global" ? "global" : "project";
|
|
35
|
+
const modelStr = `${assignment.provider}:${assignment.model}`;
|
|
36
|
+
lines.push(` ${label} ${muted(modelStr + " (" + otherLabel + ")", theme)}`);
|
|
37
|
+
}
|
|
38
|
+
else if (assignment.status === "mixed") {
|
|
39
|
+
lines.push(` ${label} ${warning("mixed — personas differ", theme)}`);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
lines.push(` ${label} ${muted("not set — falls back to pi current", theme)}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Scope row
|
|
46
|
+
const scopeLabel = state.scope === "global" ? "global" : `project ( ${state.cwd} )`;
|
|
47
|
+
const altLabel = state.scope === "global" ? "project" : "global";
|
|
48
|
+
lines.push(` ${padRight("Scope", 10)} ${accent(scopeLabel, theme)} ${muted(altLabel, theme)}`);
|
|
49
|
+
lines.push("");
|
|
50
|
+
// ── "Choose models for your AI workflow" ────────────────────────────
|
|
51
|
+
lines.push(muted("Choose models for your AI workflow", theme));
|
|
52
|
+
lines.push(rule(width, theme));
|
|
53
|
+
// Tier rows (items 0–2)
|
|
54
|
+
for (let i = 0; i < TIERS.length; i++) {
|
|
55
|
+
const tier = TIERS[i];
|
|
56
|
+
const cur = cursor(i === cursorIdx, theme);
|
|
57
|
+
const label = padRight(TIER_LABELS[tier], 10);
|
|
58
|
+
const subLabel = muted(`(${TIER_SUB_LABELS[tier]})`, theme);
|
|
59
|
+
const tierScoped = scopedAssignments.find((a) => a.tier === tier).assignment;
|
|
60
|
+
const valueStr = tierScoped.status === "set"
|
|
61
|
+
? `${tierScoped.provider}:${tierScoped.model}`
|
|
62
|
+
: tierScoped.status === "set-in-other-layer"
|
|
63
|
+
? muted(`(${tierScoped.otherLayer})`, theme)
|
|
64
|
+
: tierScoped.status === "mixed"
|
|
65
|
+
? warning("mixed", theme)
|
|
66
|
+
: muted("not set", theme);
|
|
67
|
+
lines.push(` ${cur} ${label} ${subLabel} ${valueStr}`);
|
|
68
|
+
}
|
|
69
|
+
// "Show what runs at each step" (item 3)
|
|
70
|
+
{
|
|
71
|
+
const cur = cursor(3 === cursorIdx, theme);
|
|
72
|
+
lines.push(` ${cur} ${muted("Show what runs at each step", theme)}`);
|
|
73
|
+
}
|
|
74
|
+
// "Advanced — per-persona / per-step overrides" (item 4)
|
|
75
|
+
{
|
|
76
|
+
const cur = cursor(4 === cursorIdx, theme);
|
|
77
|
+
lines.push(` ${cur} ${muted("Advanced — per-persona / per-step overrides", theme)}`);
|
|
78
|
+
}
|
|
79
|
+
lines.push("");
|
|
80
|
+
// ── Footer ──────────────────────────────────────────────────────────
|
|
81
|
+
const tierWord = cursorIdx < 3 ? "enter pick model" : "enter open";
|
|
82
|
+
lines.push(muted(` ${tierWord} tab toggle scope q quit`, theme));
|
|
83
|
+
if (state.dirty)
|
|
84
|
+
lines.push(` ${dirtyMarker(theme)}`);
|
|
85
|
+
return safeLines(lines, width);
|
|
86
|
+
}
|
|
87
|
+
handleInput(data, state) {
|
|
88
|
+
const view = getActiveView(state);
|
|
89
|
+
if (view.kind !== "tier-menu")
|
|
90
|
+
return { kind: "no-op" };
|
|
91
|
+
// ── Navigation ──────────────────────────────────────────────────────
|
|
92
|
+
if (matchesKey(data, Key.up) || matchesKey(data, "k")) {
|
|
93
|
+
return { kind: "dispatch", action: { kind: "cursor-move", delta: -1 } };
|
|
94
|
+
}
|
|
95
|
+
if (matchesKey(data, Key.down) || matchesKey(data, "j")) {
|
|
96
|
+
if (view.cursor < ITEM_COUNT - 1) {
|
|
97
|
+
return { kind: "dispatch", action: { kind: "cursor-move", delta: 1 } };
|
|
98
|
+
}
|
|
99
|
+
return { kind: "consumed" };
|
|
100
|
+
}
|
|
101
|
+
// ── Tab: toggle scope ───────────────────────────────────────────────
|
|
102
|
+
if (matchesKey(data, Key.tab)) {
|
|
103
|
+
return { kind: "dispatch", action: { kind: "toggle-scope" } };
|
|
104
|
+
}
|
|
105
|
+
// ── Enter: act on current cursor position ───────────────────────────
|
|
106
|
+
if (matchesKey(data, Key.enter)) {
|
|
107
|
+
if (view.cursor < 3) {
|
|
108
|
+
// Tier row → open tier picker
|
|
109
|
+
const tier = TIERS[view.cursor];
|
|
110
|
+
return { kind: "dispatch", action: { kind: "select-tier", tier } };
|
|
111
|
+
}
|
|
112
|
+
if (view.cursor === 3) {
|
|
113
|
+
// "Show what runs at each step"
|
|
114
|
+
return { kind: "dispatch", action: { kind: "push-view", view: { kind: "show-resolved", cursor: 0 } } };
|
|
115
|
+
}
|
|
116
|
+
if (view.cursor === 4) {
|
|
117
|
+
// "Advanced" → advanced-menu (Phase D)
|
|
118
|
+
return { kind: "dispatch", action: { kind: "push-view", view: { kind: "advanced-menu", cursor: 0 } } };
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// ── Shortcuts: 1/2/3 for tiers, s for show, a for advanced ──────────
|
|
122
|
+
if (matchesKey(data, "1"))
|
|
123
|
+
return { kind: "dispatch", action: { kind: "select-tier", tier: "heavy" } };
|
|
124
|
+
if (matchesKey(data, "2"))
|
|
125
|
+
return { kind: "dispatch", action: { kind: "select-tier", tier: "standard" } };
|
|
126
|
+
if (matchesKey(data, "3"))
|
|
127
|
+
return { kind: "dispatch", action: { kind: "select-tier", tier: "light" } };
|
|
128
|
+
if (matchesKey(data, "s"))
|
|
129
|
+
return { kind: "dispatch", action: { kind: "push-view", view: { kind: "show-resolved", cursor: 0 } } };
|
|
130
|
+
if (matchesKey(data, "a"))
|
|
131
|
+
return { kind: "dispatch", action: { kind: "push-view", view: { kind: "advanced-menu", cursor: 0 } } };
|
|
132
|
+
return { kind: "no-op" };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=tier-menu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tier-menu.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/config-tui/screens/tier-menu.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ConfigTuiState } from "../state/model.js";
|
|
2
|
+
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
import { InputResult, Screen } from "./types.js";
|
|
4
|
+
export declare class TierPickerScreen implements Screen {
|
|
5
|
+
render(state: ConfigTuiState, width: number, theme: Theme): string[];
|
|
6
|
+
handleInput(data: string, state: ConfigTuiState): InputResult;
|
|
7
|
+
private handlePickProviderInput;
|
|
8
|
+
private handlePickModelInput;
|
|
9
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// Tier-picker screen — provider + model picker for a workload tier.
|
|
2
|
+
// Phase A: minimal placeholder. Phase B adds full provider/model picking flow.
|
|
3
|
+
// Reuses the same UX patterns as persona-editor but scoped to a tier.
|
|
4
|
+
import { Key, matchesKey } from "@earendil-works/pi-tui";
|
|
5
|
+
import { getActiveView, uniqueProviders } from "../state/selectors.js";
|
|
6
|
+
import { TIER_LABELS, tierPersonaLine } from "../tier-meta.js";
|
|
7
|
+
import { rule, authBadgeFor, windowList, safeLines } from "./shared.js";
|
|
8
|
+
import { padRight, cursor, accentBold, muted, dirtyMarker } from "../theme.js";
|
|
9
|
+
export class TierPickerScreen {
|
|
10
|
+
render(state, width, theme) {
|
|
11
|
+
const view = getActiveView(state);
|
|
12
|
+
if (view.kind !== "tier-picker") {
|
|
13
|
+
return ["(tier-picker called with wrong active view)"];
|
|
14
|
+
}
|
|
15
|
+
const tierLabel = TIER_LABELS[view.tier];
|
|
16
|
+
const lines = [];
|
|
17
|
+
if (view.step === "pick-provider") {
|
|
18
|
+
lines.push(accentBold(`forge config › ${tierLabel} › pick provider`, theme));
|
|
19
|
+
lines.push(rule(width, theme));
|
|
20
|
+
lines.push(muted(` This will run for: ${tierPersonaLine(view.tier)}`, theme));
|
|
21
|
+
lines.push("");
|
|
22
|
+
const providers = uniqueProviders(state);
|
|
23
|
+
const win = windowList(providers, view.cursor);
|
|
24
|
+
if (win.aboveCount > 0)
|
|
25
|
+
lines.push(muted(` ↑ ${win.aboveCount} more above`, theme));
|
|
26
|
+
win.visible.forEach((p, i) => {
|
|
27
|
+
const absoluteIdx = win.start + i;
|
|
28
|
+
const cur = cursor(absoluteIdx === view.cursor, theme);
|
|
29
|
+
const auth = authBadgeFor(state, p, theme);
|
|
30
|
+
const modelCount = state.availableModels.filter((m) => m.provider === p).length;
|
|
31
|
+
const countLabel = `${modelCount} model${modelCount === 1 ? "" : "s"}`;
|
|
32
|
+
lines.push(` ${cur} ${padRight(p, 18)} ${auth} ${muted(countLabel, theme)}`);
|
|
33
|
+
});
|
|
34
|
+
if (win.belowCount > 0)
|
|
35
|
+
lines.push(muted(` ↓ ${win.belowCount} more below`, theme));
|
|
36
|
+
lines.push("");
|
|
37
|
+
lines.push(muted(" ↑↓ select enter advance esc back", theme));
|
|
38
|
+
}
|
|
39
|
+
else if (view.step === "pick-model") {
|
|
40
|
+
lines.push(accentBold(`forge config › ${tierLabel} › pick model`, theme));
|
|
41
|
+
lines.push(rule(width, theme));
|
|
42
|
+
lines.push(muted(` provider: ${view.provider ?? "(unknown)"}`, theme));
|
|
43
|
+
lines.push(muted(` This will run for: ${tierPersonaLine(view.tier)}`, theme));
|
|
44
|
+
lines.push("");
|
|
45
|
+
const models = state.availableModels.filter((m) => m.provider === view.provider);
|
|
46
|
+
if (models.length === 0) {
|
|
47
|
+
lines.push(muted(" No models available for this provider.", theme));
|
|
48
|
+
lines.push(muted(` (Run \`pi /login ${view.provider}\` then return.)`, theme));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const win = windowList(models, view.cursor);
|
|
52
|
+
if (win.aboveCount > 0)
|
|
53
|
+
lines.push(muted(` ↑ ${win.aboveCount} more above`, theme));
|
|
54
|
+
win.visible.forEach((m, i) => {
|
|
55
|
+
const absoluteIdx = win.start + i;
|
|
56
|
+
const cur = cursor(absoluteIdx === view.cursor, theme);
|
|
57
|
+
lines.push(` ${cur} ${m.id}`);
|
|
58
|
+
});
|
|
59
|
+
if (win.belowCount > 0)
|
|
60
|
+
lines.push(muted(` ↓ ${win.belowCount} more below`, theme));
|
|
61
|
+
}
|
|
62
|
+
lines.push("");
|
|
63
|
+
lines.push(muted(" ↑↓ select enter save esc back", theme));
|
|
64
|
+
}
|
|
65
|
+
if (state.dirty)
|
|
66
|
+
lines.push(` ${dirtyMarker(theme)}`);
|
|
67
|
+
return safeLines(lines, width);
|
|
68
|
+
}
|
|
69
|
+
handleInput(data, state) {
|
|
70
|
+
const view = getActiveView(state);
|
|
71
|
+
if (view.kind !== "tier-picker")
|
|
72
|
+
return { kind: "no-op" };
|
|
73
|
+
if (view.step === "pick-provider") {
|
|
74
|
+
return this.handlePickProviderInput(data, state, view);
|
|
75
|
+
}
|
|
76
|
+
if (view.step === "pick-model") {
|
|
77
|
+
return this.handlePickModelInput(data, state, view);
|
|
78
|
+
}
|
|
79
|
+
return { kind: "no-op" };
|
|
80
|
+
}
|
|
81
|
+
handlePickProviderInput(data, state, view) {
|
|
82
|
+
const providers = uniqueProviders(state);
|
|
83
|
+
if (matchesKey(data, Key.up) || matchesKey(data, "k")) {
|
|
84
|
+
return { kind: "dispatch", action: { kind: "cursor-move", delta: -1 } };
|
|
85
|
+
}
|
|
86
|
+
if (matchesKey(data, Key.down) || matchesKey(data, "j")) {
|
|
87
|
+
if (view.cursor < providers.length - 1) {
|
|
88
|
+
return { kind: "dispatch", action: { kind: "cursor-move", delta: 1 } };
|
|
89
|
+
}
|
|
90
|
+
return { kind: "consumed" };
|
|
91
|
+
}
|
|
92
|
+
if (matchesKey(data, Key.enter)) {
|
|
93
|
+
const provider = providers[view.cursor];
|
|
94
|
+
if (provider) {
|
|
95
|
+
return { kind: "dispatch", action: { kind: "set-tier-provider", tier: view.tier, provider } };
|
|
96
|
+
}
|
|
97
|
+
return { kind: "consumed" };
|
|
98
|
+
}
|
|
99
|
+
return { kind: "no-op" };
|
|
100
|
+
}
|
|
101
|
+
handlePickModelInput(data, state, view) {
|
|
102
|
+
const models = state.availableModels.filter((m) => m.provider === view.provider);
|
|
103
|
+
if (matchesKey(data, Key.up) || matchesKey(data, "k")) {
|
|
104
|
+
return { kind: "dispatch", action: { kind: "cursor-move", delta: -1 } };
|
|
105
|
+
}
|
|
106
|
+
if (matchesKey(data, Key.down) || matchesKey(data, "j")) {
|
|
107
|
+
if (view.cursor < models.length - 1) {
|
|
108
|
+
return { kind: "dispatch", action: { kind: "cursor-move", delta: 1 } };
|
|
109
|
+
}
|
|
110
|
+
return { kind: "consumed" };
|
|
111
|
+
}
|
|
112
|
+
if (matchesKey(data, Key.enter)) {
|
|
113
|
+
const target = models[view.cursor];
|
|
114
|
+
if (target && view.provider) {
|
|
115
|
+
return { kind: "dispatch", action: { kind: "commit-tier-model", tier: view.tier, provider: view.provider, model: target.id, layer: state.scope } };
|
|
116
|
+
}
|
|
117
|
+
return { kind: "consumed" };
|
|
118
|
+
}
|
|
119
|
+
return { kind: "no-op" };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=tier-picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tier-picker.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/config-tui/screens/tier-picker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ConfigTuiState, ConfigTuiAction } from "../state/model.js";
|
|
2
|
+
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
export type InputResult = {
|
|
4
|
+
kind: "consumed";
|
|
5
|
+
} | {
|
|
6
|
+
kind: "no-op";
|
|
7
|
+
} | {
|
|
8
|
+
kind: "dispatch";
|
|
9
|
+
action: ConfigTuiAction;
|
|
10
|
+
} | {
|
|
11
|
+
kind: "dispatch-seq";
|
|
12
|
+
actions: ConfigTuiAction[];
|
|
13
|
+
} | {
|
|
14
|
+
kind: "pop";
|
|
15
|
+
} | {
|
|
16
|
+
kind: "quit";
|
|
17
|
+
} | {
|
|
18
|
+
kind: "error";
|
|
19
|
+
message: string;
|
|
20
|
+
};
|
|
21
|
+
export interface Screen {
|
|
22
|
+
render(state: ConfigTuiState, width: number, theme: Theme): string[];
|
|
23
|
+
handleInput(data: string, state: ConfigTuiState): InputResult;
|
|
24
|
+
}
|