@wrongstack/tui 0.148.0 → 0.155.0

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/index.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import { expectDefined, writeErr, resolveWstackPaths, loadGoal, InputBuilder, DefaultSessionRewinder, writeOut, formatTodosList, buildGoalPreamble, shouldEnhance, enhanceUserPrompt, recentTextTurns, normalizedEqual, buildChildEnv } from '@wrongstack/core';
2
2
  export { buildGoalPreamble } from '@wrongstack/core';
3
3
  import { Box, Text, useInput, useStdin, useStdout, render, useApp, Static } from 'ink';
4
- import React5, { useState, useEffect, memo, useRef, useCallback, useReducer, useMemo } from 'react';
4
+ import * as path3 from 'path';
5
+ import React5, { useState, useEffect, useMemo, memo, useRef, useCallback, useReducer } from 'react';
5
6
  import * as fs2 from 'fs/promises';
6
- import * as path2 from 'path';
7
7
  import { routeImagesForModel } from '@wrongstack/runtime/vision';
8
8
  import { getIndexState, onIndexStateChange, getProcessRegistry } from '@wrongstack/tools';
9
9
  import { readClipboardImage } from '@wrongstack/runtime/clipboard';
@@ -1467,8 +1467,8 @@ function FilePicker({ query, matches, selected }) {
1467
1467
  ] }, m))
1468
1468
  ] });
1469
1469
  }
1470
- function highlight(path3, _query) {
1471
- return path3;
1470
+ function highlight(path5, _query) {
1471
+ return path5;
1472
1472
  }
1473
1473
  function FleetPanel({
1474
1474
  entries,
@@ -1607,7 +1607,7 @@ function HelpOverlay() {
1607
1607
  const keyWidth = Math.max(...sections.flatMap((s2) => s2.entries.map((e) => e.keys.length)), 0);
1608
1608
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: theme.accent, paddingX: 1, children: [
1609
1609
  /* @__PURE__ */ jsxs(Box, { flexDirection: "row", gap: 1, children: [
1610
- /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: "WrongStack \u2014 keys & commands" }),
1610
+ /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: "Keyboard shortcuts" }),
1611
1611
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: "\xB7 Esc to close" })
1612
1612
  ] }),
1613
1613
  sections.map((sec) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
@@ -3408,10 +3408,11 @@ function Banner({
3408
3408
  entry
3409
3409
  }) {
3410
3410
  const cwdShort = shortenPath(entry.cwd, 48);
3411
+ const projectLabel = path3.basename(entry.cwd);
3411
3412
  return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 0, children: [
3412
3413
  /* @__PURE__ */ jsxs(Text, { children: [
3413
3414
  /* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: " \u259F\u259B " }),
3414
- /* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: "WrongStack" }),
3415
+ /* @__PURE__ */ jsx(Text, { color: "magenta", bold: true, children: projectLabel }),
3415
3416
  /* @__PURE__ */ jsx(Text, { dimColor: true, children: " v" }),
3416
3417
  /* @__PURE__ */ jsx(Text, { children: entry.version })
3417
3418
  ] }),
@@ -3443,6 +3444,20 @@ function Banner({
3443
3444
  ] })
3444
3445
  ] });
3445
3446
  }
3447
+ var NEXT_STEPS_RE = /💡\s*Next steps?\s*\n+((?:\d+\.\s+.+\n?)+)/i;
3448
+ function parseNextSteps(content) {
3449
+ const match = NEXT_STEPS_RE.exec(content);
3450
+ if (!match?.[1]) return { steps: [], stripped: content };
3451
+ const block = match[1];
3452
+ const steps = [];
3453
+ const lines = block.split("\n").filter(Boolean);
3454
+ for (const line of lines) {
3455
+ const m = /^(\d+)\.\s+(.+)$/.exec(line.trim());
3456
+ if (m) steps.push({ index: Number.parseInt(m[1], 10), text: m[2].trim() });
3457
+ }
3458
+ const stripped = content.replace(NEXT_STEPS_RE, "").replace(/\n{3,}/g, "\n\n").trim();
3459
+ return { steps: steps.slice(0, 6), stripped };
3460
+ }
3446
3461
  function brainStatusStyle(status) {
3447
3462
  switch (status) {
3448
3463
  case "thinking":
@@ -3471,6 +3486,10 @@ var Entry = React5.memo(function Entry2({
3471
3486
  entry,
3472
3487
  termWidth
3473
3488
  }) {
3489
+ const nextSteps = useMemo(() => {
3490
+ if (entry.kind !== "assistant") return { steps: [], stripped: "" };
3491
+ return parseNextSteps(entry.text);
3492
+ }, [entry.kind, entry.text]);
3474
3493
  switch (entry.kind) {
3475
3494
  case "user":
3476
3495
  return /* @__PURE__ */ jsx(
@@ -3499,24 +3518,52 @@ var Entry = React5.memo(function Entry2({
3499
3518
  );
3500
3519
  case "assistant": {
3501
3520
  const contentWidth = assistantContentWidth(termWidth);
3502
- return /* @__PURE__ */ jsxs(
3503
- Box,
3504
- {
3505
- flexDirection: "column",
3506
- marginX: MESSAGE_PANEL_MARGIN,
3507
- marginY: 1,
3508
- borderStyle: "single",
3509
- borderTop: false,
3510
- borderRight: false,
3511
- borderBottom: false,
3512
- borderColor: theme.assistant,
3513
- paddingLeft: 1,
3514
- children: [
3515
- /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { bold: true, color: theme.assistant, children: "ASSISTANT" }) }),
3516
- /* @__PURE__ */ jsx(AssistantBody, { text: entry.text, termWidth, contentWidth })
3517
- ]
3518
- }
3519
- );
3521
+ const { steps, stripped } = nextSteps;
3522
+ const hasNext = steps.length > 0;
3523
+ return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
3524
+ /* @__PURE__ */ jsxs(
3525
+ Box,
3526
+ {
3527
+ flexDirection: "column",
3528
+ marginX: MESSAGE_PANEL_MARGIN,
3529
+ marginY: 1,
3530
+ borderStyle: "single",
3531
+ borderTop: false,
3532
+ borderRight: false,
3533
+ borderBottom: hasNext ? false : void 0,
3534
+ borderColor: theme.assistant,
3535
+ paddingLeft: 1,
3536
+ children: [
3537
+ /* @__PURE__ */ jsx(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx(Text, { bold: true, color: theme.assistant, children: "ASSISTANT" }) }),
3538
+ /* @__PURE__ */ jsx(AssistantBody, { text: stripped, termWidth, contentWidth })
3539
+ ]
3540
+ }
3541
+ ),
3542
+ hasNext && /* @__PURE__ */ jsxs(
3543
+ Box,
3544
+ {
3545
+ flexDirection: "column",
3546
+ marginX: MESSAGE_PANEL_MARGIN,
3547
+ marginY: 1,
3548
+ borderStyle: "single",
3549
+ borderTop: false,
3550
+ borderRight: false,
3551
+ borderBottom: false,
3552
+ borderColor: theme.accent,
3553
+ paddingLeft: 1,
3554
+ children: [
3555
+ /* @__PURE__ */ jsxs(Box, { flexDirection: "row", children: [
3556
+ /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: "\u{1F4A1} NEXT STEPS " }),
3557
+ /* @__PURE__ */ jsx(Text, { dimColor: true, children: "(use /next 1, /next 1 2 3 to select)" })
3558
+ ] }),
3559
+ steps.map((s2) => /* @__PURE__ */ jsx(Box, { flexDirection: "row", marginTop: 0, children: /* @__PURE__ */ jsxs(Text, { children: [
3560
+ /* @__PURE__ */ jsx(Text, { bold: true, color: theme.accent, children: ` ${s2.index}. ` }),
3561
+ /* @__PURE__ */ jsx(Text, { children: s2.text })
3562
+ ] }) }, s2.index))
3563
+ ]
3564
+ }
3565
+ )
3566
+ ] });
3520
3567
  }
3521
3568
  case "tool": {
3522
3569
  const argSummary = formatToolArgs(entry.name, entry.input);
@@ -5177,7 +5224,7 @@ async function loadIndex(root) {
5177
5224
  async function walk(root, rel, depth, out) {
5178
5225
  if (out.length >= MAX_FILES_INDEXED) return;
5179
5226
  if (depth > MAX_DEPTH) return;
5180
- const dir = rel ? path2.join(root, rel) : root;
5227
+ const dir = rel ? path3.join(root, rel) : root;
5181
5228
  let entries;
5182
5229
  try {
5183
5230
  entries = await fs2.readdir(dir, { withFileTypes: true });
@@ -7652,8 +7699,8 @@ function App({
7652
7699
  const lastEnterAtRef = useRef(0);
7653
7700
  const tokenPreviewsRef = useRef(/* @__PURE__ */ new Map());
7654
7701
  const projectName = React5.useMemo(() => {
7655
- const base = path2.basename(projectRoot);
7656
- return base && base !== path2.sep ? base : void 0;
7702
+ const base = path3.basename(projectRoot);
7703
+ return base && base !== path3.sep ? base : void 0;
7657
7704
  }, [projectRoot]);
7658
7705
  const chimeRef = useRef(chime);
7659
7706
  chimeRef.current = chime;
@@ -8059,7 +8106,7 @@ function App({
8059
8106
  dispatch({ type: "pickerClose" });
8060
8107
  return;
8061
8108
  }
8062
- const absPath = path2.isAbsolute(picked) ? picked : path2.join(projectRoot, picked);
8109
+ const absPath = path3.isAbsolute(picked) ? picked : path3.join(projectRoot, picked);
8063
8110
  try {
8064
8111
  const data = await fs2.readFile(absPath, "utf8");
8065
8112
  const token = await builder.registerFile({
@@ -10330,7 +10377,12 @@ async function runTui(opts) {
10330
10377
  stdout.write(BRACKETED_PASTE_ON);
10331
10378
  stdout.write("\x1B[2J\x1B[H");
10332
10379
  const inkStdin = stdin;
10333
- const stopTitle = opts.titleAnimation !== false ? startTerminalTitle({ stdout, events: opts.events, model: opts.model }) : (() => {
10380
+ const stopTitle = opts.titleAnimation !== false ? startTerminalTitle({
10381
+ stdout,
10382
+ events: opts.events,
10383
+ model: opts.model,
10384
+ appName: opts.projectRoot ? path3.basename(opts.projectRoot) : void 0
10385
+ }) : (() => {
10334
10386
  });
10335
10387
  const swallowSignals = ["SIGTSTP", "SIGQUIT", "SIGTTIN", "SIGTTOU"];
10336
10388
  const swallow = () => {