@boundless.network/setup 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js +9 -21
- package/dist/ui/logo.js +25 -0
- package/dist/ui/table.js +32 -9
- package/package.json +1 -1
package/dist/app.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Text, useApp, useInput } from "ink";
|
|
2
|
+
import { Box, Text, useApp, useInput, useWindowSize } from "ink";
|
|
3
3
|
import { useEffect, useRef, useState } from "react";
|
|
4
4
|
// Async screens run their task exactly once, on mount; the wizard object is mutable and shared.
|
|
5
5
|
import { HARNESSES } from "./harnesses/index.js";
|
|
@@ -18,8 +18,8 @@ import { Facts } from "./ui/facts.js";
|
|
|
18
18
|
import { Frame, Muted, Para, Title } from "./ui/frame.js";
|
|
19
19
|
import { MultiSelect, Select } from "./ui/menu.js";
|
|
20
20
|
import { Spinner } from "./ui/spinner.js";
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
21
|
+
import { LOGO, LOGO_COLUMNS, LOGO_ROWS } from "./ui/logo.js";
|
|
22
|
+
import { ModelSelect } from "./ui/table.js";
|
|
23
23
|
import { BAD, BRAND, MUTED, OK, WARN } from "./ui/theme.js";
|
|
24
24
|
const NAV = "↑↓ navigate enter select";
|
|
25
25
|
function message(error) {
|
|
@@ -172,9 +172,7 @@ export function App({ onFinish }) {
|
|
|
172
172
|
setScreen({ kind: "model", role: "primary" });
|
|
173
173
|
}, onError: (error) => fail(error, { kind: "catalog" }), wizard: wizard }));
|
|
174
174
|
case "model":
|
|
175
|
-
return (_jsx(ModelPicker, { catalog: wizard.catalog, harnesses: chosen(),
|
|
176
|
-
case "type-model":
|
|
177
|
-
return (_jsx(TypeModel, { catalog: wizard.catalog, onCancel: () => setScreen({ kind: "model", role: screen.role }), onSubmit: (id) => chooseModel(screen.role, id) }));
|
|
175
|
+
return (_jsx(ModelPicker, { catalog: wizard.catalog, harnesses: chosen(), onSelect: (id) => chooseModel(screen.role, id), role: screen.role }));
|
|
178
176
|
case "review":
|
|
179
177
|
return (_jsx(Review, { harnesses: chosen(), input: planInput(), onCancel: () => exit(), onPlans: (plans) => {
|
|
180
178
|
wizard.plans = plans;
|
|
@@ -232,7 +230,9 @@ function Welcome({ onSelect, wizard }) {
|
|
|
232
230
|
if (env.remote) {
|
|
233
231
|
facts.splice(2, 0, { label: "Remote", state: "warn", value: env.remote });
|
|
234
232
|
}
|
|
235
|
-
|
|
233
|
+
const { columns, rows } = useWindowSize();
|
|
234
|
+
const logo = rows >= LOGO_ROWS + 22 && columns >= LOGO_COLUMNS + 4;
|
|
235
|
+
return (_jsxs(Frame, { hints: NAV, children: [logo ? (_jsx(Box, { justifyContent: "center", marginBottom: 1, children: _jsx(Text, { color: BRAND, children: LOGO }) })) : null, _jsx(Title, { children: "Boundless Setup" }), _jsxs(Muted, { center: true, children: ["Signs you in through your browser, creates an inference key on your account,", "\n", "configures your coding harnesses, and sends one small test request.", "\n", "The key is never printed. Nothing is purchased."] }), _jsx(Facts, { facts: facts }), _jsx(Box, { justifyContent: "center", children: _jsx(Select, { onSelect: onSelect, options: [
|
|
236
236
|
{ label: "Continue", value: "continue" },
|
|
237
237
|
{ label: "What this does", value: "what" },
|
|
238
238
|
{ label: "Privacy & data", value: "privacy" },
|
|
@@ -309,22 +309,10 @@ function Catalog({ onDone, onError, wizard }) {
|
|
|
309
309
|
}, []);
|
|
310
310
|
return (_jsx(Frame, { hints: "", children: _jsx(Spinner, { label: "Reading the model catalog" }) }));
|
|
311
311
|
}
|
|
312
|
-
function ModelPicker({ catalog, harnesses,
|
|
312
|
+
function ModelPicker({ catalog, harnesses, onSelect, role, }) {
|
|
313
313
|
const lead = harnesses.find((harness) => role === "primary" || harness.backgroundDefault !== null) ?? harnesses[0];
|
|
314
314
|
const recommended = role === "primary" ? lead?.defaultModel : lead?.backgroundDefault;
|
|
315
|
-
|
|
316
|
-
const cheapest = [...catalog].sort((a, b) => a.outputPerMillionTokens - b.outputPerMillionTokens).map((model) => model.id);
|
|
317
|
-
const picks = [recommended, ...cheapest].filter((id) => typeof id === "string" && ids.has(id));
|
|
318
|
-
const options = [...new Set(picks)].slice(0, 4).map((id, index) => ({
|
|
319
|
-
hint: index === 0 ? `recommended for ${lead?.name ?? "you"}` : undefined,
|
|
320
|
-
label: id,
|
|
321
|
-
value: id,
|
|
322
|
-
}));
|
|
323
|
-
return (_jsxs(Frame, { hints: NAV, children: [_jsx(Title, { children: role === "primary" ? "Which model should be the default?" : "Which model for background work?" }), _jsxs(Muted, { center: true, children: [role === "primary" ? "Every configured harness gets this model." : "Cheap, fast tasks (Claude Code haiku slot, OpenCode small_model, omp tiny).", " Prices are USD per 1M tokens from the live catalog."] }), _jsx(ModelTable, { models: catalog }), _jsx(Box, { justifyContent: "center", children: _jsx(Select, { onSelect: (id) => (id === "__other" ? onOther() : onSelect(id)), options: [...options, { label: "Another model from the table", value: "__other" }] }) })] }));
|
|
324
|
-
}
|
|
325
|
-
function TypeModel({ catalog, onCancel, onSubmit }) {
|
|
326
|
-
const [rejected, setRejected] = useState(null);
|
|
327
|
-
return (_jsxs(Frame, { hints: "enter confirm esc back", children: [_jsx(Title, { children: "Type a model ID" }), _jsx(ModelTable, { models: catalog }), _jsx(Box, { justifyContent: "center", children: _jsx(TextInput, { onCancel: onCancel, onSubmit: (id) => (catalog.some((model) => model.id === id) ? onSubmit(id) : setRejected(id)), placeholder: "model id" }) }), rejected ? (_jsx(Box, { justifyContent: "center", marginTop: 1, children: _jsxs(Text, { color: WARN, children: [rejected, " is not served right now."] }) })) : null] }));
|
|
315
|
+
return (_jsxs(Frame, { hints: NAV, children: [_jsx(Title, { children: role === "primary" ? "Which model should be the default?" : "Which model for background work?" }), _jsxs(Muted, { center: true, children: [role === "primary" ? "Every configured harness gets this model." : "Cheap, fast tasks (Claude Code haiku slot, OpenCode small_model, omp tiny).", " Prices are USD per 1M tokens from the live catalog", lead ? `; the recommendation is ${lead.name}'s documented default.` : "."] }), _jsx(ModelSelect, { models: catalog, onSelect: onSelect, recommended: recommended ?? undefined }, role)] }));
|
|
328
316
|
}
|
|
329
317
|
function Review({ harnesses, input, onCancel, onPlans, onProceed, wizard, }) {
|
|
330
318
|
const [plans, setPlans] = useState(null);
|
package/dist/ui/logo.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const LOGO = ` ~Ja@@@@@@@@@@bY}
|
|
2
|
+
\\8@@@@@@@@@@@@@@@@@@@@q1
|
|
3
|
+
[@@@@@@@@%%@@@@@@@@@&tvW@@@@b+
|
|
4
|
+
/@@@Q: iX&@@@BY uW@@@#~
|
|
5
|
+
@@- \`Q@@@@u t@@@@Z
|
|
6
|
+
"m Ia@@@@@@@@@@@0I "b@@@&: b@@@M.
|
|
7
|
+
-B@@@@@@@@@aQXzCOh8q O@@@@~ Z@@@W
|
|
8
|
+
u@@@@x u@@k .| b@@@B p@@@w
|
|
9
|
+
W@@% @@@- %@@@c .8@@B>
|
|
10
|
+
&@@p 8@@Z u@@@b 0@@@0
|
|
11
|
+
*@@% "@@@Y 1@@@@ r@@@J
|
|
12
|
+
I@@@a Y@@@( !@@@p t@@@U
|
|
13
|
+
[@@@Z J@@@k U@@@^ q@@%.
|
|
14
|
+
}@@@* /@@@# @@@r u@@@[
|
|
15
|
+
M@@%! W@@@j d@@j Z@@@+
|
|
16
|
+
x@@@o n@@@%i {- 1@@W h@@@&
|
|
17
|
+
b@@@d q@@@Wl 'd%kLzucZ&@@@vYM@@@@m
|
|
18
|
+
h@@@*' 0@@@8} /M@@@@@@@@@@@@w u}
|
|
19
|
+
J@@@@r )B@@@Z' I-tnt_" W@
|
|
20
|
+
!a@@@&n JB@@@h} ]W@@f
|
|
21
|
+
~d@@@@*){W@@@@@@%0znnzZB@@@@B?
|
|
22
|
+
th@@@@@@@@@@@@@@@@@@@@&t
|
|
23
|
+
\`jm#@@@@@@@@@@WZ[`;
|
|
24
|
+
export const LOGO_ROWS = 23;
|
|
25
|
+
export const LOGO_COLUMNS = 58;
|
package/dist/ui/table.js
CHANGED
|
@@ -1,17 +1,40 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Box, Text } from "ink";
|
|
2
|
+
import { Box, Text, useInput } from "ink";
|
|
3
|
+
import { useState } from "react";
|
|
3
4
|
import { usd } from "../lib/catalog.js";
|
|
4
|
-
import { MUTED } from "./theme.js";
|
|
5
|
-
const
|
|
5
|
+
import { BRAND, MUTED } from "./theme.js";
|
|
6
|
+
const HEADER = ["ID", "Input /1M", "Output /1M", "Context", ""];
|
|
7
|
+
const cells = (model, recommended) => [
|
|
6
8
|
model.id,
|
|
7
9
|
usd(model.inputPerMillionTokens),
|
|
8
10
|
usd(model.outputPerMillionTokens),
|
|
9
11
|
model.contextTokens.toLocaleString("en-US"),
|
|
12
|
+
model.id === recommended ? "recommended" : "",
|
|
10
13
|
];
|
|
11
|
-
export function
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
export function ModelSelect({ models, onSelect, recommended, }) {
|
|
15
|
+
const start = Math.max(models.findIndex((model) => model.id === recommended), 0);
|
|
16
|
+
const [index, setIndex] = useState(start);
|
|
17
|
+
useInput((input, key) => {
|
|
18
|
+
if (key.upArrow || input === "k") {
|
|
19
|
+
setIndex((index + models.length - 1) % models.length);
|
|
20
|
+
}
|
|
21
|
+
else if (key.downArrow || input === "j") {
|
|
22
|
+
setIndex((index + 1) % models.length);
|
|
23
|
+
}
|
|
24
|
+
else if (key.return) {
|
|
25
|
+
const chosen = models[index];
|
|
26
|
+
if (chosen) {
|
|
27
|
+
onSelect(chosen.id);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
const rows = models.map((model) => cells(model, recommended));
|
|
32
|
+
const widths = HEADER.map((cell, column) => Math.max(cell.length, ...rows.map((row) => row[column]?.length ?? 0)));
|
|
33
|
+
const line = (row) => row
|
|
34
|
+
.map((cell, column) => (column === 0 || column === 4 ? cell.padEnd(widths[column] ?? 0) : cell.padStart(widths[column] ?? 0)))
|
|
35
|
+
.join(" ");
|
|
36
|
+
return (_jsx(Box, { justifyContent: "center", marginBottom: 1, children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: MUTED, children: ` ${line(HEADER)}` }), rows.map((row, position) => {
|
|
37
|
+
const active = position === index;
|
|
38
|
+
return (_jsxs(Text, { bold: active, color: active ? BRAND : undefined, children: [active ? "▸ " : " ", line(row)] }, row[0]));
|
|
39
|
+
})] }) }));
|
|
17
40
|
}
|
package/package.json
CHANGED