@bastani/atomic 0.9.14-alpha.2 → 0.9.14-alpha.4
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/CHANGELOG.md +24 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/CHANGELOG.md +6 -0
- package/dist/builtin/mcp/package.json +2 -2
- package/dist/builtin/subagents/CHANGELOG.md +6 -0
- package/dist/builtin/subagents/agents/code-simplifier.md +1 -1
- package/dist/builtin/subagents/agents/codebase-analyzer.md +1 -1
- package/dist/builtin/subagents/agents/codebase-locator.md +1 -1
- package/dist/builtin/subagents/agents/codebase-online-researcher.md +1 -1
- package/dist/builtin/subagents/agents/codebase-pattern-finder.md +1 -1
- package/dist/builtin/subagents/agents/codebase-research-analyzer.md +1 -1
- package/dist/builtin/subagents/agents/codebase-research-locator.md +1 -1
- package/dist/builtin/subagents/agents/debugger.md +1 -1
- package/dist/builtin/subagents/agents/worker.md +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/web-access/CHANGELOG.md +16 -0
- package/dist/builtin/web-access/README.md +3 -6
- package/dist/builtin/web-access/index.ts +1 -2
- package/dist/builtin/web-access/package.json +2 -2
- package/dist/builtin/web-access/web-search-config.ts +2 -8
- package/dist/builtin/web-access/web-search-tool.ts +2 -7
- package/dist/builtin/web-access/web-search-workflow.ts +10 -0
- package/dist/builtin/workflows/CHANGELOG.md +18 -0
- package/dist/builtin/workflows/README.md +1 -1
- package/dist/builtin/workflows/builtin/goal-models.ts +4 -2
- package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +2 -1
- package/dist/builtin/workflows/builtin/ralph-models.ts +10 -5
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +125 -66
- package/dist/builtin/workflows/src/runs/foreground/executor-hil.ts +32 -4
- package/dist/builtin/workflows/src/runs/foreground/executor-prompt-nodes.ts +3 -9
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +27 -20
- package/dist/builtin/workflows/src/runs/foreground/executor.ts +4 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +6 -1
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +6 -1
- package/dist/builtin/workflows/src/tui/graph-theme.ts +11 -0
- package/dist/builtin/workflows/src/tui/graph-view-render.ts +19 -10
- package/dist/builtin/workflows/src/tui/stage-chat-view-custom-ui.ts +7 -8
- package/dist/builtin/workflows/src/tui/tool-detail.ts +45 -26
- package/dist/core/tools/ask-user-question/ask-user-question.d.ts +3 -1
- package/dist/core/tools/ask-user-question/ask-user-question.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/ask-user-question.js +2 -1
- package/dist/core/tools/ask-user-question/ask-user-question.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/build-questionnaire.d.ts +1 -0
- package/dist/core/tools/ask-user-question/state/build-questionnaire.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/build-questionnaire.js +1 -0
- package/dist/core/tools/ask-user-question/state/build-questionnaire.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/key-router.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/key-router.js +3 -1
- package/dist/core/tools/ask-user-question/state/key-router.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts +3 -0
- package/dist/core/tools/ask-user-question/state/questionnaire-session.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/questionnaire-session.js +3 -0
- package/dist/core/tools/ask-user-question/state/questionnaire-session.js.map +1 -1
- package/dist/core/tools/ask-user-question/state/state-reducer.d.ts +1 -0
- package/dist/core/tools/ask-user-question/state/state-reducer.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/state/state-reducer.js +3 -1
- package/dist/core/tools/ask-user-question/state/state-reducer.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/chat-row-view.d.ts +2 -0
- package/dist/core/tools/ask-user-question/view/components/chat-row-view.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/chat-row-view.js +1 -0
- package/dist/core/tools/ask-user-question/view/components/chat-row-view.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts +3 -0
- package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/wrapping-select.js +2 -1
- package/dist/core/tools/ask-user-question/view/components/wrapping-select.js.map +1 -1
- package/dist/core/tools/edit-batch.d.ts +33 -0
- package/dist/core/tools/edit-batch.d.ts.map +1 -0
- package/dist/core/tools/edit-batch.js +89 -0
- package/dist/core/tools/edit-batch.js.map +1 -0
- package/dist/core/tools/edit.d.ts +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +98 -42
- package/dist/core/tools/edit.js.map +1 -1
- package/docs/providers.md +1 -1
- package/docs/tools.md +1 -1
- package/docs/workflows.md +4 -4
- package/npm-shrinkwrap.json +65 -50
- package/package.json +5 -5
|
@@ -31,6 +31,7 @@ const MOCHA = {
|
|
|
31
31
|
red: "#f38ba8",
|
|
32
32
|
mauve: "#cba6f7",
|
|
33
33
|
sky: "#89dceb",
|
|
34
|
+
lavender: "#b4befe",
|
|
34
35
|
} as const;
|
|
35
36
|
|
|
36
37
|
/**
|
|
@@ -51,6 +52,8 @@ export interface GenericTheme {
|
|
|
51
52
|
text?: string;
|
|
52
53
|
textMuted?: string;
|
|
53
54
|
dim?: string;
|
|
55
|
+
toolTitle?: string;
|
|
56
|
+
toolOutput?: string;
|
|
54
57
|
accent?: string;
|
|
55
58
|
mauve?: string;
|
|
56
59
|
success?: string;
|
|
@@ -87,6 +90,10 @@ export interface GraphTheme {
|
|
|
87
90
|
text: string;
|
|
88
91
|
textMuted: string;
|
|
89
92
|
dim: string;
|
|
93
|
+
/** Host tool-card title (`toolTitle`, Catppuccin lavender). */
|
|
94
|
+
toolTitle: string;
|
|
95
|
+
/** Host tool-card body (`toolOutput`, usually the same as `text`). */
|
|
96
|
+
toolOutput: string;
|
|
90
97
|
|
|
91
98
|
/** Accents */
|
|
92
99
|
accent: string;
|
|
@@ -116,6 +123,8 @@ export function deriveGraphTheme(theme: GenericTheme = {}): GraphTheme {
|
|
|
116
123
|
text: theme.text ?? MOCHA.text,
|
|
117
124
|
textMuted: theme.textMuted ?? MOCHA.subtext0,
|
|
118
125
|
dim: theme.dim ?? MOCHA.overlay1,
|
|
126
|
+
toolTitle: theme.toolTitle ?? MOCHA.lavender,
|
|
127
|
+
toolOutput: theme.toolOutput ?? MOCHA.text,
|
|
119
128
|
|
|
120
129
|
accent: theme.accent ?? MOCHA.blue,
|
|
121
130
|
mauve: theme.mauve ?? MOCHA.mauve,
|
|
@@ -262,6 +271,8 @@ export function deriveGraphThemeFromPiTheme(theme: unknown): GraphTheme {
|
|
|
262
271
|
text: fgHex(t, "text") ?? fgHex(t, "customMessageText"),
|
|
263
272
|
textMuted: fgHex(t, "muted"),
|
|
264
273
|
dim: fgHex(t, "dim"),
|
|
274
|
+
toolTitle: fgHex(t, "toolTitle"),
|
|
275
|
+
toolOutput: fgHex(t, "toolOutput") ?? fgHex(t, "text") ?? fgHex(t, "customMessageText"),
|
|
265
276
|
|
|
266
277
|
accent,
|
|
267
278
|
success: fgHex(t, "success"),
|
|
@@ -26,6 +26,13 @@ function stripLayoutWrapper(line: string): string {
|
|
|
26
26
|
const end = endsWithWrapper ? line.length - LAYOUT_OSC_RESET.length : line.length;
|
|
27
27
|
return line.slice(start, Math.max(start, end));
|
|
28
28
|
}
|
|
29
|
+
/** Unpainted canvas between the orchestrator bars and the painted card. */
|
|
30
|
+
const TOOL_DETAIL_VIEWPORT_PAD = 1;
|
|
31
|
+
|
|
32
|
+
function toolDetailViewportPad(rows: number): number {
|
|
33
|
+
return rows >= TOOL_DETAIL_VIEWPORT_PAD * 2 + 1 ? TOOL_DETAIL_VIEWPORT_PAD : 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
29
36
|
/** One frame's tool-message geometry, derived once and shared by both callbacks. */
|
|
30
37
|
interface ToolDetailFrame {
|
|
31
38
|
readonly width: number;
|
|
@@ -159,17 +166,15 @@ export abstract class GraphViewRenderer extends GraphViewGraphRenderer {
|
|
|
159
166
|
const safeWidth = Math.max(1, Math.floor(width));
|
|
160
167
|
const cached = this.detailFrame;
|
|
161
168
|
if (cached !== null && cached.width === safeWidth) return cached;
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
// standalone rounded panel or hiding content behind a border.
|
|
165
|
-
const blockWidth = Math.max(1, safeWidth - 1);
|
|
169
|
+
// Span the same columns as the header/footer bars. Main-chat tool
|
|
170
|
+
// blocks are full width; only the Box(1,1) pad insets the `$` text.
|
|
166
171
|
const frame: ToolDetailFrame = {
|
|
167
172
|
width: safeWidth,
|
|
168
|
-
blockWidth,
|
|
169
|
-
leftPad:
|
|
173
|
+
blockWidth: safeWidth,
|
|
174
|
+
leftPad: 0,
|
|
170
175
|
lines: renderToolDetailLines(node, {
|
|
171
176
|
theme: this.graphTheme,
|
|
172
|
-
width:
|
|
177
|
+
width: safeWidth,
|
|
173
178
|
expanded: this.toolDetailExpanded,
|
|
174
179
|
expandKey: toolExpandKey(isKeybindingsLike(this.piKeybindings) ? this.piKeybindings : undefined),
|
|
175
180
|
}),
|
|
@@ -181,7 +186,8 @@ export abstract class GraphViewRenderer extends GraphViewGraphRenderer {
|
|
|
181
186
|
private _graphBodyContentHeight(width: number, viewportRows: number): number {
|
|
182
187
|
const rows = Math.max(0, Math.floor(viewportRows));
|
|
183
188
|
if (this.toolDetail !== null) {
|
|
184
|
-
|
|
189
|
+
const pad = toolDetailViewportPad(rows);
|
|
190
|
+
return Math.max(rows, this._toolDetailFrame(this.toolDetail, width).lines.length + pad * 2);
|
|
185
191
|
}
|
|
186
192
|
if (!this._currentRenderRun() || this.cachedRenderGeometry.totalRows <= 0) return rows;
|
|
187
193
|
return Math.max(rows, this.cachedRenderGeometry.totalRows);
|
|
@@ -249,9 +255,12 @@ export abstract class GraphViewRenderer extends GraphViewGraphRenderer {
|
|
|
249
255
|
private _renderBody(width: number, top: number, rows: number, _contentRows: number): string[] {
|
|
250
256
|
if (this.toolDetail !== null) {
|
|
251
257
|
const detail = this._toolDetailFrame(this.toolDetail, width);
|
|
252
|
-
|
|
253
|
-
|
|
258
|
+
const pad = toolDetailViewportPad(rows);
|
|
259
|
+
const inner = Math.max(0, rows - pad * 2);
|
|
260
|
+
const painted = detail.lines
|
|
261
|
+
.slice(top, top + inner)
|
|
254
262
|
.map((line) => this._canvasRow(`${" ".repeat(detail.leftPad)}${line}`, width));
|
|
263
|
+
return [...Array.from({ length: pad }, () => ""), ...painted, ...Array.from({ length: pad }, () => "")];
|
|
255
264
|
}
|
|
256
265
|
const run = this._currentRenderRun();
|
|
257
266
|
const raw = run ? this._renderGraph(width, top, rows, run) : this._renderEmptyBody(width, rows);
|
|
@@ -21,14 +21,13 @@ export async function showCustomUi(ctx: StageChatViewContext, request: StageCust
|
|
|
21
21
|
);
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
24
|
+
// `overlay: true` (and its `overlayOptions` / `reserveTranscriptRows`
|
|
25
|
+
// companions) is a placement hint for the main-chat host, not a capability
|
|
26
|
+
// request. The stage-chat custom-UI slot already gives the widget what an
|
|
27
|
+
// overlay buys it there — focus, and a transcript that stays visible and
|
|
28
|
+
// scrollable behind it — so an overlay request mounts on this same path
|
|
29
|
+
// rather than failing the prompt. `ask_user_question` always asks for an
|
|
30
|
+
// overlay, so rejecting it made every in-stage questionnaire fail.
|
|
32
31
|
try {
|
|
33
32
|
const mounted = await mountStageCustomUi(
|
|
34
33
|
request,
|
|
@@ -19,7 +19,14 @@ export const TOOL_DETAIL_VALUE_LIMIT = TOOL_PAYLOAD_VALUE_LIMIT;
|
|
|
19
19
|
const COLLAPSED_ARGS_LIMIT = 240;
|
|
20
20
|
/** Match the host tool renderer's collapsed fallback preview row bound. */
|
|
21
21
|
const COLLAPSED_RESULT_LINES = 10;
|
|
22
|
-
|
|
22
|
+
/** Match pi-tui `Box(paddingX=1, paddingY=1)` around the host tool card. */
|
|
23
|
+
const BOX_PAD = 1;
|
|
24
|
+
|
|
25
|
+
function boxMetrics(width: number): { pad: string; inner: number } {
|
|
26
|
+
const safeWidth = Math.max(1, Math.floor(width));
|
|
27
|
+
const inset = safeWidth >= BOX_PAD * 2 + 1 ? BOX_PAD : 0;
|
|
28
|
+
return { pad: " ".repeat(inset), inner: Math.max(1, safeWidth - inset * 2) };
|
|
29
|
+
}
|
|
23
30
|
|
|
24
31
|
export interface RenderToolDetailOpts {
|
|
25
32
|
/** Provide for ANSI output; omit for plain text. */
|
|
@@ -79,17 +86,31 @@ function styledStatus(status: ToolNodeStatus, theme: GraphTheme | undefined): st
|
|
|
79
86
|
}
|
|
80
87
|
|
|
81
88
|
function styledTitle(text: string, theme: GraphTheme | undefined): string {
|
|
82
|
-
return theme === undefined ? text : `${hexToAnsi(theme.
|
|
89
|
+
return theme === undefined ? text : `${hexToAnsi(theme.toolTitle)}${BOLD}${text}${RESET}`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function styledOutput(text: string, theme: GraphTheme | undefined): string {
|
|
93
|
+
return theme === undefined ? text : `${hexToAnsi(theme.toolOutput)}${text}${RESET}`;
|
|
83
94
|
}
|
|
84
95
|
|
|
85
96
|
function styledMuted(text: string, theme: GraphTheme | undefined): string {
|
|
86
97
|
return theme === undefined ? text : `${hexToAnsi(theme.textMuted)}${text}${RESET}`;
|
|
87
98
|
}
|
|
88
99
|
|
|
100
|
+
function styledDim(text: string, theme: GraphTheme | undefined): string {
|
|
101
|
+
return theme === undefined ? text : `${hexToAnsi(theme.dim)}${text}${RESET}`;
|
|
102
|
+
}
|
|
103
|
+
|
|
89
104
|
function styledError(text: string, theme: GraphTheme | undefined): string {
|
|
90
105
|
return theme === undefined ? text : `${hexToAnsi(theme.error)}${text}${RESET}`;
|
|
91
106
|
}
|
|
92
107
|
|
|
108
|
+
function expandHintLine(earlier: number, expandKey: string, pad: string, theme: GraphTheme | undefined): string {
|
|
109
|
+
const lead = `... (${earlier} earlier lines`;
|
|
110
|
+
if (expandKey.length === 0) return `${pad}${styledMuted(`${lead})`, theme)}`;
|
|
111
|
+
return `${pad}${styledMuted(`${lead}, `, theme)}${styledDim(expandKey, theme)}${styledMuted(" Expand)", theme)}`;
|
|
112
|
+
}
|
|
113
|
+
|
|
93
114
|
function toolBackground(status: ToolNodeStatus, theme: GraphTheme): string {
|
|
94
115
|
switch (status) {
|
|
95
116
|
case "completed":
|
|
@@ -249,7 +270,7 @@ function messageHeaderRows(
|
|
|
249
270
|
theme: GraphTheme | undefined,
|
|
250
271
|
expanded: boolean,
|
|
251
272
|
): string[] {
|
|
252
|
-
const
|
|
273
|
+
const { pad, inner } = boxMetrics(width);
|
|
253
274
|
const name = sanitizeToolTitleText(tool.name);
|
|
254
275
|
const glyph = headerGlyph(tool.status);
|
|
255
276
|
const glyphSuffix = glyph === undefined ? "" : ` ${glyph}`;
|
|
@@ -258,38 +279,36 @@ function messageHeaderRows(
|
|
|
258
279
|
? ""
|
|
259
280
|
: boundedSerializedValue(tool.args, expanded ? TOOL_DETAIL_VALUE_LIMIT : COLLAPSED_ARGS_LIMIT);
|
|
260
281
|
const withArgs = `$ ${name}${args ? ` ${args}` : ""}${glyphSuffix}`;
|
|
261
|
-
const plain = !expanded && visibleWidth(withArgs) >
|
|
282
|
+
const plain = !expanded && visibleWidth(withArgs) > inner ? `$ ${name}${glyphSuffix}` : withArgs;
|
|
262
283
|
const titleEnd = `$ ${name}`;
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
return wrapFieldValue(plain, safeWidth, continuationWidth).map((chunk, index, chunks) => {
|
|
266
|
-
const prefix = index === 0 ? "" : continuationIndent;
|
|
267
|
-
if (index !== 0 || !chunk.startsWith(titleEnd)) return `${prefix}${styledMuted(chunk, theme)}`;
|
|
284
|
+
return wrapFieldValue(plain, inner, inner).map((chunk, index, chunks) => {
|
|
285
|
+
if (index !== 0 || !chunk.startsWith(titleEnd)) return `${pad}${styledMuted(chunk, theme)}`;
|
|
268
286
|
const remainder = chunk.slice(titleEnd.length);
|
|
269
287
|
const hasStatus = glyphSuffix.length > 0 && index === chunks.length - 1 && remainder.endsWith(glyphSuffix);
|
|
270
288
|
const summary = hasStatus ? remainder.slice(0, -glyphSuffix.length) : remainder;
|
|
271
289
|
const suffix = hasStatus ? ` ${styledStatus(tool.status, theme)}` : "";
|
|
272
|
-
|
|
290
|
+
const title = styledTitle(titleEnd, theme);
|
|
291
|
+
const rest = summary.trim().length > 0 ? styledMuted(summary, theme) : "";
|
|
292
|
+
return `${pad}${title}${rest}${suffix}`;
|
|
273
293
|
});
|
|
274
294
|
}
|
|
275
295
|
|
|
276
296
|
function bodyRows(text: string, error: boolean, width: number, theme: GraphTheme | undefined): string[] {
|
|
277
|
-
const
|
|
278
|
-
return wrapFieldValue(text,
|
|
279
|
-
const styled = error ? styledError(line, theme) :
|
|
280
|
-
return `${
|
|
297
|
+
const { pad, inner } = boxMetrics(width);
|
|
298
|
+
return wrapFieldValue(text, inner).map((line) => {
|
|
299
|
+
const styled = error ? styledError(line, theme) : styledOutput(line, theme);
|
|
300
|
+
return `${pad}${styled}`;
|
|
281
301
|
});
|
|
282
302
|
}
|
|
283
303
|
|
|
284
304
|
function footerText(tool: ToolNodeSnapshot, elapsed: number | undefined): string | undefined {
|
|
285
305
|
if (elapsed === undefined) return undefined;
|
|
286
306
|
const label = tool.status === "running" ? "Elapsed" : "Took";
|
|
287
|
-
const duration = elapsed < 1000 ? `${Math.round(elapsed)}ms` : fmtDuration(elapsed);
|
|
288
307
|
const markers = [
|
|
289
308
|
tool.status === "cached" ? "cached" : undefined,
|
|
290
309
|
tool.replayed === true ? "replayed" : undefined,
|
|
291
310
|
].filter((marker): marker is string => marker !== undefined);
|
|
292
|
-
return `${label} ${
|
|
311
|
+
return `${label} ${fmtDuration(elapsed)}${markers.length > 0 ? ` · ${markers.join(" · ")}` : ""}`;
|
|
293
312
|
}
|
|
294
313
|
|
|
295
314
|
function renderMessageLines(
|
|
@@ -301,36 +320,36 @@ function renderMessageLines(
|
|
|
301
320
|
now: number,
|
|
302
321
|
): string[] {
|
|
303
322
|
const safeWidth = Math.max(1, Math.floor(width));
|
|
323
|
+
const { pad, inner } = boxMetrics(safeWidth);
|
|
304
324
|
const result = resultText(tool, TOOL_DETAIL_VALUE_LIMIT);
|
|
305
325
|
const rows: string[] = messageHeaderRows(tool, safeWidth, theme, expanded);
|
|
326
|
+
// Host bash/result renderers put a blank row between the `$` call and the body.
|
|
327
|
+
rows.push("");
|
|
306
328
|
const wrappedBody = bodyRows(result.text, result.error, safeWidth, theme);
|
|
307
329
|
if (expanded) {
|
|
308
330
|
rows.push(...wrappedBody);
|
|
309
331
|
if (tool.source !== undefined && tool.source.length > 0) {
|
|
310
|
-
const sourceWidth = Math.max(1, safeWidth - visibleWidth(BODY_INDENT));
|
|
311
332
|
rows.push(
|
|
312
|
-
...wrapFieldValue(boundedToolText(sanitizeToolDisplayText(tool.source)),
|
|
313
|
-
(line) => `${
|
|
333
|
+
...wrapFieldValue(boundedToolText(sanitizeToolDisplayText(tool.source)), inner).map(
|
|
334
|
+
(line) => `${pad}${styledMuted(line, theme)}`,
|
|
314
335
|
),
|
|
315
336
|
);
|
|
316
337
|
}
|
|
317
338
|
} else {
|
|
318
339
|
const earlier = Math.max(0, wrappedBody.length - COLLAPSED_RESULT_LINES);
|
|
319
340
|
if (earlier > 0) {
|
|
320
|
-
|
|
321
|
-
expandKey.length > 0
|
|
322
|
-
? `... (${earlier} earlier lines, ${expandKey} Expand)`
|
|
323
|
-
: `... (${earlier} earlier lines)`;
|
|
324
|
-
rows.push(` ${styledMuted(hint, theme)}`);
|
|
341
|
+
rows.push(expandHintLine(earlier, expandKey, pad, theme));
|
|
325
342
|
}
|
|
326
343
|
rows.push(...wrappedBody.slice(-COLLAPSED_RESULT_LINES));
|
|
327
344
|
}
|
|
328
345
|
const footer = footerText(tool, durationMs(tool, now));
|
|
329
346
|
if (footer !== undefined) {
|
|
330
347
|
rows.push("");
|
|
331
|
-
rows.push(styledMuted(footer, theme));
|
|
348
|
+
rows.push(`${pad}${styledMuted(footer, theme)}`);
|
|
332
349
|
}
|
|
333
|
-
|
|
350
|
+
const painted = rows.map((row) => paintRow(row, safeWidth, theme, tool.status));
|
|
351
|
+
const padRow = paintRow("", safeWidth, theme, tool.status);
|
|
352
|
+
return [padRow, ...painted, padRow];
|
|
334
353
|
}
|
|
335
354
|
|
|
336
355
|
/** Render one read-only host-style operator tool message block. */
|
|
@@ -28,6 +28,8 @@ export declare const askUserQuestionToolSystemPromptContribution: Readonly<{
|
|
|
28
28
|
readonly snippet: "Ask the user up to 4 structured questions (2-4 options each) when requirements are ambiguous";
|
|
29
29
|
readonly guidelines: readonly ["Use ask_user_question whenever the user's request is underspecified and you cannot proceed without concrete decisions — you can ask up to 4 questions per invocation.", "Each question MUST have 2-4 options. Every option requires a concise label (1-5 words) and a description explaining what the choice means or its trade-offs. The user can additionally type a custom answer (\"Type something.\" row is appended automatically to single-select questions) or pick \"Chat about this\" to abandon the questionnaire.", "Set multiSelect: true when multiple answers are valid; this suppresses the \"Type something.\" row. Provide an options[].preview markdown string when an option benefits from richer side-by-side context (mockups, code snippets, diagrams, configs) — single-select only. NOTE: any non-empty preview on a single-select question ALSO suppresses the \"Type something.\" row (no room in the side-by-side layout); \"Chat about this\" remains the escape hatch. If you recommend a specific option, make it the first option and append \"(Recommended)\" to its label.", "Do not stack multiple ask_user_question calls back-to-back — group all clarifying questions into one invocation."];
|
|
30
30
|
}>;
|
|
31
|
-
export declare function createAskUserQuestionToolDefinition(
|
|
31
|
+
export declare function createAskUserQuestionToolDefinition(options?: {
|
|
32
|
+
readonly chatAsOption?: boolean;
|
|
33
|
+
}): ToolDefinition<typeof QuestionParamsSchema, unknown>;
|
|
32
34
|
export { buildQuestionnaireResponse, buildToolResult };
|
|
33
35
|
//# sourceMappingURL=ask-user-question.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ask-user-question.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/ask-user-question/ask-user-question.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,OAAO,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC1F,OAAO,EAIN,KAAK,YAAY,EAGjB,oBAAoB,EACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAI/E;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,6BAA6B,EAAE,cAG3C,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,YAAY,GAAG,kBAAkB,EAAE,CAWlF;AAED,eAAO,MAAM,2CAA2C;;;EAQ7C,CAAC;AAEZ,wBAAgB,mCAAmC,
|
|
1
|
+
{"version":3,"file":"ask-user-question.d.ts","sourceRoot":"","sources":["../../../../src/core/tools/ask-user-question/ask-user-question.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,OAAO,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC1F,OAAO,EAIN,KAAK,YAAY,EAGjB,oBAAoB,EACpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sCAAsC,CAAC;AAI/E;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,6BAA6B,EAAE,cAG3C,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,YAAY,GAAG,kBAAkB,EAAE,CAWlF;AAED,eAAO,MAAM,2CAA2C;;;EAQ7C,CAAC;AAEZ,wBAAgB,mCAAmC,CAAC,OAAO,CAAC,EAAE;IAC7D,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;CAChC,GAAG,cAAc,CAAC,OAAO,oBAAoB,EAAE,OAAO,CAAC,CAmFvD;AAED,OAAO,EAAE,0BAA0B,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -50,7 +50,7 @@ export const askUserQuestionToolSystemPromptContribution = Object.freeze({
|
|
|
50
50
|
"Do not stack multiple ask_user_question calls back-to-back — group all clarifying questions into one invocation.",
|
|
51
51
|
]),
|
|
52
52
|
});
|
|
53
|
-
export function createAskUserQuestionToolDefinition() {
|
|
53
|
+
export function createAskUserQuestionToolDefinition(options) {
|
|
54
54
|
const guidance = validateGuidanceFields(loadConfig().guidance);
|
|
55
55
|
return {
|
|
56
56
|
name: "ask_user_question",
|
|
@@ -111,6 +111,7 @@ Preview content is rendered as markdown in a monospace box. Multi-line text with
|
|
|
111
111
|
params: typed,
|
|
112
112
|
itemsByTab,
|
|
113
113
|
done,
|
|
114
|
+
...(options?.chatAsOption === true ? { chatAsOption: true } : {}),
|
|
114
115
|
});
|
|
115
116
|
return session.component;
|
|
116
117
|
}, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ask-user-question.js","sourceRoot":"","sources":["../../../../src/core/tools/ask-user-question/ask-user-question.ts"],"names":[],"mappings":"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","sourcesContent":["import type { OverlayOptions } from \"@earendil-works/pi-tui\";\nimport { experimentalToolSamplingProperty } from \"../../experimental.ts\";\nimport type { ToolDefinition } from \"../../extensions/types.ts\";\nimport { loadConfig, validateGuidanceFields } from \"./config.ts\";\nimport { QuestionnaireSession } from \"./state/questionnaire-session.ts\";\nimport { ROW_INTENT_META, sentinelsToAppend } from \"./state/row-intent.ts\";\nimport { buildQuestionnaireResponse, buildToolResult } from \"./tool/response-envelope.ts\";\nimport {\n\tMAX_OPTIONS,\n\tMAX_QUESTIONS,\n\tMIN_OPTIONS,\n\ttype QuestionData,\n\ttype QuestionnaireResult,\n\ttype QuestionParams,\n\tQuestionParamsSchema,\n} from \"./tool/types.ts\";\nimport { validateQuestionnaire } from \"./tool/validate-questionnaire.ts\";\nimport type { WrappingSelectItem } from \"./view/components/wrapping-select.ts\";\n\nconst ERROR_NO_UI = \"Error: UI not available (running in non-interactive mode)\";\n\n/**\n * Mount options for the blocking questionnaire (#2378).\n *\n * The dialog used to mount inline, inside the fullscreen dock, where it is a\n * flex sibling of the transcript `ScrollView`. A tall side-by-side dialog then\n * took the transcript's rows: on a 40-row terminal the transcript viewport\n * collapsed from 34 rows to 6, and pi-tui derives its page step from that\n * viewport (`viewportHeight - PAGE_SCROLL_OVERLAP`), so PageUp crawled two\n * lines at a time through a six-line window.\n *\n * A bottom-anchored overlay is composited over the bottom rows instead of being\n * measured into the layout, so the transcript keeps its full viewport height\n * and its full page step. `reserveTranscriptRows` is what makes those rows\n * observable rather than merely addressable: the host bounds this overlay so a\n * transcript strip always survives, and extends the transcript's scroll extent\n * by the rows the overlay still covers, so the newest output can be raised into\n * that strip. No `maxHeight` — the host's bound is tighter, and letting pi-tui\n * slice as well would make the measured overlay height wrong.\n */\nexport const QUESTIONNAIRE_OVERLAY_OPTIONS: OverlayOptions = {\n\tanchor: \"bottom-center\",\n\twidth: \"100%\",\n};\n\nexport function buildItemsForQuestion(question: QuestionData): WrappingSelectItem[] {\n\tconst items: WrappingSelectItem[] = question.options.map((o) => ({\n\t\tkind: \"option\",\n\t\tlabel: o.label,\n\t\tdescription: o.description,\n\t}));\n\tconst hasAnyPreview = question.options.some((o) => typeof o.preview === \"string\" && o.preview.length > 0);\n\tfor (const kind of sentinelsToAppend(question, hasAnyPreview)) {\n\t\titems.push({ kind, label: ROW_INTENT_META[kind].label });\n\t}\n\treturn items;\n}\n\nexport const askUserQuestionToolSystemPromptContribution = Object.freeze({\n\tsnippet: `Ask the user up to ${MAX_QUESTIONS} structured questions (${MIN_OPTIONS}-${MAX_OPTIONS} options each) when requirements are ambiguous`,\n\tguidelines: Object.freeze([\n\t\t`Use ask_user_question whenever the user's request is underspecified and you cannot proceed without concrete decisions — you can ask up to ${MAX_QUESTIONS} questions per invocation.`,\n\t\t`Each question MUST have ${MIN_OPTIONS}-${MAX_OPTIONS} options. Every option requires a concise label (1-5 words) and a description explaining what the choice means or its trade-offs. The user can additionally type a custom answer (\"Type something.\" row is appended automatically to single-select questions) or pick \"Chat about this\" to abandon the questionnaire.`,\n\t\t`Set multiSelect: true when multiple answers are valid; this suppresses the \"Type something.\" row. Provide an options[].preview markdown string when an option benefits from richer side-by-side context (mockups, code snippets, diagrams, configs) — single-select only. NOTE: any non-empty preview on a single-select question ALSO suppresses the \"Type something.\" row (no room in the side-by-side layout); \"Chat about this\" remains the escape hatch. If you recommend a specific option, make it the first option and append \"(Recommended)\" to its label.`,\n\t\t\"Do not stack multiple ask_user_question calls back-to-back — group all clarifying questions into one invocation.\",\n\t] as const),\n} as const);\n\nexport function createAskUserQuestionToolDefinition(): ToolDefinition<typeof QuestionParamsSchema, unknown> {\n\tconst guidance = validateGuidanceFields(loadConfig().guidance);\n\treturn {\n\t\tname: \"ask_user_question\",\n\t\tlabel: \"Ask User Question\",\n\t\tdescription: `Ask the user one or more structured questions during execution. Use when you need to:\n1. Gather user preferences or requirements\n2. Clarify ambiguous instructions\n3. Get decisions on implementation choices as you work\n4. Offer choices to the user about what direction to take\n\nUsage notes:\n- Users will always be able to type a custom answer (\"Type something.\" row is appended automatically to every single-select question) or pick \"Chat about this\" to abandon the questionnaire and continue in free-form conversation. Do NOT author \"Other\" / \"Type something.\" / \"Chat about this\" labels yourself — duplicates are rejected at runtime.\n- Use multiSelect: true to allow multiple answers to be selected for a question. The \"Type something.\" row is suppressed on multi-select questions, and is ALSO suppressed on single-select questions where any option carries a \\`preview\\` (the side-by-side layout has no room for inline custom text — \"Chat about this\" remains as the free-form escape hatch).\n- If you recommend a specific option, make that the first option in the list and add \"(Recommended)\" at the end of the label.\n\nPreview feature:\nUse the optional \\`preview\\` field on options when presenting concrete artifacts that users need to visually compare:\n- ASCII mockups of UI layouts or components\n- Code snippets showing different implementations\n- Diagram variations\n- Configuration examples\n\nPreview content is rendered as markdown in a monospace box. Multi-line text with newlines is supported. When any option has a preview, the UI switches to a side-by-side layout with a vertical option list on the left and preview on the right. Do not use previews for simple preference questions where labels and descriptions suffice. Note: previews are only supported for single-select questions (not multiSelect).`,\n\t\tpromptSnippet: guidance.promptSnippet ?? askUserQuestionToolSystemPromptContribution.snippet,\n\t\tpromptGuidelines: guidance.promptGuidelines ?? [...askUserQuestionToolSystemPromptContribution.guidelines],\n\t\t...experimentalToolSamplingProperty(),\n\t\tparameters: QuestionParamsSchema,\n\n\t\tasync execute(_toolCallId, params, signal, _onUpdate, ctx) {\n\t\t\tconst typed = params as unknown as QuestionParams;\n\t\t\tif (!ctx.hasUI) return buildToolResult(ERROR_NO_UI, { answers: [], cancelled: true, error: \"no_ui\" });\n\n\t\t\tconst validation = validateQuestionnaire(typed);\n\t\t\tif (!validation.ok) {\n\t\t\t\treturn buildToolResult(validation.message, {\n\t\t\t\t\tanswers: [],\n\t\t\t\t\tcancelled: true,\n\t\t\t\t\terror: validation.error,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst itemsByTab: WrappingSelectItem[][] = typed.questions.map((q) => buildItemsForQuestion(q));\n\n\t\t\t// Suspend the animated working loader for the lifetime of the blocking dialog.\n\t\t\t//\n\t\t\t// The loader ticks every ~88ms and calls `requestRender()` on each frame, and it\n\t\t\t// conveys nothing while we are blocked on human input. Hiding it for the duration\n\t\t\t// keeps the frame behind the dialog static and avoids the differential renderer\n\t\t\t// falling back to a full clear+replay (`\\x1b[2J\\x1b[H\\x1b[3J`) on every tick.\n\t\t\t// Restored once the dialog closes (on every path).\n\t\t\t//\n\t\t\t// Guarded: some hosts (e.g. the workflow stage-UI broker) pass a minimal UI\n\t\t\t// context that only implements `custom`, so treat a missing loader control as a\n\t\t\t// no-op rather than throwing.\n\t\t\tctx.ui.setWorkingVisible?.(false);\n\t\t\ttry {\n\t\t\t\tconst result = await ctx.ui.custom<QuestionnaireResult>(\n\t\t\t\t\t(tui, theme, _kb, done) => {\n\t\t\t\t\t\tconst session = new QuestionnaireSession({\n\t\t\t\t\t\t\ttui,\n\t\t\t\t\t\t\ttheme,\n\t\t\t\t\t\t\tparams: typed,\n\t\t\t\t\t\t\titemsByTab,\n\t\t\t\t\t\t\tdone,\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn session.component;\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\toverlay: true,\n\t\t\t\t\t\treserveTranscriptRows: true,\n\t\t\t\t\t\toverlayOptions: QUESTIONNAIRE_OVERLAY_OPTIONS,\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\treturn buildQuestionnaireResponse(result, typed);\n\t\t\t} finally {\n\t\t\t\tctx.ui.setWorkingVisible?.(true);\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport { buildQuestionnaireResponse, buildToolResult };\n"]}
|
|
1
|
+
{"version":3,"file":"ask-user-question.js","sourceRoot":"","sources":["../../../../src/core/tools/ask-user-question/ask-user-question.ts"],"names":[],"mappings":"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","sourcesContent":["import type { OverlayOptions } from \"@earendil-works/pi-tui\";\nimport { experimentalToolSamplingProperty } from \"../../experimental.ts\";\nimport type { ToolDefinition } from \"../../extensions/types.ts\";\nimport { loadConfig, validateGuidanceFields } from \"./config.ts\";\nimport { QuestionnaireSession } from \"./state/questionnaire-session.ts\";\nimport { ROW_INTENT_META, sentinelsToAppend } from \"./state/row-intent.ts\";\nimport { buildQuestionnaireResponse, buildToolResult } from \"./tool/response-envelope.ts\";\nimport {\n\tMAX_OPTIONS,\n\tMAX_QUESTIONS,\n\tMIN_OPTIONS,\n\ttype QuestionData,\n\ttype QuestionnaireResult,\n\ttype QuestionParams,\n\tQuestionParamsSchema,\n} from \"./tool/types.ts\";\nimport { validateQuestionnaire } from \"./tool/validate-questionnaire.ts\";\nimport type { WrappingSelectItem } from \"./view/components/wrapping-select.ts\";\n\nconst ERROR_NO_UI = \"Error: UI not available (running in non-interactive mode)\";\n\n/**\n * Mount options for the blocking questionnaire (#2378).\n *\n * The dialog used to mount inline, inside the fullscreen dock, where it is a\n * flex sibling of the transcript `ScrollView`. A tall side-by-side dialog then\n * took the transcript's rows: on a 40-row terminal the transcript viewport\n * collapsed from 34 rows to 6, and pi-tui derives its page step from that\n * viewport (`viewportHeight - PAGE_SCROLL_OVERLAP`), so PageUp crawled two\n * lines at a time through a six-line window.\n *\n * A bottom-anchored overlay is composited over the bottom rows instead of being\n * measured into the layout, so the transcript keeps its full viewport height\n * and its full page step. `reserveTranscriptRows` is what makes those rows\n * observable rather than merely addressable: the host bounds this overlay so a\n * transcript strip always survives, and extends the transcript's scroll extent\n * by the rows the overlay still covers, so the newest output can be raised into\n * that strip. No `maxHeight` — the host's bound is tighter, and letting pi-tui\n * slice as well would make the measured overlay height wrong.\n */\nexport const QUESTIONNAIRE_OVERLAY_OPTIONS: OverlayOptions = {\n\tanchor: \"bottom-center\",\n\twidth: \"100%\",\n};\n\nexport function buildItemsForQuestion(question: QuestionData): WrappingSelectItem[] {\n\tconst items: WrappingSelectItem[] = question.options.map((o) => ({\n\t\tkind: \"option\",\n\t\tlabel: o.label,\n\t\tdescription: o.description,\n\t}));\n\tconst hasAnyPreview = question.options.some((o) => typeof o.preview === \"string\" && o.preview.length > 0);\n\tfor (const kind of sentinelsToAppend(question, hasAnyPreview)) {\n\t\titems.push({ kind, label: ROW_INTENT_META[kind].label });\n\t}\n\treturn items;\n}\n\nexport const askUserQuestionToolSystemPromptContribution = Object.freeze({\n\tsnippet: `Ask the user up to ${MAX_QUESTIONS} structured questions (${MIN_OPTIONS}-${MAX_OPTIONS} options each) when requirements are ambiguous`,\n\tguidelines: Object.freeze([\n\t\t`Use ask_user_question whenever the user's request is underspecified and you cannot proceed without concrete decisions — you can ask up to ${MAX_QUESTIONS} questions per invocation.`,\n\t\t`Each question MUST have ${MIN_OPTIONS}-${MAX_OPTIONS} options. Every option requires a concise label (1-5 words) and a description explaining what the choice means or its trade-offs. The user can additionally type a custom answer (\"Type something.\" row is appended automatically to single-select questions) or pick \"Chat about this\" to abandon the questionnaire.`,\n\t\t`Set multiSelect: true when multiple answers are valid; this suppresses the \"Type something.\" row. Provide an options[].preview markdown string when an option benefits from richer side-by-side context (mockups, code snippets, diagrams, configs) — single-select only. NOTE: any non-empty preview on a single-select question ALSO suppresses the \"Type something.\" row (no room in the side-by-side layout); \"Chat about this\" remains the escape hatch. If you recommend a specific option, make it the first option and append \"(Recommended)\" to its label.`,\n\t\t\"Do not stack multiple ask_user_question calls back-to-back — group all clarifying questions into one invocation.\",\n\t] as const),\n} as const);\n\nexport function createAskUserQuestionToolDefinition(options?: {\n\treadonly chatAsOption?: boolean;\n}): ToolDefinition<typeof QuestionParamsSchema, unknown> {\n\tconst guidance = validateGuidanceFields(loadConfig().guidance);\n\treturn {\n\t\tname: \"ask_user_question\",\n\t\tlabel: \"Ask User Question\",\n\t\tdescription: `Ask the user one or more structured questions during execution. Use when you need to:\n1. Gather user preferences or requirements\n2. Clarify ambiguous instructions\n3. Get decisions on implementation choices as you work\n4. Offer choices to the user about what direction to take\n\nUsage notes:\n- Users will always be able to type a custom answer (\"Type something.\" row is appended automatically to every single-select question) or pick \"Chat about this\" to abandon the questionnaire and continue in free-form conversation. Do NOT author \"Other\" / \"Type something.\" / \"Chat about this\" labels yourself — duplicates are rejected at runtime.\n- Use multiSelect: true to allow multiple answers to be selected for a question. The \"Type something.\" row is suppressed on multi-select questions, and is ALSO suppressed on single-select questions where any option carries a \\`preview\\` (the side-by-side layout has no room for inline custom text — \"Chat about this\" remains as the free-form escape hatch).\n- If you recommend a specific option, make that the first option in the list and add \"(Recommended)\" at the end of the label.\n\nPreview feature:\nUse the optional \\`preview\\` field on options when presenting concrete artifacts that users need to visually compare:\n- ASCII mockups of UI layouts or components\n- Code snippets showing different implementations\n- Diagram variations\n- Configuration examples\n\nPreview content is rendered as markdown in a monospace box. Multi-line text with newlines is supported. When any option has a preview, the UI switches to a side-by-side layout with a vertical option list on the left and preview on the right. Do not use previews for simple preference questions where labels and descriptions suffice. Note: previews are only supported for single-select questions (not multiSelect).`,\n\t\tpromptSnippet: guidance.promptSnippet ?? askUserQuestionToolSystemPromptContribution.snippet,\n\t\tpromptGuidelines: guidance.promptGuidelines ?? [...askUserQuestionToolSystemPromptContribution.guidelines],\n\t\t...experimentalToolSamplingProperty(),\n\t\tparameters: QuestionParamsSchema,\n\n\t\tasync execute(_toolCallId, params, signal, _onUpdate, ctx) {\n\t\t\tconst typed = params as unknown as QuestionParams;\n\t\t\tif (!ctx.hasUI) return buildToolResult(ERROR_NO_UI, { answers: [], cancelled: true, error: \"no_ui\" });\n\n\t\t\tconst validation = validateQuestionnaire(typed);\n\t\t\tif (!validation.ok) {\n\t\t\t\treturn buildToolResult(validation.message, {\n\t\t\t\t\tanswers: [],\n\t\t\t\t\tcancelled: true,\n\t\t\t\t\terror: validation.error,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst itemsByTab: WrappingSelectItem[][] = typed.questions.map((q) => buildItemsForQuestion(q));\n\n\t\t\t// Suspend the animated working loader for the lifetime of the blocking dialog.\n\t\t\t//\n\t\t\t// The loader ticks every ~88ms and calls `requestRender()` on each frame, and it\n\t\t\t// conveys nothing while we are blocked on human input. Hiding it for the duration\n\t\t\t// keeps the frame behind the dialog static and avoids the differential renderer\n\t\t\t// falling back to a full clear+replay (`\\x1b[2J\\x1b[H\\x1b[3J`) on every tick.\n\t\t\t// Restored once the dialog closes (on every path).\n\t\t\t//\n\t\t\t// Guarded: some hosts (e.g. the workflow stage-UI broker) pass a minimal UI\n\t\t\t// context that only implements `custom`, so treat a missing loader control as a\n\t\t\t// no-op rather than throwing.\n\t\t\tctx.ui.setWorkingVisible?.(false);\n\t\t\ttry {\n\t\t\t\tconst result = await ctx.ui.custom<QuestionnaireResult>(\n\t\t\t\t\t(tui, theme, _kb, done) => {\n\t\t\t\t\t\tconst session = new QuestionnaireSession({\n\t\t\t\t\t\t\ttui,\n\t\t\t\t\t\t\ttheme,\n\t\t\t\t\t\t\tparams: typed,\n\t\t\t\t\t\t\titemsByTab,\n\t\t\t\t\t\t\tdone,\n\t\t\t\t\t\t\t...(options?.chatAsOption === true ? { chatAsOption: true } : {}),\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn session.component;\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tsignal,\n\t\t\t\t\t\toverlay: true,\n\t\t\t\t\t\treserveTranscriptRows: true,\n\t\t\t\t\t\toverlayOptions: QUESTIONNAIRE_OVERLAY_OPTIONS,\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\treturn buildQuestionnaireResponse(result, typed);\n\t\t\t} finally {\n\t\t\t\tctx.ui.setWorkingVisible?.(true);\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport { buildQuestionnaireResponse, buildToolResult };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-questionnaire.d.ts","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/build-questionnaire.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAC/C,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,8CAA8C,CAAC;AAC5F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAgBrD,OAAO,KAAK,EAAE,kBAAkB,EAAuB,MAAM,uCAAuC,CAAC;AAErG,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAerE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,WAAW,wBAAwB;IACxC,GAAG,EAAE;QAAE,QAAQ,EAAE;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,aAAa,IAAI,IAAI,CAAA;KAAE,CAAC;IAC9D,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,SAAS,YAAY,EAAE,CAAC;IACnC,UAAU,EAAE,aAAa,CAAC,SAAS,kBAAkB,EAAE,CAAC,CAAC;IACzD,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,kBAAkB,CAAC;IACjC,aAAa,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"build-questionnaire.d.ts","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/build-questionnaire.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAC/C,OAAO,EAAoB,KAAK,KAAK,EAAE,MAAM,8CAA8C,CAAC;AAC5F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAgBrD,OAAO,KAAK,EAAE,kBAAkB,EAAuB,MAAM,uCAAuC,CAAC;AAErG,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAerE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,WAAW,wBAAwB;IACxC,GAAG,EAAE;QAAE,QAAQ,EAAE;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,aAAa,IAAI,IAAI,CAAA;KAAE,CAAC;IAC9D,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,SAAS,YAAY,EAAE,CAAC;IACnC,UAAU,EAAE,aAAa,CAAC,SAAS,kBAAkB,EAAE,CAAC,CAAC;IACzD,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,kBAAkB,CAAC;IACjC,aAAa,EAAE,MAAM,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IAClC,OAAO,EAAE,yBAAyB,CAAC;IACnC,UAAU,EAAE,KAAK,CAAC;IAClB,WAAW,EAAE,KAAK,CAAC;IACnB,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IACpC,UAAU,EAAE,MAAM,IAAI,CAAC;CACvB;AAwBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,wBAAwB,GAAG,kBAAkB,CAEvF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-questionnaire.js","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/build-questionnaire.ts"],"names":[],"mappings":"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","sourcesContent":["import { Input } from \"@earendil-works/pi-tui\";\nimport { getMarkdownTheme, type Theme } from \"../../../../modes/interactive/theme/theme.ts\";\nimport type { QuestionData } from \"../tool/types.ts\";\nimport {\n\ttype BoundGlobalBinding,\n\ttype BoundPerTabBinding,\n\tglobalBinding,\n\tperTabBinding,\n} from \"../view/component-binding.ts\";\nimport { ChatRowView } from \"../view/components/chat-row-view.ts\";\nimport { MultiSelectView } from \"../view/components/multi-select-view.ts\";\nimport { OptionListView } from \"../view/components/option-list-view.ts\";\nimport { PreviewBlockRenderer } from \"../view/components/preview/preview-block-renderer.ts\";\nimport { crossTabLeftWidthWithDonation } from \"../view/components/preview/preview-layout-decider.ts\";\nimport type { PreviewPaneProps } from \"../view/components/preview/preview-pane.ts\";\nimport { PreviewPane } from \"../view/components/preview/preview-pane.ts\";\nimport { SubmitPicker } from \"../view/components/submit-picker.ts\";\nimport { TabBar } from \"../view/components/tab-bar.ts\";\nimport type { WrappingSelectItem, WrappingSelectTheme } from \"../view/components/wrapping-select.ts\";\nimport { DialogView } from \"../view/dialog-builder.ts\";\nimport { QuestionnairePropsAdapter } from \"../view/props-adapter.ts\";\nimport type { StatefulView } from \"../view/stateful-view.ts\";\nimport type { TabBodyHeights, TabComponents } from \"../view/tab-components.ts\";\nimport { ROW_INTENT_META } from \"./row-intent.ts\";\nimport type { PerTabSelector } from \"./selectors/contract.ts\";\nimport { selectActivePreviewPaneIndex } from \"./selectors/derivations.ts\";\nimport {\n\tselectChatRowProps,\n\tselectDialogProps,\n\tselectMultiSelectProps,\n\tselectOptionListProps,\n\tselectPreviewPaneProps,\n\tselectSubmitPickerProps,\n\tselectTabBarProps,\n} from \"./selectors/projections.ts\";\nimport type { QuestionnaireState } from \"./state.ts\";\n\nexport interface QuestionnaireBuildConfig {\n\ttui: { terminal: { columns: number }; requestRender(): void };\n\ttheme: Theme;\n\tquestions: readonly QuestionData[];\n\titemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n\tisMulti: boolean;\n\tinitialState: QuestionnaireState;\n\tgetCurrentTab: () => number;\n}\n\nexport interface QuestionnaireBuilt {\n\tadapter: QuestionnairePropsAdapter;\n\tnotesInput: Input;\n\tinlineInput: Input;\n\trender: (width: number) => string[];\n\tinvalidate: () => void;\n}\n\ninterface HeightComputers {\n\tglobal: (width: number) => number;\n\tcurrent: (width: number) => number;\n}\n\nfunction previewBodyHeights(pane: PreviewPane): (width: number) => TabBodyHeights {\n\treturn (width) => ({\n\t\tcurrent: pane.naturalHeight(width),\n\t\tmax: pane.maxNaturalHeight(width),\n\t});\n}\n\nfunction multiSelectBodyHeights(view: MultiSelectView): (width: number) => TabBodyHeights {\n\treturn (width) => {\n\t\tconst h = view.naturalHeight(width);\n\t\treturn { current: h, max: h };\n\t};\n}\n\nconst isActiveTab: PerTabSelector<boolean> = (s, ctx) =>\n\tctx.i === selectActivePreviewPaneIndex(s.currentTab, ctx.totalQuestions);\n\n/**\n * Pure factory: assembles every TUI component, the props adapter, and a\n * lifecycle handle. Session-state dependencies arrive via `getCurrentTab` and\n * the `inputBuffer` cell. Initial paint is delegated to\n * `adapter.apply(initialState)` (called by the session at construction-end);\n * no selector is invoked here.\n */\nexport function buildQuestionnaire(config: QuestionnaireBuildConfig): QuestionnaireBuilt {\n\treturn new QuestionnaireBuilder(config).build();\n}\n\n/**\n * Programming-by-intention assembly: each private method names one\n * construction step from `build()`. Read top-down; the class is build-only and\n * discarded once the handle is returned.\n */\nclass QuestionnaireBuilder {\n\tprivate readonly tui: QuestionnaireBuildConfig[\"tui\"];\n\tprivate readonly theme: Theme;\n\tprivate readonly questions: readonly QuestionData[];\n\tprivate readonly itemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n\tprivate readonly isMulti: boolean;\n\tprivate readonly initialState: QuestionnaireState;\n\tprivate readonly getCurrentTab: () => number;\n\n\tprivate readonly selectTheme: WrappingSelectTheme;\n\tprivate readonly markdownTheme = getMarkdownTheme();\n\tprivate readonly chatRow: ChatRowView;\n\tprivate readonly notesInput = new Input();\n\tprivate readonly inlineInput = new Input();\n\tprivate readonly getTerminalWidth = () => this.tui.terminal.columns;\n\n\tconstructor(config: QuestionnaireBuildConfig) {\n\t\tthis.tui = config.tui;\n\t\tthis.theme = config.theme;\n\t\tthis.questions = config.questions;\n\t\tthis.itemsByTab = config.itemsByTab;\n\t\tthis.isMulti = config.isMulti;\n\t\tthis.initialState = config.initialState;\n\t\tthis.getCurrentTab = config.getCurrentTab;\n\n\t\tthis.selectTheme = this.makeSelectTheme();\n\t\tthis.chatRow = new ChatRowView({\n\t\t\titem: { kind: \"chat\", label: ROW_INTENT_META.chat.label },\n\t\t\ttheme: this.selectTheme,\n\t\t});\n\t}\n\n\tbuild(): QuestionnaireBuilt {\n\t\tconst tabs = this.buildTabComponents();\n\t\tthis.injectGlobalLeftWidth(tabs);\n\t\tconst submitPicker = this.buildSubmitPicker();\n\t\tconst tabBar = this.buildTabBar();\n\t\tconst heights = this.buildHeightComputers(tabs);\n\t\tconst dialog = this.buildDialog(tabs, submitPicker, tabBar, heights);\n\t\tconst globalBindings = this.buildGlobalBindings(dialog, submitPicker, tabBar);\n\t\tconst perTabBindings = this.buildPerTabBindings();\n\t\tconst adapter = this.buildAdapter(tabs, globalBindings, perTabBindings);\n\t\treturn this.handle(adapter, dialog);\n\t}\n\n\tprivate makeSelectTheme(): WrappingSelectTheme {\n\t\tconst t = this.theme;\n\t\treturn {\n\t\t\tselectedText: (s) => t.fg(\"accent\", t.bold(s)),\n\t\t\tdescription: (s) => t.fg(\"muted\", s),\n\t\t\tscrollInfo: (s) => t.fg(\"dim\", s),\n\t\t};\n\t}\n\n\tprivate buildTabComponents(): ReadonlyArray<TabComponents> {\n\t\treturn this.questions.map((q, i) => this.buildTabFor(q, i));\n\t}\n\n\tprivate buildTabFor(question: QuestionData, index: number): TabComponents {\n\t\tconst optionList = new OptionListView({\n\t\t\titems: this.itemsByTab[index] ?? [],\n\t\t\ttheme: this.selectTheme,\n\t\t});\n\t\tconst previewBlock = new PreviewBlockRenderer({\n\t\t\tquestion,\n\t\t\ttheme: this.theme,\n\t\t\tmarkdownTheme: this.markdownTheme,\n\t\t});\n\t\tconst preview = new PreviewPane({\n\t\t\tquestion,\n\t\t\tgetTerminalWidth: this.getTerminalWidth,\n\t\t\toptionListView: optionList,\n\t\t\tpreviewBlock,\n\t\t});\n\t\tconst multiSelect = question.multiSelect ? new MultiSelectView(this.theme, question) : undefined;\n\t\tconst bodyHeights = this.buildBodyHeights(question, preview, multiSelect);\n\t\treturn { optionList, preview, multiSelect, bodyHeights };\n\t}\n\n\tprivate buildBodyHeights(\n\t\tquestion: QuestionData,\n\t\tpreview: PreviewPane,\n\t\tmultiSelect: MultiSelectView | undefined,\n\t): (width: number) => TabBodyHeights {\n\t\treturn question.multiSelect ? multiSelectBodyHeights(multiSelect!) : previewBodyHeights(preview);\n\t}\n\n\t/**\n\t * Compute cross-tab max adaptive left width and inject into each PreviewPane.\n\t * Mirrors buildHeightComputers pattern — iterates all tabs, takes max.\n\t * Called after buildTabComponents, before buildDialog (so setGlobalLeftWidth\n\t * is set before any rendering occurs).\n\t */\n\tprivate injectGlobalLeftWidth(tabs: ReadonlyArray<TabComponents>): void {\n\t\tconst questions = this.questions;\n\t\tconst itemsByTab = this.itemsByTab;\n\t\tconst tabsDescriptor = questions.map((q) => ({ multiSelect: q.multiSelect }));\n\t\tconst globalLeftWidth = (paneWidth: number): number =>\n\t\t\tcrossTabLeftWidthWithDonation(tabsDescriptor, itemsByTab, questions, paneWidth);\n\t\tfor (const tab of tabs) {\n\t\t\ttab.preview.setGlobalLeftWidth(globalLeftWidth);\n\t\t}\n\t}\n\n\tprivate buildSubmitPicker(): SubmitPicker | undefined {\n\t\treturn this.isMulti ? new SubmitPicker(this.theme) : undefined;\n\t}\n\n\tprivate buildTabBar(): TabBar | undefined {\n\t\treturn this.isMulti ? new TabBar(this.theme) : undefined;\n\t}\n\n\tprivate buildHeightComputers(tabs: ReadonlyArray<TabComponents>): HeightComputers {\n\t\tconst global = (width: number): number => {\n\t\t\tlet max = 0;\n\t\t\tfor (const tab of tabs) {\n\t\t\t\tconst h = tab.bodyHeights(width).max;\n\t\t\t\tif (h > max) max = h;\n\t\t\t}\n\t\t\treturn Math.max(1, max);\n\t\t};\n\t\tconst current = (width: number): number => {\n\t\t\tconst idx = Math.min(this.getCurrentTab(), tabs.length - 1);\n\t\t\treturn Math.max(0, tabs[idx]?.bodyHeights(width).current ?? 0);\n\t\t};\n\t\treturn { global, current };\n\t}\n\n\tprivate pickInitialActivePreview(tabs: ReadonlyArray<TabComponents>): StatefulView<PreviewPaneProps> {\n\t\tconst idx = selectActivePreviewPaneIndex(this.initialState.currentTab, this.questions.length);\n\t\treturn tabs[idx]?.preview ?? tabs[0]!.preview;\n\t}\n\n\tprivate buildDialog(\n\t\ttabs: ReadonlyArray<TabComponents>,\n\t\tsubmitPicker: SubmitPicker | undefined,\n\t\ttabBar: TabBar | undefined,\n\t\theights: HeightComputers,\n\t): DialogView {\n\t\treturn new DialogView(\n\t\t\t{\n\t\t\t\ttheme: this.theme,\n\t\t\t\tquestions: this.questions,\n\t\t\t\ttabBar,\n\t\t\t\tnotesInput: this.notesInput,\n\t\t\t\tchatRow: this.chatRow,\n\t\t\t\tisMulti: this.isMulti,\n\t\t\t\ttabsByIndex: tabs,\n\t\t\t\tsubmitPicker,\n\t\t\t\tgetBodyHeight: heights.global,\n\t\t\t\tgetCurrentBodyHeight: heights.current,\n\t\t\t},\n\t\t\t{ state: this.initialState, activePreviewPane: this.pickInitialActivePreview(tabs) },\n\t\t);\n\t}\n\n\tprivate buildGlobalBindings(\n\t\tdialog: DialogView,\n\t\tsubmitPicker: SubmitPicker | undefined,\n\t\ttabBar: TabBar | undefined,\n\t): ReadonlyArray<BoundGlobalBinding> {\n\t\treturn [\n\t\t\tglobalBinding({ component: dialog, select: selectDialogProps }),\n\t\t\tglobalBinding({ component: this.chatRow, select: selectChatRowProps }),\n\t\t\t...(submitPicker ? [globalBinding({ component: submitPicker, select: selectSubmitPickerProps })] : []),\n\t\t\t...(tabBar ? [globalBinding({ component: tabBar, select: selectTabBarProps })] : []),\n\t\t];\n\t}\n\n\tprivate buildPerTabBindings(): ReadonlyArray<BoundPerTabBinding> {\n\t\treturn [\n\t\t\tperTabBinding({\n\t\t\t\tresolve: (tab) => tab.optionList,\n\t\t\t\tpredicate: isActiveTab,\n\t\t\t\tselect: selectOptionListProps,\n\t\t\t}),\n\t\t\tperTabBinding({\n\t\t\t\tresolve: (tab) => tab.preview,\n\t\t\t\tpredicate: isActiveTab,\n\t\t\t\tselect: selectPreviewPaneProps,\n\t\t\t}),\n\t\t\tperTabBinding({\n\t\t\t\tresolve: (tab) => tab.multiSelect,\n\t\t\t\tselect: selectMultiSelectProps,\n\t\t\t}),\n\t\t];\n\t}\n\n\tprivate buildAdapter(\n\t\ttabs: ReadonlyArray<TabComponents>,\n\t\tglobalBindings: ReadonlyArray<BoundGlobalBinding>,\n\t\tperTabBindings: ReadonlyArray<BoundPerTabBinding>,\n\t): QuestionnairePropsAdapter {\n\t\treturn new QuestionnairePropsAdapter({\n\t\t\ttui: this.tui,\n\t\t\tquestions: this.questions,\n\t\t\titemsByTab: this.itemsByTab,\n\t\t\ttabsByIndex: tabs,\n\t\t\tinlineInput: this.inlineInput,\n\t\t\tglobalBindings,\n\t\t\tperTabBindings,\n\t\t\textraInvalidatables: [this.notesInput],\n\t\t});\n\t}\n\n\tprivate handle(adapter: QuestionnairePropsAdapter, dialog: DialogView): QuestionnaireBuilt {\n\t\treturn {\n\t\t\tadapter,\n\t\t\tnotesInput: this.notesInput,\n\t\t\tinlineInput: this.inlineInput,\n\t\t\trender: (w) => dialog.render(w),\n\t\t\tinvalidate: () => adapter.invalidate(),\n\t\t};\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"build-questionnaire.js","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/build-questionnaire.ts"],"names":[],"mappings":"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","sourcesContent":["import { Input } from \"@earendil-works/pi-tui\";\nimport { getMarkdownTheme, type Theme } from \"../../../../modes/interactive/theme/theme.ts\";\nimport type { QuestionData } from \"../tool/types.ts\";\nimport {\n\ttype BoundGlobalBinding,\n\ttype BoundPerTabBinding,\n\tglobalBinding,\n\tperTabBinding,\n} from \"../view/component-binding.ts\";\nimport { ChatRowView } from \"../view/components/chat-row-view.ts\";\nimport { MultiSelectView } from \"../view/components/multi-select-view.ts\";\nimport { OptionListView } from \"../view/components/option-list-view.ts\";\nimport { PreviewBlockRenderer } from \"../view/components/preview/preview-block-renderer.ts\";\nimport { crossTabLeftWidthWithDonation } from \"../view/components/preview/preview-layout-decider.ts\";\nimport type { PreviewPaneProps } from \"../view/components/preview/preview-pane.ts\";\nimport { PreviewPane } from \"../view/components/preview/preview-pane.ts\";\nimport { SubmitPicker } from \"../view/components/submit-picker.ts\";\nimport { TabBar } from \"../view/components/tab-bar.ts\";\nimport type { WrappingSelectItem, WrappingSelectTheme } from \"../view/components/wrapping-select.ts\";\nimport { DialogView } from \"../view/dialog-builder.ts\";\nimport { QuestionnairePropsAdapter } from \"../view/props-adapter.ts\";\nimport type { StatefulView } from \"../view/stateful-view.ts\";\nimport type { TabBodyHeights, TabComponents } from \"../view/tab-components.ts\";\nimport { ROW_INTENT_META } from \"./row-intent.ts\";\nimport type { PerTabSelector } from \"./selectors/contract.ts\";\nimport { selectActivePreviewPaneIndex } from \"./selectors/derivations.ts\";\nimport {\n\tselectChatRowProps,\n\tselectDialogProps,\n\tselectMultiSelectProps,\n\tselectOptionListProps,\n\tselectPreviewPaneProps,\n\tselectSubmitPickerProps,\n\tselectTabBarProps,\n} from \"./selectors/projections.ts\";\nimport type { QuestionnaireState } from \"./state.ts\";\n\nexport interface QuestionnaireBuildConfig {\n\ttui: { terminal: { columns: number }; requestRender(): void };\n\ttheme: Theme;\n\tquestions: readonly QuestionData[];\n\titemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n\tisMulti: boolean;\n\tinitialState: QuestionnaireState;\n\tgetCurrentTab: () => number;\n\tchatAsOption?: boolean;\n}\n\nexport interface QuestionnaireBuilt {\n\tadapter: QuestionnairePropsAdapter;\n\tnotesInput: Input;\n\tinlineInput: Input;\n\trender: (width: number) => string[];\n\tinvalidate: () => void;\n}\n\ninterface HeightComputers {\n\tglobal: (width: number) => number;\n\tcurrent: (width: number) => number;\n}\n\nfunction previewBodyHeights(pane: PreviewPane): (width: number) => TabBodyHeights {\n\treturn (width) => ({\n\t\tcurrent: pane.naturalHeight(width),\n\t\tmax: pane.maxNaturalHeight(width),\n\t});\n}\n\nfunction multiSelectBodyHeights(view: MultiSelectView): (width: number) => TabBodyHeights {\n\treturn (width) => {\n\t\tconst h = view.naturalHeight(width);\n\t\treturn { current: h, max: h };\n\t};\n}\n\nconst isActiveTab: PerTabSelector<boolean> = (s, ctx) =>\n\tctx.i === selectActivePreviewPaneIndex(s.currentTab, ctx.totalQuestions);\n\n/**\n * Pure factory: assembles every TUI component, the props adapter, and a\n * lifecycle handle. Session-state dependencies arrive via `getCurrentTab` and\n * the `inputBuffer` cell. Initial paint is delegated to\n * `adapter.apply(initialState)` (called by the session at construction-end);\n * no selector is invoked here.\n */\nexport function buildQuestionnaire(config: QuestionnaireBuildConfig): QuestionnaireBuilt {\n\treturn new QuestionnaireBuilder(config).build();\n}\n\n/**\n * Programming-by-intention assembly: each private method names one\n * construction step from `build()`. Read top-down; the class is build-only and\n * discarded once the handle is returned.\n */\nclass QuestionnaireBuilder {\n\tprivate readonly tui: QuestionnaireBuildConfig[\"tui\"];\n\tprivate readonly theme: Theme;\n\tprivate readonly questions: readonly QuestionData[];\n\tprivate readonly itemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>;\n\tprivate readonly isMulti: boolean;\n\tprivate readonly initialState: QuestionnaireState;\n\tprivate readonly getCurrentTab: () => number;\n\n\tprivate readonly selectTheme: WrappingSelectTheme;\n\tprivate readonly markdownTheme = getMarkdownTheme();\n\tprivate readonly chatRow: ChatRowView;\n\tprivate readonly notesInput = new Input();\n\tprivate readonly inlineInput = new Input();\n\tprivate readonly getTerminalWidth = () => this.tui.terminal.columns;\n\n\tconstructor(config: QuestionnaireBuildConfig) {\n\t\tthis.tui = config.tui;\n\t\tthis.theme = config.theme;\n\t\tthis.questions = config.questions;\n\t\tthis.itemsByTab = config.itemsByTab;\n\t\tthis.isMulti = config.isMulti;\n\t\tthis.initialState = config.initialState;\n\t\tthis.getCurrentTab = config.getCurrentTab;\n\n\t\tthis.selectTheme = this.makeSelectTheme();\n\t\tthis.chatRow = new ChatRowView({\n\t\t\titem: { kind: \"chat\", label: ROW_INTENT_META.chat.label },\n\t\t\ttheme: this.selectTheme,\n\t\t\tinlineInputEnabled: config.chatAsOption !== true,\n\t\t});\n\t}\n\n\tbuild(): QuestionnaireBuilt {\n\t\tconst tabs = this.buildTabComponents();\n\t\tthis.injectGlobalLeftWidth(tabs);\n\t\tconst submitPicker = this.buildSubmitPicker();\n\t\tconst tabBar = this.buildTabBar();\n\t\tconst heights = this.buildHeightComputers(tabs);\n\t\tconst dialog = this.buildDialog(tabs, submitPicker, tabBar, heights);\n\t\tconst globalBindings = this.buildGlobalBindings(dialog, submitPicker, tabBar);\n\t\tconst perTabBindings = this.buildPerTabBindings();\n\t\tconst adapter = this.buildAdapter(tabs, globalBindings, perTabBindings);\n\t\treturn this.handle(adapter, dialog);\n\t}\n\n\tprivate makeSelectTheme(): WrappingSelectTheme {\n\t\tconst t = this.theme;\n\t\treturn {\n\t\t\tselectedText: (s) => t.fg(\"accent\", t.bold(s)),\n\t\t\tdescription: (s) => t.fg(\"muted\", s),\n\t\t\tscrollInfo: (s) => t.fg(\"dim\", s),\n\t\t};\n\t}\n\n\tprivate buildTabComponents(): ReadonlyArray<TabComponents> {\n\t\treturn this.questions.map((q, i) => this.buildTabFor(q, i));\n\t}\n\n\tprivate buildTabFor(question: QuestionData, index: number): TabComponents {\n\t\tconst optionList = new OptionListView({\n\t\t\titems: this.itemsByTab[index] ?? [],\n\t\t\ttheme: this.selectTheme,\n\t\t});\n\t\tconst previewBlock = new PreviewBlockRenderer({\n\t\t\tquestion,\n\t\t\ttheme: this.theme,\n\t\t\tmarkdownTheme: this.markdownTheme,\n\t\t});\n\t\tconst preview = new PreviewPane({\n\t\t\tquestion,\n\t\t\tgetTerminalWidth: this.getTerminalWidth,\n\t\t\toptionListView: optionList,\n\t\t\tpreviewBlock,\n\t\t});\n\t\tconst multiSelect = question.multiSelect ? new MultiSelectView(this.theme, question) : undefined;\n\t\tconst bodyHeights = this.buildBodyHeights(question, preview, multiSelect);\n\t\treturn { optionList, preview, multiSelect, bodyHeights };\n\t}\n\n\tprivate buildBodyHeights(\n\t\tquestion: QuestionData,\n\t\tpreview: PreviewPane,\n\t\tmultiSelect: MultiSelectView | undefined,\n\t): (width: number) => TabBodyHeights {\n\t\treturn question.multiSelect ? multiSelectBodyHeights(multiSelect!) : previewBodyHeights(preview);\n\t}\n\n\t/**\n\t * Compute cross-tab max adaptive left width and inject into each PreviewPane.\n\t * Mirrors buildHeightComputers pattern — iterates all tabs, takes max.\n\t * Called after buildTabComponents, before buildDialog (so setGlobalLeftWidth\n\t * is set before any rendering occurs).\n\t */\n\tprivate injectGlobalLeftWidth(tabs: ReadonlyArray<TabComponents>): void {\n\t\tconst questions = this.questions;\n\t\tconst itemsByTab = this.itemsByTab;\n\t\tconst tabsDescriptor = questions.map((q) => ({ multiSelect: q.multiSelect }));\n\t\tconst globalLeftWidth = (paneWidth: number): number =>\n\t\t\tcrossTabLeftWidthWithDonation(tabsDescriptor, itemsByTab, questions, paneWidth);\n\t\tfor (const tab of tabs) {\n\t\t\ttab.preview.setGlobalLeftWidth(globalLeftWidth);\n\t\t}\n\t}\n\n\tprivate buildSubmitPicker(): SubmitPicker | undefined {\n\t\treturn this.isMulti ? new SubmitPicker(this.theme) : undefined;\n\t}\n\n\tprivate buildTabBar(): TabBar | undefined {\n\t\treturn this.isMulti ? new TabBar(this.theme) : undefined;\n\t}\n\n\tprivate buildHeightComputers(tabs: ReadonlyArray<TabComponents>): HeightComputers {\n\t\tconst global = (width: number): number => {\n\t\t\tlet max = 0;\n\t\t\tfor (const tab of tabs) {\n\t\t\t\tconst h = tab.bodyHeights(width).max;\n\t\t\t\tif (h > max) max = h;\n\t\t\t}\n\t\t\treturn Math.max(1, max);\n\t\t};\n\t\tconst current = (width: number): number => {\n\t\t\tconst idx = Math.min(this.getCurrentTab(), tabs.length - 1);\n\t\t\treturn Math.max(0, tabs[idx]?.bodyHeights(width).current ?? 0);\n\t\t};\n\t\treturn { global, current };\n\t}\n\n\tprivate pickInitialActivePreview(tabs: ReadonlyArray<TabComponents>): StatefulView<PreviewPaneProps> {\n\t\tconst idx = selectActivePreviewPaneIndex(this.initialState.currentTab, this.questions.length);\n\t\treturn tabs[idx]?.preview ?? tabs[0]!.preview;\n\t}\n\n\tprivate buildDialog(\n\t\ttabs: ReadonlyArray<TabComponents>,\n\t\tsubmitPicker: SubmitPicker | undefined,\n\t\ttabBar: TabBar | undefined,\n\t\theights: HeightComputers,\n\t): DialogView {\n\t\treturn new DialogView(\n\t\t\t{\n\t\t\t\ttheme: this.theme,\n\t\t\t\tquestions: this.questions,\n\t\t\t\ttabBar,\n\t\t\t\tnotesInput: this.notesInput,\n\t\t\t\tchatRow: this.chatRow,\n\t\t\t\tisMulti: this.isMulti,\n\t\t\t\ttabsByIndex: tabs,\n\t\t\t\tsubmitPicker,\n\t\t\t\tgetBodyHeight: heights.global,\n\t\t\t\tgetCurrentBodyHeight: heights.current,\n\t\t\t},\n\t\t\t{ state: this.initialState, activePreviewPane: this.pickInitialActivePreview(tabs) },\n\t\t);\n\t}\n\n\tprivate buildGlobalBindings(\n\t\tdialog: DialogView,\n\t\tsubmitPicker: SubmitPicker | undefined,\n\t\ttabBar: TabBar | undefined,\n\t): ReadonlyArray<BoundGlobalBinding> {\n\t\treturn [\n\t\t\tglobalBinding({ component: dialog, select: selectDialogProps }),\n\t\t\tglobalBinding({ component: this.chatRow, select: selectChatRowProps }),\n\t\t\t...(submitPicker ? [globalBinding({ component: submitPicker, select: selectSubmitPickerProps })] : []),\n\t\t\t...(tabBar ? [globalBinding({ component: tabBar, select: selectTabBarProps })] : []),\n\t\t];\n\t}\n\n\tprivate buildPerTabBindings(): ReadonlyArray<BoundPerTabBinding> {\n\t\treturn [\n\t\t\tperTabBinding({\n\t\t\t\tresolve: (tab) => tab.optionList,\n\t\t\t\tpredicate: isActiveTab,\n\t\t\t\tselect: selectOptionListProps,\n\t\t\t}),\n\t\t\tperTabBinding({\n\t\t\t\tresolve: (tab) => tab.preview,\n\t\t\t\tpredicate: isActiveTab,\n\t\t\t\tselect: selectPreviewPaneProps,\n\t\t\t}),\n\t\t\tperTabBinding({\n\t\t\t\tresolve: (tab) => tab.multiSelect,\n\t\t\t\tselect: selectMultiSelectProps,\n\t\t\t}),\n\t\t];\n\t}\n\n\tprivate buildAdapter(\n\t\ttabs: ReadonlyArray<TabComponents>,\n\t\tglobalBindings: ReadonlyArray<BoundGlobalBinding>,\n\t\tperTabBindings: ReadonlyArray<BoundPerTabBinding>,\n\t): QuestionnairePropsAdapter {\n\t\treturn new QuestionnairePropsAdapter({\n\t\t\ttui: this.tui,\n\t\t\tquestions: this.questions,\n\t\t\titemsByTab: this.itemsByTab,\n\t\t\ttabsByIndex: tabs,\n\t\t\tinlineInput: this.inlineInput,\n\t\t\tglobalBindings,\n\t\t\tperTabBindings,\n\t\t\textraInvalidatables: [this.notesInput],\n\t\t});\n\t}\n\n\tprivate handle(adapter: QuestionnairePropsAdapter, dialog: DialogView): QuestionnaireBuilt {\n\t\treturn {\n\t\t\tadapter,\n\t\t\tnotesInput: this.notesInput,\n\t\t\tinlineInput: this.inlineInput,\n\t\t\trender: (w) => dialog.render(w),\n\t\t\tinvalidate: () => adapter.invalidate(),\n\t\t};\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"key-router.d.ts","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/key-router.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAU3E,MAAM,MAAM,mBAAmB,GAC5B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,cAAc,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,CAAC,GAAG,CAAC,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE;AACxB;;;GAGG;GACD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEtB,MAAM,WAAW,wBAAwB;IACxC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAC7C;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAG5D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,kBAAkB,EAAE,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAM7F;
|
|
1
|
+
{"version":3,"file":"key-router.d.ts","sourceRoot":"","sources":["../../../../../src/core/tools/ask-user-question/state/key-router.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAU3E,MAAM,MAAM,mBAAmB,GAC5B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,cAAc,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,GACtB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,CAAC,GAAG,CAAC,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE;AACxB;;;GAGG;GACD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEtB,MAAM,WAAW,wBAAwB;IACxC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAC7C;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAG5D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,kBAAkB,EAAE,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAM7F;AAiHD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,EAAE,OAAO,EAAE,oBAAoB,GAAG,mBAAmB,CAsIpH"}
|
|
@@ -62,11 +62,13 @@ function buildSingleSelectAnswer(state, runtime) {
|
|
|
62
62
|
}
|
|
63
63
|
if (state.inputMode && state.inlineInputOwner === "other") {
|
|
64
64
|
const label = runtime.inputBuffer;
|
|
65
|
+
if (label.trim().length === 0)
|
|
66
|
+
return null;
|
|
65
67
|
return {
|
|
66
68
|
questionIndex: state.currentTab,
|
|
67
69
|
question: q.question,
|
|
68
70
|
kind: "custom",
|
|
69
|
-
answer: label
|
|
71
|
+
answer: label,
|
|
70
72
|
};
|
|
71
73
|
}
|
|
72
74
|
if (!item)
|