@markjaquith/agency 2.32.1 → 2.32.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markjaquith/agency",
3
- "version": "2.32.1",
3
+ "version": "2.32.2",
4
4
  "description": "Manage agentic work across repositories with durable workbases",
5
5
  "keywords": [
6
6
  "agents",
@@ -44,7 +44,7 @@ describe("OpenTUI interaction", () => {
44
44
  test("uses the split-footer renderer contract", () => {
45
45
  expect(interactiveRendererConfig).toMatchObject({
46
46
  screenMode: "split-footer",
47
- footerHeight: 4,
47
+ footerHeight: 5,
48
48
  externalOutputMode: "capture-stdout",
49
49
  clearOnShutdown: false,
50
50
  })
@@ -212,6 +212,26 @@ describe("OpenTUI interaction", () => {
212
212
  }
213
213
  })
214
214
 
215
+ test("wraps text prompt input onto another line", async () => {
216
+ const setup = await testRender(
217
+ () => <InteractiveTextPrompt prompt="Task ID" onDone={() => {}} />,
218
+ { width: 16, height: 5 },
219
+ )
220
+ try {
221
+ await setup.renderer.setupTerminal()
222
+ await setup.renderOnce()
223
+ await Bun.sleep(0)
224
+ await setup.mockInput.typeText("alpha beta gamma delta")
225
+ await setup.flush()
226
+ const frame = setup.captureCharFrame()
227
+ expect(frame).toContain("alpha beta")
228
+ expect(frame).toContain("gamma")
229
+ expect(frame).toMatch(/alpha beta\s*\ngamma delta/)
230
+ } finally {
231
+ setup.renderer.destroy()
232
+ }
233
+ })
234
+
215
235
  test("submits text and cancels with ctrl-c or escape", async () => {
216
236
  let submitted: string | null | undefined
217
237
  const input = await testRender(
@@ -4,7 +4,7 @@ import {
4
4
  createCliRenderer,
5
5
  type CliRenderer,
6
6
  type CliRendererConfig,
7
- type InputRenderable,
7
+ type TextareaRenderable,
8
8
  } from "@opentui/core"
9
9
  import { render, useKeyboard, type JSX } from "@opentui/solid"
10
10
  import { createMemo, createSignal, For } from "solid-js"
@@ -16,7 +16,7 @@ export interface InteractiveChoice {
16
16
 
17
17
  export const interactiveRendererConfig = {
18
18
  screenMode: "split-footer",
19
- footerHeight: 4,
19
+ footerHeight: 5,
20
20
  externalOutputMode: "capture-stdout",
21
21
  consoleMode: "disabled",
22
22
  clearOnShutdown: false,
@@ -35,7 +35,7 @@ const isCancel = (key: { name: string; ctrl: boolean }) =>
35
35
  key.name === "escape" || (key.ctrl && key.name === "c")
36
36
 
37
37
  export const InteractiveTextPrompt = (props: PromptProps<string>) => {
38
- let input: InputRenderable | undefined
38
+ let input: TextareaRenderable | undefined
39
39
  let value = ""
40
40
  useKeyboard((key) => {
41
41
  if (isCancel(key)) {
@@ -53,10 +53,13 @@ export const InteractiveTextPrompt = (props: PromptProps<string>) => {
53
53
  return (
54
54
  <box flexDirection="column" width="100%" height="100%">
55
55
  <text fg="#7aa2f7">{props.prompt}</text>
56
- <input
56
+ <textarea
57
57
  focused
58
- onInput={(next) => {
59
- value = next
58
+ height={2}
59
+ wrapMode="word"
60
+ keyBindings={[{ name: "return", action: "submit" }]}
61
+ onContentChange={() => {
62
+ value = input?.plainText ?? ""
60
63
  }}
61
64
  ref={(next) => {
62
65
  input = next
@@ -140,7 +143,7 @@ export const fuzzyChoices = (
140
143
  }
141
144
 
142
145
  export const InteractiveSelectPrompt = (props: SelectPromptProps) => {
143
- let input: InputRenderable | undefined
146
+ let input: TextareaRenderable | undefined
144
147
  const [query, setQuery] = createSignal("")
145
148
  const [selected, setSelected] = createSignal(0)
146
149
  const choices = createMemo(() => fuzzyChoices(props.choices, query()))
@@ -195,13 +198,16 @@ export const InteractiveSelectPrompt = (props: SelectPromptProps) => {
195
198
  {props.prompt}
196
199
  </text>
197
200
  <text fg="#7aa2f7">{" > "}</text>
198
- <input
201
+ <textarea
199
202
  focused
200
203
  flexGrow={1}
201
204
  minWidth={8}
205
+ height={2}
206
+ wrapMode="word"
202
207
  placeholder="filter"
203
- onInput={(next) => {
204
- setQuery(next)
208
+ keyBindings={[{ name: "return", action: "submit" }]}
209
+ onContentChange={() => {
210
+ setQuery(input?.plainText ?? "")
205
211
  setSelected(0)
206
212
  }}
207
213
  ref={(next) => {
@@ -266,7 +272,6 @@ async function runInteractive<T>(
266
272
  } finally {
267
273
  if (renderer) {
268
274
  await shutdown(renderer)
269
- process.stdout.write("\n")
270
275
  }
271
276
  }
272
277
  }