@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 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 { ModelTable } from "./ui/table.js";
22
- import { TextInput } from "./ui/text-input.js";
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(), onOther: () => setScreen({ kind: "type-model", role: screen.role }), onSelect: (id) => chooseModel(screen.role, id), role: screen.role }));
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
- return (_jsxs(Frame, { hints: NAV, children: [_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: [
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, onOther, onSelect, role, }) {
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
- const ids = new Set(catalog.map((model) => model.id));
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);
@@ -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 columns = (model) => [
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 ModelTable({ models }) {
12
- const header = ["ID", "Input /1M", "Output /1M", "Context"];
13
- const rows = models.map(columns);
14
- const widths = header.map((cell, column) => Math.max(cell.length, ...rows.map((row) => row[column]?.length ?? 0)));
15
- const line = (cells) => cells.map((cell, column) => (column === 0 ? cell.padEnd(widths[column] ?? 0) : cell.padStart(widths[column] ?? 0))).join(" ");
16
- return (_jsxs(Box, { alignItems: "center", flexDirection: "column", marginBottom: 1, children: [_jsx(Text, { color: MUTED, children: line(header) }), rows.map((row) => (_jsx(Text, { children: line(row) }, row[0])))] }));
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boundless.network/setup",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Set up Boundless as the inference provider for your coding harness. Run: npx -y @boundless.network/setup@latest",
5
5
  "license": "MIT",
6
6
  "type": "module",