@skein-code/cli 0.3.28 → 0.3.29
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/README.md +17 -2
- package/dist/cli.js +55 -24
- package/dist/cli.js.map +1 -1
- package/docs/NEXT_STEPS.md +25 -16
- package/package.json +7 -1
package/README.md
CHANGED
|
@@ -96,7 +96,7 @@ To build, verify, and install a local package artifact from this checkout:
|
|
|
96
96
|
|
|
97
97
|
```bash
|
|
98
98
|
npm run verify:package -- --output-dir artifacts/package
|
|
99
|
-
npm install -g ./artifacts/package/skein-code-cli-0.3.
|
|
99
|
+
npm install -g ./artifacts/package/skein-code-cli-0.3.29.tgz
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
To install the published package from npm:
|
|
@@ -252,7 +252,13 @@ as `accent`, `text`, `muted`, `success`, and `error`. Set
|
|
|
252
252
|
`SKEIN_GLYPHS=ascii` when a terminal or multiplexer renders Unicode symbols
|
|
253
253
|
inconsistently. `NO_COLOR=1` or `ui.color: false` removes palette colors while
|
|
254
254
|
keeping status symbols and semantic labels intact. `/density compact` and
|
|
255
|
-
`/density comfortable` control vertical rhythm.
|
|
255
|
+
`/density comfortable` control vertical rhythm. `TERM=dumb` automatically uses
|
|
256
|
+
ASCII, monochrome, reduced-motion, non-incremental output. Set
|
|
257
|
+
`SKEIN_SCREEN_READER=1` (or Ink's `INK_SCREEN_READER=true`) for linear
|
|
258
|
+
screen-reader output with semantic timeline, permission-choice, and input roles;
|
|
259
|
+
this profile applies the same low-motion fallbacks while preserving keyboard
|
|
260
|
+
commands. `SKEIN_REDUCE_MOTION=1` disables activity animation independently.
|
|
261
|
+
Skein enables Kitty keyboard
|
|
256
262
|
enhancements without probing when Kitty, WezTerm, Ghostty, or foot declares
|
|
257
263
|
support; set `SKEIN_KITTY_KEYBOARD=on|off` to override detection.
|
|
258
264
|
|
|
@@ -639,7 +645,16 @@ npm test
|
|
|
639
645
|
npm run build
|
|
640
646
|
npm run check
|
|
641
647
|
npm run test:pty
|
|
648
|
+
npm run benchmark:terminal-ui
|
|
642
649
|
npm run release:verify
|
|
643
650
|
```
|
|
644
651
|
|
|
652
|
+
The PTY suite exercises 20/24/40/80/120 columns, a 40×10 viewport,
|
|
653
|
+
`TERM=dumb`, ASCII/`NO_COLOR`, and screen-reader interaction. It replays raw
|
|
654
|
+
output in a headless terminal and checks the final visible frame for overflow,
|
|
655
|
+
stale panels, control-sequence leaks, and missing ready/permission/error state.
|
|
656
|
+
`benchmark:terminal-ui` is a local single-process regression gate with p95
|
|
657
|
+
budgets of 25 ms for input processing and 150 ms for streaming renders; it is
|
|
658
|
+
not a universal hardware performance claim.
|
|
659
|
+
|
|
645
660
|
Skein is licensed under MIT.
|
package/dist/cli.js
CHANGED
|
@@ -220,7 +220,7 @@ function isSqliteBusy(error) {
|
|
|
220
220
|
// package.json
|
|
221
221
|
var package_default = {
|
|
222
222
|
name: "@skein-code/cli",
|
|
223
|
-
version: "0.3.
|
|
223
|
+
version: "0.3.29",
|
|
224
224
|
description: "A context-first, model-agnostic coding agent with an auditable terminal workspace.",
|
|
225
225
|
type: "module",
|
|
226
226
|
license: "MIT",
|
|
@@ -236,6 +236,10 @@ var package_default = {
|
|
|
236
236
|
},
|
|
237
237
|
skein: {
|
|
238
238
|
releaseNotes: [
|
|
239
|
+
"TERM=dumb and screen-reader sessions now use deterministic ASCII, monochrome, reduced-motion, non-incremental rendering without losing keyboard input",
|
|
240
|
+
"SKEIN_SCREEN_READER=1 enables Ink accessibility output with semantic timeline, permission, and composer roles plus clean phase boundaries",
|
|
241
|
+
"PTY release gates now replay eight terminal scenarios through a headless emulator and reject final-frame overflow, stale panels, announcement joins, and missing status",
|
|
242
|
+
"A local terminal UI benchmark enforces 25 ms input and 150 ms streaming-render p95 budgets while retaining the final streamed chunk",
|
|
239
243
|
"MCP trust and revoke confirmation rendering now has a deterministic cross-platform release regression gate",
|
|
240
244
|
"MCP now follows a no-network search and inspect review before explicit workspace-bound manifest trust and lazy activation",
|
|
241
245
|
"Declarative capability manifests expose redacted source, version, tools, permissions, network, command, path, sensitive-field, process, and completion-evidence effects",
|
|
@@ -319,6 +323,7 @@ var package_default = {
|
|
|
319
323
|
"benchmark:context": "tsx scripts/benchmark-local-index.ts",
|
|
320
324
|
"benchmark:duplication": "tsx scripts/benchmark-duplication.ts",
|
|
321
325
|
"benchmark:token-economy": "tsx scripts/benchmark-token-economy.ts",
|
|
326
|
+
"benchmark:terminal-ui": "tsx scripts/benchmark-terminal-ui.ts",
|
|
322
327
|
"verify:package": "node scripts/verify-package.mjs",
|
|
323
328
|
"release:verify": "npm run check && npm run verify:package --",
|
|
324
329
|
typecheck: "tsc --noEmit",
|
|
@@ -346,6 +351,7 @@ var package_default = {
|
|
|
346
351
|
"@types/diff": "^8.0.0",
|
|
347
352
|
"@types/node": "^22.19.7",
|
|
348
353
|
"@types/react": "^19.2.7",
|
|
354
|
+
"@xterm/headless": "^6.0.0",
|
|
349
355
|
tsup: "^8.5.1",
|
|
350
356
|
tsx: "^4.21.0",
|
|
351
357
|
vitest: "^4.0.18"
|
|
@@ -14770,6 +14776,20 @@ import { constants as constants5 } from "node:fs";
|
|
|
14770
14776
|
import chalk from "chalk";
|
|
14771
14777
|
|
|
14772
14778
|
// src/ui/terminal-capabilities.ts
|
|
14779
|
+
function resolveTerminalAccessibility(environment = process.env) {
|
|
14780
|
+
const screenReader = truthy(environment.SKEIN_SCREEN_READER) || environment.INK_SCREEN_READER?.trim().toLowerCase() === "true";
|
|
14781
|
+
const dumb = environment.TERM?.trim().toLowerCase() === "dumb";
|
|
14782
|
+
const reducedMotion = screenReader || dumb || truthy(environment.SKEIN_REDUCE_MOTION);
|
|
14783
|
+
const ascii = screenReader || dumb || environment.SKEIN_GLYPHS === "ascii" || environment.MOSAIC_GLYPHS === "ascii";
|
|
14784
|
+
const color = !screenReader && !dumb && environment.NO_COLOR === void 0;
|
|
14785
|
+
return {
|
|
14786
|
+
screenReader,
|
|
14787
|
+
reducedMotion,
|
|
14788
|
+
ascii,
|
|
14789
|
+
color,
|
|
14790
|
+
incrementalRendering: !screenReader && !dumb
|
|
14791
|
+
};
|
|
14792
|
+
}
|
|
14773
14793
|
function resolveKittyKeyboardConfig(environment = process.env) {
|
|
14774
14794
|
const override = environment.SKEIN_KITTY_KEYBOARD?.trim().toLowerCase();
|
|
14775
14795
|
if (override && ["1", "true", "yes", "on", "enabled"].includes(override)) {
|
|
@@ -14791,6 +14811,9 @@ function enabledKittyKeyboard() {
|
|
|
14791
14811
|
function disabledKittyKeyboard() {
|
|
14792
14812
|
return { mode: "disabled", flags: ["disambiguateEscapeCodes"] };
|
|
14793
14813
|
}
|
|
14814
|
+
function truthy(value) {
|
|
14815
|
+
return value !== void 0 && ["1", "true", "yes", "on"].includes(value.trim().toLowerCase());
|
|
14816
|
+
}
|
|
14794
14817
|
|
|
14795
14818
|
// src/cli/glyphs.ts
|
|
14796
14819
|
var unicodeGlyphs = {
|
|
@@ -16219,7 +16242,7 @@ function Timeline({ items, width = 80, glyphMode = "auto", showToolOutput = fals
|
|
|
16219
16242
|
if (!items.length) {
|
|
16220
16243
|
return /* @__PURE__ */ jsx(Box, { paddingLeft: 2, marginBottom: 1, children: /* @__PURE__ */ jsx(Text, { color: theme.muted, children: "Start with a request, @file, or /help." }) });
|
|
16221
16244
|
}
|
|
16222
|
-
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", children: items.map((item, index) => {
|
|
16245
|
+
return /* @__PURE__ */ jsx(Box, { flexDirection: "column", "aria-role": "list", children: items.map((item, index) => {
|
|
16223
16246
|
if (item.kind === "user") {
|
|
16224
16247
|
return /* @__PURE__ */ jsxs(Box, { marginBottom: compact3 || item.clipped ? 0 : 1, children: [
|
|
16225
16248
|
/* @__PURE__ */ jsx(Box, { width: 2, children: /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: glyphs.prompt }) }),
|
|
@@ -16690,7 +16713,7 @@ function PermissionCard({ call, category, reason, width = 80, glyphMode = "auto"
|
|
|
16690
16713
|
{ text: "[Esc]", color: theme.muted }
|
|
16691
16714
|
];
|
|
16692
16715
|
const marker = glyphs.borderStyle === "classic" ? "!" : "\u258E";
|
|
16693
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
16716
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, "aria-role": "radiogroup", children: [
|
|
16694
16717
|
/* @__PURE__ */ jsx(PermissionLine, { marker, children: /* @__PURE__ */ jsx(Text, { bold: true, color: theme.warning, children: title }) }),
|
|
16695
16718
|
/* @__PURE__ */ jsx(PermissionLine, { marker, children: /* @__PURE__ */ jsx(Text, { color: theme.muted, children: tool }) }),
|
|
16696
16719
|
/* @__PURE__ */ jsx(PermissionLine, { marker, children: /* @__PURE__ */ jsx(Text, { color: theme.text, children: summaryLine }) }),
|
|
@@ -16753,7 +16776,7 @@ function PromptBar({ busy, value, placeholder, width = 80, mode = "chat", queueC
|
|
|
16753
16776
|
] }),
|
|
16754
16777
|
/* @__PURE__ */ jsx(Text, { color: theme.text, children: truncateDisplay(safeQueuePreview, queuePreviewWidth) })
|
|
16755
16778
|
] }) : null,
|
|
16756
|
-
/* @__PURE__ */ jsxs(Box, { children: [
|
|
16779
|
+
/* @__PURE__ */ jsxs(Box, { "aria-role": "textbox", children: [
|
|
16757
16780
|
/* @__PURE__ */ jsx(Text, { bold: true, color: shell ? theme.warning : theme.accent, children: shell ? "! " : `${glyphs.prompt} ` }),
|
|
16758
16781
|
children
|
|
16759
16782
|
] }),
|
|
@@ -18417,13 +18440,14 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
18417
18440
|
const terminalHeight = Math.max(1, rows || 24);
|
|
18418
18441
|
const horizontalPadding = terminalWidth >= 24 ? 1 : 0;
|
|
18419
18442
|
const contentWidth = Math.max(1, terminalWidth - horizontalPadding * 2);
|
|
18420
|
-
const
|
|
18443
|
+
const terminalAccessibility = resolveTerminalAccessibility();
|
|
18444
|
+
const glyphMode = terminalAccessibility.ascii ? "ascii" : "auto";
|
|
18421
18445
|
const glyphs = resolveGlyphs(glyphMode);
|
|
18422
18446
|
const separator = ` ${glyphs.separator} `;
|
|
18423
18447
|
const ellipsis = terminalEllipsis();
|
|
18424
18448
|
const initialSession = runner.getSession();
|
|
18425
18449
|
const setupProblem = config.model.provider !== "compatible" && !config.model.apiKey ? `No ${config.model.provider} API key found. Set it and restart: export ${providerApiKeyEnv(config.model.provider)}=<your-key>${separator}then run ${PRODUCT_COMMAND} again. Use ${PRODUCT_COMMAND} doctor to verify, or --model to switch provider.` : config.model.provider === "compatible" && !config.model.baseUrl ? `No model endpoint configured. Set one and restart: export SKEIN_BASE_URL=<endpoint>${separator}or pass --base-url <endpoint>. Run ${PRODUCT_COMMAND} doctor to verify.` : void 0;
|
|
18426
|
-
const colorEnabled = config.ui.color &&
|
|
18450
|
+
const colorEnabled = config.ui.color && terminalAccessibility.color;
|
|
18427
18451
|
const [theme, setTheme] = useState2(() => resolveThemeWithColor(config.ui.theme, colorEnabled));
|
|
18428
18452
|
const [themeCatalogRevision, setThemeCatalogRevision] = useState2(0);
|
|
18429
18453
|
const [compact3, setCompact] = useState2(config.ui.compact);
|
|
@@ -18559,13 +18583,13 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
|
|
|
18559
18583
|
setHistorySearch((current) => current ? setHistorySearchQuery(current, input2) : current);
|
|
18560
18584
|
}, [input2]);
|
|
18561
18585
|
useEffect2(() => {
|
|
18562
|
-
if (!busy || reducedMotion
|
|
18586
|
+
if (!busy || terminalAccessibility.reducedMotion) {
|
|
18563
18587
|
setFrameIndex(0);
|
|
18564
18588
|
return void 0;
|
|
18565
18589
|
}
|
|
18566
18590
|
const timer = setInterval(() => setFrameIndex((value) => (value + 1) % spinnerFrames().length), 120);
|
|
18567
18591
|
return () => clearInterval(timer);
|
|
18568
|
-
}, [busy]);
|
|
18592
|
+
}, [busy, terminalAccessibility.reducedMotion]);
|
|
18569
18593
|
const requestPermission = useCallback((call, category, reason) => {
|
|
18570
18594
|
return new Promise((resolve28) => setPermission({
|
|
18571
18595
|
call,
|
|
@@ -20004,14 +20028,17 @@ function permissionPosture(config) {
|
|
|
20004
20028
|
}
|
|
20005
20029
|
async function runInteractiveTui(options) {
|
|
20006
20030
|
await reloadUserThemes();
|
|
20031
|
+
const terminalAccessibility = resolveTerminalAccessibility();
|
|
20007
20032
|
const instance = render2(/* @__PURE__ */ jsx3(SkeinApp, { ...options }), {
|
|
20008
20033
|
exitOnCtrlC: false,
|
|
20009
20034
|
patchConsole: true,
|
|
20010
|
-
incrementalRendering:
|
|
20035
|
+
incrementalRendering: terminalAccessibility.incrementalRendering,
|
|
20036
|
+
isScreenReaderEnabled: terminalAccessibility.screenReader,
|
|
20011
20037
|
maxFps: 30,
|
|
20012
20038
|
kittyKeyboard: resolveKittyKeyboardConfig()
|
|
20013
20039
|
});
|
|
20014
20040
|
await instance.waitUntilExit();
|
|
20041
|
+
if (terminalAccessibility.screenReader) process.stdout.write("\n");
|
|
20015
20042
|
}
|
|
20016
20043
|
function initialTimeline(session, banner, setupProblem) {
|
|
20017
20044
|
const items = session.messages.filter((message2) => (message2.role === "user" || message2.role === "assistant") && visibleMessage(message2)).slice(-20).map((message2) => ({ id: message2.id, kind: message2.role, text: message2.content }));
|
|
@@ -20201,12 +20228,9 @@ function toolDetail2(call) {
|
|
|
20201
20228
|
return keys.slice(0, 3).join(", ");
|
|
20202
20229
|
}
|
|
20203
20230
|
function spinnerFrames() {
|
|
20204
|
-
const ascii =
|
|
20231
|
+
const ascii = resolveTerminalAccessibility().ascii;
|
|
20205
20232
|
return ascii ? [".", "o", "O", "o"] : ["\u25CC", "\u25CD", "\u25CE", "\u25C9", "\u25CE", "\u25CD"];
|
|
20206
20233
|
}
|
|
20207
|
-
function reducedMotion() {
|
|
20208
|
-
return process.env.SKEIN_REDUCE_MOTION === "1" || process.env.SKEIN_REDUCE_MOTION === "true" || process.env.INK_SCREEN_READER === "true" || process.env.TERM === "dumb";
|
|
20209
|
-
}
|
|
20210
20234
|
|
|
20211
20235
|
// src/ui/workspace-preparation.tsx
|
|
20212
20236
|
import { useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
@@ -20229,10 +20253,11 @@ function WorkspacePreparationView({
|
|
|
20229
20253
|
}) {
|
|
20230
20254
|
const theme = useTheme();
|
|
20231
20255
|
const safeWidth2 = Math.max(1, Math.floor(width));
|
|
20232
|
-
const innerWidth = Math.max(1, safeWidth2 - (safeWidth2 >= 24 ? 4 : 0));
|
|
20233
20256
|
const compact3 = safeWidth2 < 48;
|
|
20234
20257
|
const constrained = height < 14;
|
|
20235
|
-
const
|
|
20258
|
+
const horizontalPadding = safeWidth2 >= 24 && !constrained ? 2 : 0;
|
|
20259
|
+
const innerWidth = Math.max(1, safeWidth2 - horizontalPadding * 2);
|
|
20260
|
+
const ascii = resolveTerminalAccessibility().ascii;
|
|
20236
20261
|
const spinner = (ascii ? [".", "o", "O", "o"] : ["\u25DC", "\u25E0", "\u25DD", "\u25DE", "\u25E1", "\u25DF"])[frame % (ascii ? 4 : 6)];
|
|
20237
20262
|
const separator = ascii ? "|" : "\xB7";
|
|
20238
20263
|
const brand = ascii ? "*" : PRODUCT_MARK;
|
|
@@ -20242,7 +20267,7 @@ function WorkspacePreparationView({
|
|
|
20242
20267
|
const modelLine = `model ${sanitizeTerminalText(model)}`;
|
|
20243
20268
|
const workspaceLine = `workspace ${compactDisplayPath(sanitizeTerminalText(workspace), Math.max(1, innerWidth - 10))}`;
|
|
20244
20269
|
const steps = preparationSteps(phase, progress, readiness, error, { ascii, spinner });
|
|
20245
|
-
return /* @__PURE__ */ jsxs4(Box3, { flexDirection: "column", paddingX:
|
|
20270
|
+
return /* @__PURE__ */ jsxs4(Box3, { flexDirection: "column", paddingX: horizontalPadding, children: [
|
|
20246
20271
|
/* @__PURE__ */ jsxs4(Box3, { children: [
|
|
20247
20272
|
/* @__PURE__ */ jsxs4(Text4, { bold: true, color: theme.accent, children: [
|
|
20248
20273
|
brand,
|
|
@@ -20260,11 +20285,11 @@ function WorkspacePreparationView({
|
|
|
20260
20285
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(modelLine, innerWidth) }),
|
|
20261
20286
|
/* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(workspaceLine, innerWidth) })
|
|
20262
20287
|
] }) : /* @__PURE__ */ jsx4(Text4, { color: theme.dim, children: truncateDisplay(workspaceLine, innerWidth) }),
|
|
20263
|
-
/* @__PURE__ */ jsx4(Box3, { marginTop: 1, flexDirection: constrained ? "row" : "column", children: steps.map((step2) => constrained ? /* @__PURE__ */ jsxs4(Text4, { color: step2.state === "active" ? theme.accent : step2.state === "complete" ? theme.success : step2.state === "error" ? theme.error : theme.dim, children: [
|
|
20288
|
+
/* @__PURE__ */ jsx4(Box3, { marginTop: 1, flexDirection: constrained ? "row" : "column", children: steps.map((step2, index) => constrained ? /* @__PURE__ */ jsxs4(Text4, { color: step2.state === "active" ? theme.accent : step2.state === "complete" ? theme.success : step2.state === "error" ? theme.error : theme.dim, children: [
|
|
20289
|
+
index ? " " : "",
|
|
20264
20290
|
step2.glyph,
|
|
20265
20291
|
" ",
|
|
20266
|
-
step2.id === "persist" ? "save" : step2.id
|
|
20267
|
-
step2.id === "verify" ? "" : " "
|
|
20292
|
+
step2.id === "persist" ? "save" : step2.id
|
|
20268
20293
|
] }, step2.id) : /* @__PURE__ */ jsxs4(Box3, { height: 1, overflowY: "hidden", children: [
|
|
20269
20294
|
/* @__PURE__ */ jsxs4(Text4, { bold: true, color: step2.state === "active" ? theme.accent : step2.state === "complete" ? theme.success : step2.state === "error" ? theme.error : theme.border, children: [
|
|
20270
20295
|
step2.glyph,
|
|
@@ -20276,7 +20301,7 @@ function WorkspacePreparationView({
|
|
|
20276
20301
|
truncateDisplay(step2.detail, Math.max(1, innerWidth - displayWidth(step2.glyph) - (compact3 ? 12 : 14)))
|
|
20277
20302
|
] })
|
|
20278
20303
|
] }, step2.id)) }),
|
|
20279
|
-
/* @__PURE__ */ jsxs4(Box3, { marginTop: 1, children: [
|
|
20304
|
+
/* @__PURE__ */ jsxs4(Box3, { marginTop: constrained ? 0 : 1, children: [
|
|
20280
20305
|
/* @__PURE__ */ jsxs4(Text4, { bold: true, color: error ? theme.error : readiness ? theme.success : theme.accent, children: [
|
|
20281
20306
|
readiness ? ascii ? "[ok]" : "\u2713" : error ? ascii ? "[x]" : "\xD7" : spinner,
|
|
20282
20307
|
" "
|
|
@@ -20385,7 +20410,8 @@ function WorkspacePreparationApp({
|
|
|
20385
20410
|
}
|
|
20386
20411
|
async function runWorkspacePreparation(engine, config, options = {}) {
|
|
20387
20412
|
let result;
|
|
20388
|
-
const
|
|
20413
|
+
const terminalAccessibility = resolveTerminalAccessibility();
|
|
20414
|
+
const colorEnabled = config.ui.color && terminalAccessibility.color;
|
|
20389
20415
|
const theme = resolveThemeWithColor(config.ui.theme, colorEnabled);
|
|
20390
20416
|
const instance = render3(
|
|
20391
20417
|
/* @__PURE__ */ jsx4(ThemeProvider, { theme, children: /* @__PURE__ */ jsx4(
|
|
@@ -20407,11 +20433,13 @@ async function runWorkspacePreparation(engine, config, options = {}) {
|
|
|
20407
20433
|
...options.stderr ? { stderr: options.stderr } : {},
|
|
20408
20434
|
exitOnCtrlC: false,
|
|
20409
20435
|
patchConsole: false,
|
|
20410
|
-
incrementalRendering:
|
|
20436
|
+
incrementalRendering: terminalAccessibility.incrementalRendering,
|
|
20437
|
+
isScreenReaderEnabled: terminalAccessibility.screenReader,
|
|
20411
20438
|
kittyKeyboard: resolveKittyKeyboardConfig()
|
|
20412
20439
|
}
|
|
20413
20440
|
);
|
|
20414
20441
|
await instance.waitUntilExit();
|
|
20442
|
+
if (terminalAccessibility.screenReader) (options.stdout ?? process.stdout).write("\n");
|
|
20415
20443
|
return result ?? { status: "cancelled" };
|
|
20416
20444
|
}
|
|
20417
20445
|
function preparationLabel(phase, progress, readiness, compact3 = false) {
|
|
@@ -20758,7 +20786,7 @@ function isLoopbackHostname(hostname) {
|
|
|
20758
20786
|
return normalized === "localhost" || normalized.endsWith(".localhost") || normalized === "::1" || /^127(?:\.\d{1,3}){3}$/u.test(normalized);
|
|
20759
20787
|
}
|
|
20760
20788
|
function OnboardingApp({ initialConfig, saveConfig, onFinish }) {
|
|
20761
|
-
const colorEnabled = initialConfig.ui.color &&
|
|
20789
|
+
const colorEnabled = initialConfig.ui.color && resolveTerminalAccessibility().color;
|
|
20762
20790
|
const theme = useMemo2(() => resolveThemeWithColor(initialConfig.ui.theme, colorEnabled), [colorEnabled, initialConfig.ui.theme]);
|
|
20763
20791
|
return /* @__PURE__ */ jsx5(ThemeProvider, { theme, children: /* @__PURE__ */ jsx5(OnboardingFlow, { initialConfig, saveConfig, onFinish }) });
|
|
20764
20792
|
}
|
|
@@ -20981,6 +21009,7 @@ function providerLabel(provider) {
|
|
|
20981
21009
|
}
|
|
20982
21010
|
async function runFirstRunOnboarding(initialConfig, options = {}) {
|
|
20983
21011
|
let result;
|
|
21012
|
+
const terminalAccessibility = resolveTerminalAccessibility();
|
|
20984
21013
|
const instance = render4(
|
|
20985
21014
|
/* @__PURE__ */ jsx5(
|
|
20986
21015
|
OnboardingApp,
|
|
@@ -20998,11 +21027,13 @@ async function runFirstRunOnboarding(initialConfig, options = {}) {
|
|
|
20998
21027
|
...options.stderr ? { stderr: options.stderr } : {},
|
|
20999
21028
|
exitOnCtrlC: false,
|
|
21000
21029
|
patchConsole: false,
|
|
21001
|
-
incrementalRendering:
|
|
21030
|
+
incrementalRendering: terminalAccessibility.incrementalRendering,
|
|
21031
|
+
isScreenReaderEnabled: terminalAccessibility.screenReader,
|
|
21002
21032
|
kittyKeyboard: resolveKittyKeyboardConfig()
|
|
21003
21033
|
}
|
|
21004
21034
|
);
|
|
21005
21035
|
await instance.waitUntilExit();
|
|
21036
|
+
if (terminalAccessibility.screenReader) (options.stdout ?? process.stdout).write("\n");
|
|
21006
21037
|
return result ?? { status: "cancelled" };
|
|
21007
21038
|
}
|
|
21008
21039
|
|