@astralyn/pi 0.84.6 → 0.84.7
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 +8 -0
- package/dist/extensions/background/render.d.ts.map +1 -1
- package/dist/extensions/background/render.js +9 -1
- package/dist/extensions/background/render.js.map +1 -1
- package/dist/extensions/router/dialog-host.d.ts +60 -0
- package/dist/extensions/router/dialog-host.d.ts.map +1 -0
- package/dist/extensions/router/dialog-host.js +196 -0
- package/dist/extensions/router/dialog-host.js.map +1 -0
- package/dist/extensions/router/probe.d.ts.map +1 -1
- package/dist/extensions/router/probe.js +2 -0
- package/dist/extensions/router/probe.js.map +1 -1
- package/dist/extensions/router/ui.d.ts.map +1 -1
- package/dist/extensions/router/ui.js +117 -67
- package/dist/extensions/router/ui.js.map +1 -1
- package/dist/extensions/subagent/agents-command.d.ts.map +1 -1
- package/dist/extensions/subagent/agents-command.js +355 -71
- package/dist/extensions/subagent/agents-command.js.map +1 -1
- package/dist/extensions/subagent/settings.d.ts.map +1 -1
- package/dist/extensions/subagent/settings.js +11 -4
- package/dist/extensions/subagent/settings.js.map +1 -1
- package/dist/extensions/subagent/ui/model-list.d.ts +1 -0
- package/dist/extensions/subagent/ui/model-list.d.ts.map +1 -1
- package/dist/extensions/subagent/ui/model-list.js +5 -0
- package/dist/extensions/subagent/ui/model-list.js.map +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,14 @@ This file records `@astralyn/pi` releases beginning with the first Fork-owned re
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.84.7] - 2026-08-21
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Fixed `/agents` flashing the main editor for one frame between nested TUI pages by keeping profile, settings, model, and thinking navigation inside one custom UI lifecycle.
|
|
12
|
+
- Fixed `/router` flashing the main editor between nested menus, prompts, confirmations, catalog loading, and model selection by keeping its complete TUI flow inside one custom UI lifecycle.
|
|
13
|
+
- Fixed an uncaught TUI crash when the Background tool received an incomplete streaming argument frame by keeping its call renderer valid until the action and create command are available.
|
|
14
|
+
|
|
7
15
|
## [0.84.6] - 2026-08-15
|
|
8
16
|
|
|
9
17
|
### Added
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/extensions/background/render.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,SAAS,EAAkC,MAAM,wBAAwB,CAAC;AACxF,OAAO,KAAK,EACX,eAAe,EACf,oBAAoB,EACpB,iBAAiB,EACjB,uBAAuB,EACvB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,EAAiB,KAAK,KAAK,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,KAAK,EAAiB,SAAS,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAC3F,OAAO,EAIN,KAAK,YAAY,EAGjB,MAAM,eAAe,CAAC;AASvB,iFAAiF;AACjF,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAC;AAEvE,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC7B,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;IAC7C,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAmBrG;AAED,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAeD,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAa3E;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAa/G;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGnE;AAID,wBAAgB,YAAY,CAC3B,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,CAAC,aAAa,CAAC,EACzC,WAAW,CAAC,EAAE,aAAa,GACzB,SAAS,
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/extensions/background/render.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,KAAK,SAAS,EAAkC,MAAM,wBAAwB,CAAC;AACxF,OAAO,KAAK,EACX,eAAe,EACf,oBAAoB,EACpB,iBAAiB,EACjB,uBAAuB,EACvB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,EAAiB,KAAK,KAAK,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,KAAK,EAAiB,SAAS,EAAE,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAC3F,OAAO,EAIN,KAAK,YAAY,EAGjB,MAAM,eAAe,CAAC;AASvB,iFAAiF;AACjF,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,UAAU,GAAG,SAAS,CAAC;AAEvE,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC7B,YAAY,CAAC,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;IAC7C,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,iBAAiB,CAAC,aAAa,CAAC,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAmBrG;AAED,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE/C;AAeD,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAa3E;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAa/G;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGnE;AAID,wBAAgB,YAAY,CAC3B,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,CAAC,aAAa,CAAC,EACzC,WAAW,CAAC,EAAE,aAAa,GACzB,SAAS,CAgCX;AAED,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE9D;AAiED,wBAAgB,cAAc,CAC7B,MAAM,EAAE,eAAe,CAAC,SAAS,GAAG,SAAS,CAAC,EAC9C,OAAO,EAAE,uBAAuB,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,CAAC,aAAa,CAAC,GACvC,SAAS,CAkBX;AAoDD;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC3C,OAAO,EAAE,aAAa,CAAC,qBAAqB,CAAC,EAC7C,OAAO,EAAE,oBAAoB,EAC7B,KAAK,EAAE,KAAK,GACV,SAAS,GAAG,SAAS,CAoCvB"}
|
|
@@ -94,7 +94,9 @@ export function commandLabel(command, width) {
|
|
|
94
94
|
export function renderBgCall(args, theme, context, getTaskLive) {
|
|
95
95
|
switch (args.action) {
|
|
96
96
|
case "create":
|
|
97
|
-
return
|
|
97
|
+
return typeof args.command === "string"
|
|
98
|
+
? renderCreateCall(args, theme, context)
|
|
99
|
+
: new Text(theme.fg("toolTitle", theme.bold("bg create")), 0, 0);
|
|
98
100
|
case "read": {
|
|
99
101
|
const mode = args.mode ?? "tail";
|
|
100
102
|
const size = args.bytes !== undefined ? ` ${formatSize(args.bytes)}` : "";
|
|
@@ -106,6 +108,12 @@ export function renderBgCall(args, theme, context, getTaskLive) {
|
|
|
106
108
|
return new Text(`${theme.fg("toolTitle", theme.bold("bg kill "))}${theme.fg("accent", args.taskId ?? "")}`, 0, 0);
|
|
107
109
|
case "list":
|
|
108
110
|
return new Text(theme.fg("toolTitle", theme.bold("bg list")), 0, 0);
|
|
111
|
+
default: {
|
|
112
|
+
// Tool arguments arrive incrementally while the model is still emitting
|
|
113
|
+
// JSON. Keep the call row renderable until `action` becomes valid.
|
|
114
|
+
const action = typeof args.action === "string" ? ` ${theme.fg("dim", args.action)}` : "";
|
|
115
|
+
return new Text(`${theme.fg("toolTitle", theme.bold("bg"))}${action}`, 0, 0);
|
|
116
|
+
}
|
|
109
117
|
}
|
|
110
118
|
}
|
|
111
119
|
/** Mirror the execution-side clamp so the shown window matches the real one. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/extensions/background/render.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Transcript rendering for the background extension: the single bg tool's\n * call/result rows (dispatched on action) and the completion-notification\n * message. Style follows the built-in bash presentation: a `$` prompt row\n * with an `&` marker for the background call.\n */\n\nimport { type Component, Container, Text, TruncatedText } from \"@earendil-works/pi-tui\";\nimport type {\n\tAgentToolResult,\n\tMessageRenderOptions,\n\tToolRenderContext,\n\tToolRenderResultOptions,\n} from \"../../core/extensions/types.ts\";\nimport type { CustomMessage } from \"../../core/messages.ts\";\nimport { formatSize } from \"../../core/tools/truncate.ts\";\nimport { highlightCode, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { BgCreateInput, BgDetails, BgInput, BgNotificationDetails } from \"./index.ts\";\nimport {\n\tBG_WAIT_DEFAULT_MS,\n\tBG_WAIT_MAX_MS,\n\tBG_WAIT_MIN_MS,\n\ttype BgTaskStatus,\n\tfirstCommandLine,\n\tformatDuration,\n} from \"./registry.ts\";\n\nconst COMMAND_PREVIEW_LIMIT = 120;\nconst NOTIFY_TAIL_LIMIT = 4000;\n/** Cap for expanded transcript views of tool-result text (already bounded at the source). */\nconst RESULT_EXPAND_LIMIT = 4000;\n/** Live pending-wait line refresh cadence; the first settled render clears the timer. */\nconst WAIT_REFRESH_MS = 1000;\n\n/** Live peek at a waited-on task, fed from the registry by the call renderer. */\nexport interface BgTaskLive {\n\tstatus: BgTaskStatus;\n\toutputBytes: number;\n}\n\nexport type WaitLiveProbe = (taskId: string) => BgTaskLive | undefined;\n\n/** Per-call live-refresh state owned by the shell's render context. */\nexport interface BgRenderState {\n\trefreshTimer?: ReturnType<typeof setTimeout>;\n\t/** First pending render of a wait call; anchors the elapsed display. */\n\twaitStartedAt?: number;\n\t/** outputBytes snapshot at wait start; anchors the \"+new output\" display. */\n\twaitBaselineBytes?: number;\n}\n\n/**\n * Arm a one-shot 1s refresh while a wait call is pending, clear it once\n * settled. The timer fires → context.invalidate() → renderCall re-runs →\n * re-arms, so at most one armed timer exists per tool row. Unref'd: it can\n * never hold the process open.\n */\nexport function scheduleWaitRefresh(context: ToolRenderContext<BgRenderState>, pending: boolean): void {\n\tconst state = context.state;\n\tif (state === undefined) return; // Standalone render without shell state: nothing to schedule.\n\tif (pending) {\n\t\tif (state.refreshTimer === undefined) {\n\t\t\tstate.refreshTimer = setTimeout(() => {\n\t\t\t\tstate.refreshTimer = undefined;\n\t\t\t\tcontext.invalidate();\n\t\t\t}, WAIT_REFRESH_MS);\n\t\t\tstate.refreshTimer.unref?.();\n\t\t}\n\t\treturn;\n\t}\n\tif (state.refreshTimer !== undefined) {\n\t\tclearTimeout(state.refreshTimer);\n\t\tstate.refreshTimer = undefined;\n\t}\n\tstate.waitStartedAt = undefined;\n\tstate.waitBaselineBytes = undefined;\n}\n\n/** Basename of a path, slash-normalized — compact display of output files. */\nexport function fileNameOf(path: string): string {\n\treturn path.replace(/\\\\/g, \"/\").split(\"/\").at(-1) ?? path;\n}\n\nfunction bgPrompt(theme: Theme): string {\n\treturn theme.fg(\"toolTitle\", theme.bold(\"$ \"));\n}\n\nfunction timeoutSuffix(timeout: number | undefined, theme: Theme): string {\n\treturn timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n}\n\n/** Keep the END of oversized text — that is where the outcome lives. */\nfunction capForTranscript(text: string, limit: number): string {\n\treturn text.length > limit ? `…${text.slice(-limit)}` : text;\n}\n\nexport function statusGlyph(status: BgTaskStatus, stalled?: boolean): string {\n\tif (stalled) return \"…\";\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn \"✓\";\n\t\tcase \"failed\":\n\t\tcase \"timeout\":\n\t\t\treturn \"✗\";\n\t\tcase \"killed\":\n\t\t\treturn \"○\";\n\t\tdefault:\n\t\t\treturn \"●\";\n\t}\n}\n\nexport function statusColor(status: BgTaskStatus, stalled?: boolean): \"success\" | \"error\" | \"warning\" | \"accent\" {\n\tif (stalled) return \"warning\";\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn \"success\";\n\t\tcase \"failed\":\n\t\t\treturn \"error\";\n\t\tcase \"timeout\":\n\t\tcase \"killed\":\n\t\t\treturn \"warning\";\n\t\tdefault:\n\t\t\treturn \"accent\";\n\t}\n}\n\n/** First command line truncated to a visible-character budget with an ellipsis. */\nexport function commandLabel(command: string, width: number): string {\n\tconst characters = [...firstCommandLine(command)];\n\treturn characters.length <= width ? characters.join(\"\") : `${characters.slice(0, Math.max(0, width - 1)).join(\"\")}…`;\n}\n\n// ── tool call ─────────────────────────────────────────────────────────────\n\nexport function renderBgCall(\n\targs: BgInput,\n\ttheme: Theme,\n\tcontext: ToolRenderContext<BgRenderState>,\n\tgetTaskLive?: WaitLiveProbe,\n): Component {\n\tswitch (args.action) {\n\t\tcase \"create\":\n\t\t\treturn renderCreateCall(args as BgCreateInput, theme, context);\n\t\tcase \"read\": {\n\t\t\tconst mode = args.mode ?? \"tail\";\n\t\t\tconst size = args.bytes !== undefined ? ` ${formatSize(args.bytes)}` : \"\";\n\t\t\treturn new Text(\n\t\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"bg read \"))}${theme.fg(\"accent\", args.taskId ?? \"\")}${theme.fg(\"muted\", ` ${mode}${size}`)}`,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t);\n\t\t}\n\t\tcase \"wait\":\n\t\t\treturn renderWaitCall(args, theme, context, getTaskLive);\n\t\tcase \"kill\":\n\t\t\treturn new Text(\n\t\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"bg kill \"))}${theme.fg(\"accent\", args.taskId ?? \"\")}`,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t);\n\t\tcase \"list\":\n\t\t\treturn new Text(theme.fg(\"toolTitle\", theme.bold(\"bg list\")), 0, 0);\n\t}\n}\n\n/** Mirror the execution-side clamp so the shown window matches the real one. */\nexport function clampWaitMs(waitMs: number | undefined): number {\n\treturn Math.min(BG_WAIT_MAX_MS, Math.max(BG_WAIT_MIN_MS, Math.floor(waitMs ?? BG_WAIT_DEFAULT_MS)));\n}\n\n/**\n * Pending wait call: elapsed/wait-window and the new-output delta since the\n * wait began, refreshed once per second by scheduleWaitRefresh until the\n * result settles and takes over the row.\n */\nfunction renderWaitCall(\n\targs: BgInput,\n\ttheme: Theme,\n\tcontext: ToolRenderContext<BgRenderState>,\n\tgetTaskLive: WaitLiveProbe | undefined,\n): Component {\n\tconst taskId = typeof args.taskId === \"string\" ? args.taskId.trim() : \"\";\n\tconst live = getTaskLive !== undefined && taskId ? getTaskLive(taskId) : undefined;\n\t// The live display needs shell-owned state; without it (standalone renders)\n\t// fall back to the static line.\n\tconst pending = context.isPartial === true && context.state !== undefined && taskId.length > 0;\n\tscheduleWaitRefresh(context, pending);\n\tif (!pending) {\n\t\tconst ms = args.waitMs !== undefined ? ` ${formatDuration(clampWaitMs(args.waitMs))}` : \"\";\n\t\treturn new Text(\n\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"bg wait \"))}${theme.fg(\"accent\", args.taskId ?? \"\")}${theme.fg(\"muted\", ms)}`,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\tconst state = context.state;\n\tif (state.waitStartedAt === undefined) state.waitStartedAt = Date.now();\n\tconst startedAt = state.waitStartedAt;\n\tlet liveBase: number | undefined;\n\tif (live) {\n\t\tif (state.waitBaselineBytes === undefined) state.waitBaselineBytes = live.outputBytes;\n\t\tliveBase = state.waitBaselineBytes;\n\t}\n\tconst parts = [`waiting ${formatDuration(Date.now() - startedAt)}/${formatDuration(clampWaitMs(args.waitMs))}`];\n\tif (live && live.status === \"running\" && liveBase !== undefined && live.outputBytes > liveBase) {\n\t\tparts.push(`+${formatSize(live.outputBytes - liveBase)} new output`);\n\t}\n\treturn new Text(\n\t\t`${theme.fg(\"toolTitle\", theme.bold(\"bg wait \"))}${theme.fg(\"accent\", taskId)} ${theme.fg(\"muted\", parts.join(\" · \"))}`,\n\t\t0,\n\t\t0,\n\t);\n}\n\nfunction renderCreateCall(args: BgCreateInput, theme: Theme, context: ToolRenderContext): Component {\n\tconst lines = args.command.split(/\\r?\\n/).filter((line) => line.trim().length > 0);\n\tconst label = args.description ? theme.fg(\"muted\", ` · ${args.description}`) : \"\";\n\tconst suffix = theme.fg(\"muted\", \" &\") + timeoutSuffix(args.timeout, theme) + label;\n\tif (context.expanded && lines.length > 1) {\n\t\tconst body = highlightCode(args.command, \"bash\").join(\"\\n\");\n\t\treturn new Text(`${bgPrompt(theme)}${body}${suffix}`, 0, 0);\n\t}\n\tconst body = highlightCode(firstCommandLine(args.command), \"bash\").join(\"\\n\");\n\tif (lines.length > 1) {\n\t\tconst hidden = lines.length - 1;\n\t\tconst more = theme.fg(\"muted\", ` (+${hidden} line${hidden === 1 ? \"\" : \"s\"})`);\n\t\treturn new Text(`${bgPrompt(theme)}${body}${suffix}${more}`, 0, 0);\n\t}\n\treturn new Text(`${bgPrompt(theme)}${body}${suffix}`, 0, 0);\n}\n\n// ── tool result ───────────────────────────────────────────────────────────\n\nexport function renderBgResult(\n\tresult: AgentToolResult<BgDetails | undefined>,\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tcontext: ToolRenderContext<BgRenderState>,\n): Component {\n\t// bg results are always settled today; clear defensively so no live-refresh\n\t// timer can outlive its row if a host ever streams partial results.\n\tif (context.args?.action === \"wait\" && !options.isPartial) scheduleWaitRefresh(context, false);\n\tconst details = result.details;\n\tif (context.isError || !details) {\n\t\tconst text = result.content.find((part) => part.type === \"text\")?.text ?? \"\";\n\t\treturn new Text(theme.fg(\"toolOutput\", text.trimEnd()), 0, 0);\n\t}\n\n\tconst container = new Container();\n\tcontainer.addChild(new TruncatedText(resultSummaryLine(details, theme), 1, 0));\n\tif (options.expanded) {\n\t\tconst text = result.content.find((part) => part.type === \"text\")?.text ?? \"\";\n\t\tcontainer.addChild(new Text(\"\", 0, 0));\n\t\tcontainer.addChild(new Text(theme.fg(\"toolOutput\", capForTranscript(text, RESULT_EXPAND_LIMIT).trimEnd()), 1, 0));\n\t}\n\treturn container;\n}\n\nfunction resultSummaryLine(details: BgDetails, theme: Theme): string {\n\tswitch (details.action) {\n\t\tcase \"create\": {\n\t\t\tconst label = details.description ? ` (${details.description})` : \"\";\n\t\t\treturn `${theme.fg(\"muted\", \"→ task \")}${theme.fg(\"accent\", `${details.taskId}${label}`)}${theme.fg(\"muted\", ` started · ${details.outputPath}`)}`;\n\t\t}\n\t\tcase \"read\": {\n\t\t\tconst size =\n\t\t\t\tdetails.sliceBytes !== details.totalBytes\n\t\t\t\t\t? `${details.mode} ${formatSize(details.sliceBytes)} of ${formatSize(details.totalBytes)}`\n\t\t\t\t\t: formatSize(details.totalBytes);\n\t\t\treturn `${theme.fg(\"muted\", \"→ \")}${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", ` ${size} · ${details.outputPath}`)}`;\n\t\t}\n\t\tcase \"wait\": {\n\t\t\tif (details.timedOut) {\n\t\t\t\treturn `${theme.fg(statusColor(details.status), statusGlyph(details.status))} ${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", ` still running · waited ${formatDuration(details.waitedMs)} · ${formatSize(details.totalBytes)}`)}`;\n\t\t\t}\n\t\t\tconst exit = details.exitCode !== undefined && details.exitCode !== null ? `, exit ${details.exitCode}` : \"\";\n\t\t\treturn `${theme.fg(statusColor(details.status), statusGlyph(details.status))} ${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", ` ${details.status}${exit} · waited ${formatDuration(details.waitedMs)} · +${formatSize(details.deltaBytes)}`)}`;\n\t\t}\n\t\tcase \"kill\":\n\t\t\treturn `${theme.fg(statusColor(\"killed\"), statusGlyph(\"killed\"))} ${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", \" stopped\")}`;\n\t\tcase \"list\": {\n\t\t\tconst hidden = details.hidden > 0 ? ` · ${details.hidden} more finished` : \"\";\n\t\t\treturn theme.fg(\"muted\", `${details.running} running · ${details.finished} finished${hidden}`);\n\t\t}\n\t}\n}\n\n// ── completion notification ───────────────────────────────────────────────\n\n/** One-line summary of a finished task, shared by the notification renderer. */\nfunction taskSummaryLine(details: BgNotificationDetails, theme: Theme): string {\n\tconst runtime = formatDuration(details.runtimeMs);\n\tconst exit = details.exitCode !== undefined && details.exitCode !== null ? `, exit ${details.exitCode}` : \"\";\n\tif (details.stalled) {\n\t\tconst glyph = theme.fg(\"warning\", \"…\");\n\t\tconst label = details.description\n\t\t\t? `${details.description} (${commandLabel(details.command, 40)})`\n\t\t\t: commandLabel(details.command, COMMAND_PREVIEW_LIMIT);\n\t\treturn `${glyph} ${theme.fg(\"accent\", details.taskId)} ${label} ${theme.fg(\"muted\", `— waiting for input (${runtime})`)}`;\n\t}\n\tconst outcome = theme.fg(statusColor(details.status), `${details.status}${exit} in ${runtime}`);\n\tconst glyph = theme.fg(statusColor(details.status), statusGlyph(details.status));\n\tconst label = details.description\n\t\t? `${details.description} (${commandLabel(details.command, 40)})`\n\t\t: commandLabel(details.command, COMMAND_PREVIEW_LIMIT);\n\treturn `${glyph} ${theme.fg(\"accent\", details.taskId)} ${label} ${theme.fg(\"muted\", `— ${outcome}`)}`;\n}\n\n/**\n * Collapsed: status glyph, task id, label, and outcome on one line, output\n * path below. Expanded adds the embedded output tail. Returns undefined for\n * malformed details so the default custom-message rendering takes over.\n */\nexport function renderBackgroundNotification(\n\tmessage: CustomMessage<BgNotificationDetails>,\n\toptions: MessageRenderOptions,\n\ttheme: Theme,\n): Component | undefined {\n\tconst details = message.details;\n\tif (!details || typeof details.taskId !== \"string\") return undefined;\n\n\tconst container = new Container();\n\tcontainer.addChild(new TruncatedText(taskSummaryLine(details, theme), 1, 0));\n\t// Collapsed keeps the row compact with the file name; the full path\n\t// (model-relevant, human-rarely) shows when expanded.\n\tconst shownPath = options.expanded ? details.outputPath : fileNameOf(details.outputPath);\n\tcontainer.addChild(new Text(theme.fg(\"muted\", shownPath), 1, 0));\n\n\tif (details.tailError) {\n\t\tcontainer.addChild(new Text(theme.fg(\"error\", `Output unavailable: ${details.tailError}`), 1, 0));\n\t} else if (options.expanded && details.tailText) {\n\t\tcontainer.addChild(new Text(\"\", 0, 0));\n\t\tconst tail = capForTranscript(details.tailText, NOTIFY_TAIL_LIMIT);\n\t\tconst truncatedNote = details.tailTruncated\n\t\t\t? `\\n[showing tail of ${formatSize(details.totalBytes)} bytes; full output: ${details.outputPath}]`\n\t\t\t: \"\";\n\t\tcontainer.addChild(\n\t\t\tnew Text(`${theme.fg(\"toolOutput\", tail.trimEnd())}${theme.fg(\"muted\", truncatedNote)}`, 1, 0),\n\t\t);\n\t}\n\tif (details.stalled && options.expanded) {\n\t\tcontainer.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\n\t\t\t\t\t\"warning\",\n\t\t\t\t\t\"Blocked on interactive input — kill (bg action kill) and re-run with piped input or a non-interactive flag.\",\n\t\t\t\t),\n\t\t\t\t1,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t}\n\treturn container;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/extensions/background/render.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Transcript rendering for the background extension: the single bg tool's\n * call/result rows (dispatched on action) and the completion-notification\n * message. Style follows the built-in bash presentation: a `$` prompt row\n * with an `&` marker for the background call.\n */\n\nimport { type Component, Container, Text, TruncatedText } from \"@earendil-works/pi-tui\";\nimport type {\n\tAgentToolResult,\n\tMessageRenderOptions,\n\tToolRenderContext,\n\tToolRenderResultOptions,\n} from \"../../core/extensions/types.ts\";\nimport type { CustomMessage } from \"../../core/messages.ts\";\nimport { formatSize } from \"../../core/tools/truncate.ts\";\nimport { highlightCode, type Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { BgCreateInput, BgDetails, BgInput, BgNotificationDetails } from \"./index.ts\";\nimport {\n\tBG_WAIT_DEFAULT_MS,\n\tBG_WAIT_MAX_MS,\n\tBG_WAIT_MIN_MS,\n\ttype BgTaskStatus,\n\tfirstCommandLine,\n\tformatDuration,\n} from \"./registry.ts\";\n\nconst COMMAND_PREVIEW_LIMIT = 120;\nconst NOTIFY_TAIL_LIMIT = 4000;\n/** Cap for expanded transcript views of tool-result text (already bounded at the source). */\nconst RESULT_EXPAND_LIMIT = 4000;\n/** Live pending-wait line refresh cadence; the first settled render clears the timer. */\nconst WAIT_REFRESH_MS = 1000;\n\n/** Live peek at a waited-on task, fed from the registry by the call renderer. */\nexport interface BgTaskLive {\n\tstatus: BgTaskStatus;\n\toutputBytes: number;\n}\n\nexport type WaitLiveProbe = (taskId: string) => BgTaskLive | undefined;\n\n/** Per-call live-refresh state owned by the shell's render context. */\nexport interface BgRenderState {\n\trefreshTimer?: ReturnType<typeof setTimeout>;\n\t/** First pending render of a wait call; anchors the elapsed display. */\n\twaitStartedAt?: number;\n\t/** outputBytes snapshot at wait start; anchors the \"+new output\" display. */\n\twaitBaselineBytes?: number;\n}\n\n/**\n * Arm a one-shot 1s refresh while a wait call is pending, clear it once\n * settled. The timer fires → context.invalidate() → renderCall re-runs →\n * re-arms, so at most one armed timer exists per tool row. Unref'd: it can\n * never hold the process open.\n */\nexport function scheduleWaitRefresh(context: ToolRenderContext<BgRenderState>, pending: boolean): void {\n\tconst state = context.state;\n\tif (state === undefined) return; // Standalone render without shell state: nothing to schedule.\n\tif (pending) {\n\t\tif (state.refreshTimer === undefined) {\n\t\t\tstate.refreshTimer = setTimeout(() => {\n\t\t\t\tstate.refreshTimer = undefined;\n\t\t\t\tcontext.invalidate();\n\t\t\t}, WAIT_REFRESH_MS);\n\t\t\tstate.refreshTimer.unref?.();\n\t\t}\n\t\treturn;\n\t}\n\tif (state.refreshTimer !== undefined) {\n\t\tclearTimeout(state.refreshTimer);\n\t\tstate.refreshTimer = undefined;\n\t}\n\tstate.waitStartedAt = undefined;\n\tstate.waitBaselineBytes = undefined;\n}\n\n/** Basename of a path, slash-normalized — compact display of output files. */\nexport function fileNameOf(path: string): string {\n\treturn path.replace(/\\\\/g, \"/\").split(\"/\").at(-1) ?? path;\n}\n\nfunction bgPrompt(theme: Theme): string {\n\treturn theme.fg(\"toolTitle\", theme.bold(\"$ \"));\n}\n\nfunction timeoutSuffix(timeout: number | undefined, theme: Theme): string {\n\treturn timeout ? theme.fg(\"muted\", ` (timeout ${timeout}s)`) : \"\";\n}\n\n/** Keep the END of oversized text — that is where the outcome lives. */\nfunction capForTranscript(text: string, limit: number): string {\n\treturn text.length > limit ? `…${text.slice(-limit)}` : text;\n}\n\nexport function statusGlyph(status: BgTaskStatus, stalled?: boolean): string {\n\tif (stalled) return \"…\";\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn \"✓\";\n\t\tcase \"failed\":\n\t\tcase \"timeout\":\n\t\t\treturn \"✗\";\n\t\tcase \"killed\":\n\t\t\treturn \"○\";\n\t\tdefault:\n\t\t\treturn \"●\";\n\t}\n}\n\nexport function statusColor(status: BgTaskStatus, stalled?: boolean): \"success\" | \"error\" | \"warning\" | \"accent\" {\n\tif (stalled) return \"warning\";\n\tswitch (status) {\n\t\tcase \"completed\":\n\t\t\treturn \"success\";\n\t\tcase \"failed\":\n\t\t\treturn \"error\";\n\t\tcase \"timeout\":\n\t\tcase \"killed\":\n\t\t\treturn \"warning\";\n\t\tdefault:\n\t\t\treturn \"accent\";\n\t}\n}\n\n/** First command line truncated to a visible-character budget with an ellipsis. */\nexport function commandLabel(command: string, width: number): string {\n\tconst characters = [...firstCommandLine(command)];\n\treturn characters.length <= width ? characters.join(\"\") : `${characters.slice(0, Math.max(0, width - 1)).join(\"\")}…`;\n}\n\n// ── tool call ─────────────────────────────────────────────────────────────\n\nexport function renderBgCall(\n\targs: BgInput,\n\ttheme: Theme,\n\tcontext: ToolRenderContext<BgRenderState>,\n\tgetTaskLive?: WaitLiveProbe,\n): Component {\n\tswitch (args.action) {\n\t\tcase \"create\":\n\t\t\treturn typeof args.command === \"string\"\n\t\t\t\t? renderCreateCall(args as BgCreateInput, theme, context)\n\t\t\t\t: new Text(theme.fg(\"toolTitle\", theme.bold(\"bg create\")), 0, 0);\n\t\tcase \"read\": {\n\t\t\tconst mode = args.mode ?? \"tail\";\n\t\t\tconst size = args.bytes !== undefined ? ` ${formatSize(args.bytes)}` : \"\";\n\t\t\treturn new Text(\n\t\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"bg read \"))}${theme.fg(\"accent\", args.taskId ?? \"\")}${theme.fg(\"muted\", ` ${mode}${size}`)}`,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t);\n\t\t}\n\t\tcase \"wait\":\n\t\t\treturn renderWaitCall(args, theme, context, getTaskLive);\n\t\tcase \"kill\":\n\t\t\treturn new Text(\n\t\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"bg kill \"))}${theme.fg(\"accent\", args.taskId ?? \"\")}`,\n\t\t\t\t0,\n\t\t\t\t0,\n\t\t\t);\n\t\tcase \"list\":\n\t\t\treturn new Text(theme.fg(\"toolTitle\", theme.bold(\"bg list\")), 0, 0);\n\t\tdefault: {\n\t\t\t// Tool arguments arrive incrementally while the model is still emitting\n\t\t\t// JSON. Keep the call row renderable until `action` becomes valid.\n\t\t\tconst action = typeof args.action === \"string\" ? ` ${theme.fg(\"dim\", args.action)}` : \"\";\n\t\t\treturn new Text(`${theme.fg(\"toolTitle\", theme.bold(\"bg\"))}${action}`, 0, 0);\n\t\t}\n\t}\n}\n\n/** Mirror the execution-side clamp so the shown window matches the real one. */\nexport function clampWaitMs(waitMs: number | undefined): number {\n\treturn Math.min(BG_WAIT_MAX_MS, Math.max(BG_WAIT_MIN_MS, Math.floor(waitMs ?? BG_WAIT_DEFAULT_MS)));\n}\n\n/**\n * Pending wait call: elapsed/wait-window and the new-output delta since the\n * wait began, refreshed once per second by scheduleWaitRefresh until the\n * result settles and takes over the row.\n */\nfunction renderWaitCall(\n\targs: BgInput,\n\ttheme: Theme,\n\tcontext: ToolRenderContext<BgRenderState>,\n\tgetTaskLive: WaitLiveProbe | undefined,\n): Component {\n\tconst taskId = typeof args.taskId === \"string\" ? args.taskId.trim() : \"\";\n\tconst live = getTaskLive !== undefined && taskId ? getTaskLive(taskId) : undefined;\n\t// The live display needs shell-owned state; without it (standalone renders)\n\t// fall back to the static line.\n\tconst pending = context.isPartial === true && context.state !== undefined && taskId.length > 0;\n\tscheduleWaitRefresh(context, pending);\n\tif (!pending) {\n\t\tconst ms = args.waitMs !== undefined ? ` ${formatDuration(clampWaitMs(args.waitMs))}` : \"\";\n\t\treturn new Text(\n\t\t\t`${theme.fg(\"toolTitle\", theme.bold(\"bg wait \"))}${theme.fg(\"accent\", args.taskId ?? \"\")}${theme.fg(\"muted\", ms)}`,\n\t\t\t0,\n\t\t\t0,\n\t\t);\n\t}\n\tconst state = context.state;\n\tif (state.waitStartedAt === undefined) state.waitStartedAt = Date.now();\n\tconst startedAt = state.waitStartedAt;\n\tlet liveBase: number | undefined;\n\tif (live) {\n\t\tif (state.waitBaselineBytes === undefined) state.waitBaselineBytes = live.outputBytes;\n\t\tliveBase = state.waitBaselineBytes;\n\t}\n\tconst parts = [`waiting ${formatDuration(Date.now() - startedAt)}/${formatDuration(clampWaitMs(args.waitMs))}`];\n\tif (live && live.status === \"running\" && liveBase !== undefined && live.outputBytes > liveBase) {\n\t\tparts.push(`+${formatSize(live.outputBytes - liveBase)} new output`);\n\t}\n\treturn new Text(\n\t\t`${theme.fg(\"toolTitle\", theme.bold(\"bg wait \"))}${theme.fg(\"accent\", taskId)} ${theme.fg(\"muted\", parts.join(\" · \"))}`,\n\t\t0,\n\t\t0,\n\t);\n}\n\nfunction renderCreateCall(args: BgCreateInput, theme: Theme, context: ToolRenderContext): Component {\n\tconst lines = args.command.split(/\\r?\\n/).filter((line) => line.trim().length > 0);\n\tconst label = args.description ? theme.fg(\"muted\", ` · ${args.description}`) : \"\";\n\tconst suffix = theme.fg(\"muted\", \" &\") + timeoutSuffix(args.timeout, theme) + label;\n\tif (context.expanded && lines.length > 1) {\n\t\tconst body = highlightCode(args.command, \"bash\").join(\"\\n\");\n\t\treturn new Text(`${bgPrompt(theme)}${body}${suffix}`, 0, 0);\n\t}\n\tconst body = highlightCode(firstCommandLine(args.command), \"bash\").join(\"\\n\");\n\tif (lines.length > 1) {\n\t\tconst hidden = lines.length - 1;\n\t\tconst more = theme.fg(\"muted\", ` (+${hidden} line${hidden === 1 ? \"\" : \"s\"})`);\n\t\treturn new Text(`${bgPrompt(theme)}${body}${suffix}${more}`, 0, 0);\n\t}\n\treturn new Text(`${bgPrompt(theme)}${body}${suffix}`, 0, 0);\n}\n\n// ── tool result ───────────────────────────────────────────────────────────\n\nexport function renderBgResult(\n\tresult: AgentToolResult<BgDetails | undefined>,\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tcontext: ToolRenderContext<BgRenderState>,\n): Component {\n\t// bg results are always settled today; clear defensively so no live-refresh\n\t// timer can outlive its row if a host ever streams partial results.\n\tif (context.args?.action === \"wait\" && !options.isPartial) scheduleWaitRefresh(context, false);\n\tconst details = result.details;\n\tif (context.isError || !details) {\n\t\tconst text = result.content.find((part) => part.type === \"text\")?.text ?? \"\";\n\t\treturn new Text(theme.fg(\"toolOutput\", text.trimEnd()), 0, 0);\n\t}\n\n\tconst container = new Container();\n\tcontainer.addChild(new TruncatedText(resultSummaryLine(details, theme), 1, 0));\n\tif (options.expanded) {\n\t\tconst text = result.content.find((part) => part.type === \"text\")?.text ?? \"\";\n\t\tcontainer.addChild(new Text(\"\", 0, 0));\n\t\tcontainer.addChild(new Text(theme.fg(\"toolOutput\", capForTranscript(text, RESULT_EXPAND_LIMIT).trimEnd()), 1, 0));\n\t}\n\treturn container;\n}\n\nfunction resultSummaryLine(details: BgDetails, theme: Theme): string {\n\tswitch (details.action) {\n\t\tcase \"create\": {\n\t\t\tconst label = details.description ? ` (${details.description})` : \"\";\n\t\t\treturn `${theme.fg(\"muted\", \"→ task \")}${theme.fg(\"accent\", `${details.taskId}${label}`)}${theme.fg(\"muted\", ` started · ${details.outputPath}`)}`;\n\t\t}\n\t\tcase \"read\": {\n\t\t\tconst size =\n\t\t\t\tdetails.sliceBytes !== details.totalBytes\n\t\t\t\t\t? `${details.mode} ${formatSize(details.sliceBytes)} of ${formatSize(details.totalBytes)}`\n\t\t\t\t\t: formatSize(details.totalBytes);\n\t\t\treturn `${theme.fg(\"muted\", \"→ \")}${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", ` ${size} · ${details.outputPath}`)}`;\n\t\t}\n\t\tcase \"wait\": {\n\t\t\tif (details.timedOut) {\n\t\t\t\treturn `${theme.fg(statusColor(details.status), statusGlyph(details.status))} ${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", ` still running · waited ${formatDuration(details.waitedMs)} · ${formatSize(details.totalBytes)}`)}`;\n\t\t\t}\n\t\t\tconst exit = details.exitCode !== undefined && details.exitCode !== null ? `, exit ${details.exitCode}` : \"\";\n\t\t\treturn `${theme.fg(statusColor(details.status), statusGlyph(details.status))} ${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", ` ${details.status}${exit} · waited ${formatDuration(details.waitedMs)} · +${formatSize(details.deltaBytes)}`)}`;\n\t\t}\n\t\tcase \"kill\":\n\t\t\treturn `${theme.fg(statusColor(\"killed\"), statusGlyph(\"killed\"))} ${theme.fg(\"accent\", details.taskId)}${theme.fg(\"muted\", \" stopped\")}`;\n\t\tcase \"list\": {\n\t\t\tconst hidden = details.hidden > 0 ? ` · ${details.hidden} more finished` : \"\";\n\t\t\treturn theme.fg(\"muted\", `${details.running} running · ${details.finished} finished${hidden}`);\n\t\t}\n\t}\n}\n\n// ── completion notification ───────────────────────────────────────────────\n\n/** One-line summary of a finished task, shared by the notification renderer. */\nfunction taskSummaryLine(details: BgNotificationDetails, theme: Theme): string {\n\tconst runtime = formatDuration(details.runtimeMs);\n\tconst exit = details.exitCode !== undefined && details.exitCode !== null ? `, exit ${details.exitCode}` : \"\";\n\tif (details.stalled) {\n\t\tconst glyph = theme.fg(\"warning\", \"…\");\n\t\tconst label = details.description\n\t\t\t? `${details.description} (${commandLabel(details.command, 40)})`\n\t\t\t: commandLabel(details.command, COMMAND_PREVIEW_LIMIT);\n\t\treturn `${glyph} ${theme.fg(\"accent\", details.taskId)} ${label} ${theme.fg(\"muted\", `— waiting for input (${runtime})`)}`;\n\t}\n\tconst outcome = theme.fg(statusColor(details.status), `${details.status}${exit} in ${runtime}`);\n\tconst glyph = theme.fg(statusColor(details.status), statusGlyph(details.status));\n\tconst label = details.description\n\t\t? `${details.description} (${commandLabel(details.command, 40)})`\n\t\t: commandLabel(details.command, COMMAND_PREVIEW_LIMIT);\n\treturn `${glyph} ${theme.fg(\"accent\", details.taskId)} ${label} ${theme.fg(\"muted\", `— ${outcome}`)}`;\n}\n\n/**\n * Collapsed: status glyph, task id, label, and outcome on one line, output\n * path below. Expanded adds the embedded output tail. Returns undefined for\n * malformed details so the default custom-message rendering takes over.\n */\nexport function renderBackgroundNotification(\n\tmessage: CustomMessage<BgNotificationDetails>,\n\toptions: MessageRenderOptions,\n\ttheme: Theme,\n): Component | undefined {\n\tconst details = message.details;\n\tif (!details || typeof details.taskId !== \"string\") return undefined;\n\n\tconst container = new Container();\n\tcontainer.addChild(new TruncatedText(taskSummaryLine(details, theme), 1, 0));\n\t// Collapsed keeps the row compact with the file name; the full path\n\t// (model-relevant, human-rarely) shows when expanded.\n\tconst shownPath = options.expanded ? details.outputPath : fileNameOf(details.outputPath);\n\tcontainer.addChild(new Text(theme.fg(\"muted\", shownPath), 1, 0));\n\n\tif (details.tailError) {\n\t\tcontainer.addChild(new Text(theme.fg(\"error\", `Output unavailable: ${details.tailError}`), 1, 0));\n\t} else if (options.expanded && details.tailText) {\n\t\tcontainer.addChild(new Text(\"\", 0, 0));\n\t\tconst tail = capForTranscript(details.tailText, NOTIFY_TAIL_LIMIT);\n\t\tconst truncatedNote = details.tailTruncated\n\t\t\t? `\\n[showing tail of ${formatSize(details.totalBytes)} bytes; full output: ${details.outputPath}]`\n\t\t\t: \"\";\n\t\tcontainer.addChild(\n\t\t\tnew Text(`${theme.fg(\"toolOutput\", tail.trimEnd())}${theme.fg(\"muted\", truncatedNote)}`, 1, 0),\n\t\t);\n\t}\n\tif (details.stalled && options.expanded) {\n\t\tcontainer.addChild(\n\t\t\tnew Text(\n\t\t\t\ttheme.fg(\n\t\t\t\t\t\"warning\",\n\t\t\t\t\t\"Blocked on interactive input — kill (bg action kill) and re-run with piped input or a non-interactive flag.\",\n\t\t\t\t),\n\t\t\t\t1,\n\t\t\t\t0,\n\t\t\t),\n\t\t);\n\t}\n\treturn container;\n}\n"]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** Extension-owned dialog host that keeps every /router TUI page in one modal lifecycle. */
|
|
2
|
+
import { type Component, Container, type Focusable, type TUI } from "@earendil-works/pi-tui";
|
|
3
|
+
import type { ExtensionCommandContext } from "../../core/extensions/types.ts";
|
|
4
|
+
import type { KeybindingsManager } from "../../core/keybindings.ts";
|
|
5
|
+
import type { Theme } from "../../modes/interactive/theme/theme.ts";
|
|
6
|
+
export type RouterComponent = Component & {
|
|
7
|
+
dispose?(): void;
|
|
8
|
+
};
|
|
9
|
+
export type RouterComponentFactory<T> = (tui: TUI, theme: Theme, keybindings: KeybindingsManager, done: (result: T) => void) => RouterComponent | Promise<RouterComponent>;
|
|
10
|
+
interface RouterDialogBase {
|
|
11
|
+
input(title: string, placeholder?: string): Promise<string | undefined>;
|
|
12
|
+
confirm(title: string, message: string): Promise<boolean>;
|
|
13
|
+
}
|
|
14
|
+
export interface RouterNativeDialogs extends RouterDialogBase {
|
|
15
|
+
readonly kind: "native";
|
|
16
|
+
select(title: string, options: string[]): Promise<string | undefined>;
|
|
17
|
+
}
|
|
18
|
+
export interface RouterTuiDialogs extends RouterDialogBase {
|
|
19
|
+
readonly kind: "tui";
|
|
20
|
+
show<T>(factory: RouterComponentFactory<T>): Promise<T>;
|
|
21
|
+
}
|
|
22
|
+
export type RouterDialogs = RouterNativeDialogs | RouterTuiDialogs;
|
|
23
|
+
export declare class RouterTuiSessionClosedError extends Error {
|
|
24
|
+
constructor();
|
|
25
|
+
}
|
|
26
|
+
export declare function createNativeRouterDialogs(ctx: ExtensionCommandContext): RouterNativeDialogs;
|
|
27
|
+
/**
|
|
28
|
+
* Persistent root mounted by one ctx.ui.custom() call. Child dialogs resolve
|
|
29
|
+
* without closing this root, so async flow continuations can replace them
|
|
30
|
+
* without exposing the main editor between pages.
|
|
31
|
+
*/
|
|
32
|
+
export declare class RouterTuiSession extends Container implements Focusable, RouterTuiDialogs {
|
|
33
|
+
readonly kind: "tui";
|
|
34
|
+
private readonly tui;
|
|
35
|
+
private readonly theme;
|
|
36
|
+
private readonly keybindings;
|
|
37
|
+
private readonly onTransitionClose;
|
|
38
|
+
private activeScreen;
|
|
39
|
+
private pendingReject;
|
|
40
|
+
private transitionTimer;
|
|
41
|
+
private acceptsInput;
|
|
42
|
+
private closeRequested;
|
|
43
|
+
private disposed;
|
|
44
|
+
private _focused;
|
|
45
|
+
constructor(tui: TUI, theme: Theme, keybindings: KeybindingsManager, onTransitionClose: () => void);
|
|
46
|
+
get focused(): boolean;
|
|
47
|
+
set focused(value: boolean);
|
|
48
|
+
show<T>(factory: RouterComponentFactory<T>): Promise<T>;
|
|
49
|
+
input(title: string, placeholder?: string): Promise<string | undefined>;
|
|
50
|
+
confirm(title: string, message: string): Promise<boolean>;
|
|
51
|
+
handleInput(data: string): void;
|
|
52
|
+
dispose(): void;
|
|
53
|
+
private beginTransition;
|
|
54
|
+
private clearTransitionTimer;
|
|
55
|
+
private setActiveScreen;
|
|
56
|
+
private disposeActiveScreen;
|
|
57
|
+
private disposeScreen;
|
|
58
|
+
}
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=dialog-host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialog-host.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/dialog-host.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/** Extension-owned dialog host that keeps every /router TUI page in one modal lifecycle. */
|
|
2
|
+
import { Container, isFocusable, Spacer, Text } from "@earendil-works/pi-tui";
|
|
3
|
+
import { DynamicBorder } from "../../modes/interactive/components/dynamic-border.js";
|
|
4
|
+
import { ExtensionInputComponent } from "../../modes/interactive/components/extension-input.js";
|
|
5
|
+
import { ExtensionSelectorComponent } from "../../modes/interactive/components/extension-selector.js";
|
|
6
|
+
import { keyLabel } from "../../modes/interactive/components/keybinding-hints.js";
|
|
7
|
+
export class RouterTuiSessionClosedError extends Error {
|
|
8
|
+
constructor() {
|
|
9
|
+
super("Router TUI session is closed.");
|
|
10
|
+
this.name = "RouterTuiSessionClosedError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export function createNativeRouterDialogs(ctx) {
|
|
14
|
+
return {
|
|
15
|
+
kind: "native",
|
|
16
|
+
select: (title, options) => ctx.ui.select(title, options),
|
|
17
|
+
input: (title, placeholder) => ctx.ui.input(title, placeholder),
|
|
18
|
+
confirm: (title, message) => ctx.ui.confirm(title, message),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Persistent root mounted by one ctx.ui.custom() call. Child dialogs resolve
|
|
23
|
+
* without closing this root, so async flow continuations can replace them
|
|
24
|
+
* without exposing the main editor between pages.
|
|
25
|
+
*/
|
|
26
|
+
export class RouterTuiSession extends Container {
|
|
27
|
+
constructor(tui, theme, keybindings, onTransitionClose) {
|
|
28
|
+
super();
|
|
29
|
+
this.kind = "tui";
|
|
30
|
+
this.acceptsInput = false;
|
|
31
|
+
this.closeRequested = false;
|
|
32
|
+
this.disposed = false;
|
|
33
|
+
this._focused = false;
|
|
34
|
+
this.tui = tui;
|
|
35
|
+
this.theme = theme;
|
|
36
|
+
this.keybindings = keybindings;
|
|
37
|
+
this.onTransitionClose = onTransitionClose;
|
|
38
|
+
const loading = new Container();
|
|
39
|
+
loading.addChild(new DynamicBorder((text) => theme.fg("border", text)));
|
|
40
|
+
loading.addChild(new Spacer(1));
|
|
41
|
+
loading.addChild(new Text(theme.fg("muted", "Loading router…"), 1, 0));
|
|
42
|
+
loading.addChild(new Spacer(1));
|
|
43
|
+
loading.addChild(new DynamicBorder((text) => theme.fg("border", text)));
|
|
44
|
+
this.activeScreen = loading;
|
|
45
|
+
this.addChild(loading);
|
|
46
|
+
}
|
|
47
|
+
get focused() {
|
|
48
|
+
return this._focused;
|
|
49
|
+
}
|
|
50
|
+
set focused(value) {
|
|
51
|
+
this._focused = value;
|
|
52
|
+
if (this.activeScreen && isFocusable(this.activeScreen)) {
|
|
53
|
+
this.activeScreen.focused = value && this.acceptsInput;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
show(factory) {
|
|
57
|
+
this.clearTransitionTimer();
|
|
58
|
+
if (this.disposed || this.closeRequested)
|
|
59
|
+
return Promise.reject(new RouterTuiSessionClosedError());
|
|
60
|
+
if (this.pendingReject)
|
|
61
|
+
return Promise.reject(new Error("Router TUI session already has an active dialog."));
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
let settled = false;
|
|
64
|
+
const fail = (error) => {
|
|
65
|
+
if (settled || this.disposed)
|
|
66
|
+
return;
|
|
67
|
+
settled = true;
|
|
68
|
+
this.acceptsInput = false;
|
|
69
|
+
if (this.pendingReject === reject)
|
|
70
|
+
this.pendingReject = undefined;
|
|
71
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
72
|
+
};
|
|
73
|
+
const done = (result) => {
|
|
74
|
+
if (settled || this.disposed)
|
|
75
|
+
return;
|
|
76
|
+
settled = true;
|
|
77
|
+
this.acceptsInput = false;
|
|
78
|
+
if (this.activeScreen && isFocusable(this.activeScreen))
|
|
79
|
+
this.activeScreen.focused = false;
|
|
80
|
+
if (this.pendingReject === reject)
|
|
81
|
+
this.pendingReject = undefined;
|
|
82
|
+
this.tui.setFocus(this);
|
|
83
|
+
this.beginTransition();
|
|
84
|
+
resolve(result);
|
|
85
|
+
};
|
|
86
|
+
this.pendingReject = reject;
|
|
87
|
+
let pending;
|
|
88
|
+
try {
|
|
89
|
+
pending = factory(this.tui, this.theme, this.keybindings, done);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
fail(error);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
void Promise.resolve(pending).then((component) => {
|
|
96
|
+
if (settled || this.disposed) {
|
|
97
|
+
this.disposeScreen(component);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
this.setActiveScreen(component);
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
this.disposeScreen(component);
|
|
105
|
+
fail(error);
|
|
106
|
+
}
|
|
107
|
+
}, fail);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
input(title, placeholder) {
|
|
111
|
+
return this.show((tui, _theme, _keybindings, done) => new ExtensionInputComponent(title, placeholder, done, () => done(undefined), { tui }));
|
|
112
|
+
}
|
|
113
|
+
async confirm(title, message) {
|
|
114
|
+
const selected = await this.show((tui, _theme, _keybindings, done) => new ExtensionSelectorComponent(title, ["Yes", "No"], done, () => done(undefined), {
|
|
115
|
+
tui,
|
|
116
|
+
subtitle: message,
|
|
117
|
+
}));
|
|
118
|
+
return selected === "Yes";
|
|
119
|
+
}
|
|
120
|
+
handleInput(data) {
|
|
121
|
+
if (this.acceptsInput) {
|
|
122
|
+
this.activeScreen?.handleInput?.(data);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (this.closeRequested || !this.keybindings.matches(data, "tui.select.cancel"))
|
|
126
|
+
return;
|
|
127
|
+
this.closeRequested = true;
|
|
128
|
+
this.onTransitionClose();
|
|
129
|
+
}
|
|
130
|
+
dispose() {
|
|
131
|
+
if (this.disposed)
|
|
132
|
+
return;
|
|
133
|
+
this.disposed = true;
|
|
134
|
+
this.acceptsInput = false;
|
|
135
|
+
this.clearTransitionTimer();
|
|
136
|
+
const reject = this.pendingReject;
|
|
137
|
+
this.pendingReject = undefined;
|
|
138
|
+
this.disposeActiveScreen();
|
|
139
|
+
this.clear();
|
|
140
|
+
reject?.(new RouterTuiSessionClosedError());
|
|
141
|
+
}
|
|
142
|
+
beginTransition() {
|
|
143
|
+
this.clearTransitionTimer();
|
|
144
|
+
this.transitionTimer = setTimeout(() => {
|
|
145
|
+
this.transitionTimer = undefined;
|
|
146
|
+
if (this.disposed || this.closeRequested || this.acceptsInput)
|
|
147
|
+
return;
|
|
148
|
+
const working = new Container();
|
|
149
|
+
working.addChild(new DynamicBorder((text) => this.theme.fg("border", text)));
|
|
150
|
+
working.addChild(new Spacer(1));
|
|
151
|
+
const cancelKey = keyLabel("tui.select.cancel", { keybindings: this.keybindings });
|
|
152
|
+
const closeHint = cancelKey ? `${cancelKey} closes /router` : "Close /router to continue";
|
|
153
|
+
working.addChild(new Text(this.theme.fg("muted", `Working… ${closeHint}`), 1, 0));
|
|
154
|
+
working.addChild(new Spacer(1));
|
|
155
|
+
working.addChild(new DynamicBorder((text) => this.theme.fg("border", text)));
|
|
156
|
+
this.disposeActiveScreen();
|
|
157
|
+
this.clear();
|
|
158
|
+
this.activeScreen = working;
|
|
159
|
+
this.addChild(working);
|
|
160
|
+
this.tui.requestRender();
|
|
161
|
+
}, 150);
|
|
162
|
+
}
|
|
163
|
+
clearTransitionTimer() {
|
|
164
|
+
if (this.transitionTimer === undefined)
|
|
165
|
+
return;
|
|
166
|
+
clearTimeout(this.transitionTimer);
|
|
167
|
+
this.transitionTimer = undefined;
|
|
168
|
+
}
|
|
169
|
+
setActiveScreen(component) {
|
|
170
|
+
this.disposeActiveScreen();
|
|
171
|
+
this.clear();
|
|
172
|
+
this.activeScreen = component;
|
|
173
|
+
this.addChild(component);
|
|
174
|
+
this.acceptsInput = true;
|
|
175
|
+
this.tui.setFocus(component);
|
|
176
|
+
this.tui.requestRender();
|
|
177
|
+
}
|
|
178
|
+
disposeActiveScreen() {
|
|
179
|
+
const screen = this.activeScreen;
|
|
180
|
+
this.activeScreen = undefined;
|
|
181
|
+
if (screen)
|
|
182
|
+
this.disposeScreen(screen);
|
|
183
|
+
}
|
|
184
|
+
disposeScreen(screen) {
|
|
185
|
+
const dispose = screen.dispose;
|
|
186
|
+
if (isFocusable(screen))
|
|
187
|
+
screen.focused = false;
|
|
188
|
+
try {
|
|
189
|
+
dispose?.call(screen);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
// A child cleanup failure must not strand the outer custom lifecycle.
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=dialog-host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialog-host.js","sourceRoot":"","sources":["../../../src/extensions/router/dialog-host.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAE5F,OAAO,EAAkB,SAAS,EAAkB,WAAW,EAAE,MAAM,EAAE,IAAI,EAAY,MAAM,wBAAwB,CAAC;AAGxH,OAAO,EAAE,aAAa,EAAE,MAAM,sDAAsD,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,uDAAuD,CAAC;AAChG,OAAO,EAAE,0BAA0B,EAAE,MAAM,0DAA0D,CAAC;AACtG,OAAO,EAAE,QAAQ,EAAE,MAAM,wDAAwD,CAAC;AA6BlF,MAAM,OAAO,2BAA4B,SAAQ,KAAK;IACrD;QACC,KAAK,CAAC,+BAA+B,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,GAAG,6BAA6B,CAAC;IAC3C,CAAC;CACD;AAED,MAAM,UAAU,yBAAyB,CAAC,GAA4B;IACrE,OAAO;QACN,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC;QACzD,KAAK,EAAE,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,WAAW,CAAC;QAC/D,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC;KAC3D,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,gBAAiB,SAAQ,SAAS;IAe9C,YAAY,GAAQ,EAAE,KAAY,EAAE,WAA+B,EAAE,iBAA6B;QACjG,KAAK,EAAE,CAAC;QAfA,SAAI,GAAG,KAAc,CAAC;QASvB,iBAAY,GAAG,KAAK,CAAC;QACrB,mBAAc,GAAG,KAAK,CAAC;QACvB,aAAQ,GAAG,KAAK,CAAC;QACjB,aAAQ,GAAG,KAAK,CAAC;QAIxB,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,iBAAiB,GAAG,iBAAiB,CAAC;QAE3C,MAAM,OAAO,GAAG,IAAI,SAAS,EAAE,CAAC;QAChC,OAAO,CAAC,QAAQ,CAAC,IAAI,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QACxE,OAAO,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,iBAAiB,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACvE,OAAO,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,OAAO,CAAC,QAAQ,CAAC,IAAI,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QACxE,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;QAC5B,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;IAED,IAAI,OAAO;QACV,OAAO,IAAI,CAAC,QAAQ,CAAC;IACtB,CAAC;IAED,IAAI,OAAO,CAAC,KAAc;QACzB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACtB,IAAI,IAAI,CAAC,YAAY,IAAI,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;YACzD,IAAI,CAAC,YAAY,CAAC,OAAO,GAAG,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC;QACxD,CAAC;IACF,CAAC;IAED,IAAI,CAAI,OAAkC;QACzC,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,cAAc;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,2BAA2B,EAAE,CAAC,CAAC;QACnG,IAAI,IAAI,CAAC,aAAa;YAAE,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC,CAAC;QAC7G,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACzC,IAAI,OAAO,GAAG,KAAK,CAAC;YACpB,MAAM,IAAI,GAAG,CAAC,KAAc,EAAE,EAAE;gBAC/B,IAAI,OAAO,IAAI,IAAI,CAAC,QAAQ;oBAAE,OAAO;gBACrC,OAAO,GAAG,IAAI,CAAC;gBACf,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;gBAC1B,IAAI,IAAI,CAAC,aAAa,KAAK,MAAM;oBAAE,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;gBAClE,MAAM,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACnE,CAAC,CAAC;YACF,MAAM,IAAI,GAAG,CAAC,MAAS,EAAE,EAAE;gBAC1B,IAAI,OAAO,IAAI,IAAI,CAAC,QAAQ;oBAAE,OAAO;gBACrC,OAAO,GAAG,IAAI,CAAC;gBACf,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;gBAC1B,IAAI,IAAI,CAAC,YAAY,IAAI,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC;oBAAE,IAAI,CAAC,YAAY,CAAC,OAAO,GAAG,KAAK,CAAC;gBAC3F,IAAI,IAAI,CAAC,aAAa,KAAK,MAAM;oBAAE,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;gBAClE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;gBACxB,IAAI,CAAC,eAAe,EAAE,CAAC;gBACvB,OAAO,CAAC,MAAM,CAAC,CAAC;YACjB,CAAC,CAAC;YACF,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC;YAC5B,IAAI,OAAmD,CAAC;YACxD,IAAI,CAAC;gBACJ,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YACjE,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,IAAI,CAAC,KAAK,CAAC,CAAC;gBACZ,OAAO;YACR,CAAC;YACD,KAAK,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;gBAChD,IAAI,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAC9B,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;oBAC9B,OAAO;gBACR,CAAC;gBACD,IAAI,CAAC;oBACJ,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;gBACjC,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBAChB,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;oBAC9B,IAAI,CAAC,KAAK,CAAC,CAAC;gBACb,CAAC;YACF,CAAC,EAAE,IAAI,CAAC,CAAC;QACV,CAAC,CAAC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,KAAa,EAAE,WAAoB;QACxC,OAAO,IAAI,CAAC,IAAI,CACf,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,CACnC,IAAI,uBAAuB,CAAC,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,CACtF,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,KAAa,EAAE,OAAe;QAC3C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAC/B,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,CACnC,IAAI,0BAA0B,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;YACjF,GAAG;YACH,QAAQ,EAAE,OAAO;SACjB,CAAC,CACH,CAAC;QACF,OAAO,QAAQ,KAAK,KAAK,CAAC;IAC3B,CAAC;IAED,WAAW,CAAC,IAAY;QACvB,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACvB,IAAI,CAAC,YAAY,EAAE,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC;YACvC,OAAO;QACR,CAAC;QACD,IAAI,IAAI,CAAC,cAAc,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,mBAAmB,CAAC;YAAE,OAAO;QACxF,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC1B,CAAC;IAED,OAAO;QACN,IAAI,IAAI,CAAC,QAAQ;YAAE,OAAO;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC;QAClC,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;QAC/B,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,MAAM,EAAE,CAAC,IAAI,2BAA2B,EAAE,CAAC,CAAC;IAC7C,CAAC;IAEO,eAAe;QACtB,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,eAAe,GAAG,UAAU,CAAC,GAAG,EAAE;YACtC,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;YACjC,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,YAAY;gBAAE,OAAO;YACtE,MAAM,OAAO,GAAG,IAAI,SAAS,EAAE,CAAC;YAChC,OAAO,CAAC,QAAQ,CAAC,IAAI,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;YAC7E,OAAO,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAChC,MAAM,SAAS,GAAG,QAAQ,CAAC,mBAAmB,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;YACnF,MAAM,SAAS,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,iBAAiB,CAAC,CAAC,CAAC,2BAA2B,CAAC;YAC1F,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,aAAa,SAAS,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACnF,OAAO,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAChC,OAAO,CAAC,QAAQ,CAAC,IAAI,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;YAC7E,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;YACb,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC;YAC5B,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACvB,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;QAC1B,CAAC,EAAE,GAAG,CAAC,CAAC;IACT,CAAC;IAEO,oBAAoB;QAC3B,IAAI,IAAI,CAAC,eAAe,KAAK,SAAS;YAAE,OAAO;QAC/C,YAAY,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACnC,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;IAClC,CAAC;IAEO,eAAe,CAAC,SAA0B;QACjD,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;QAC9B,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;IAC1B,CAAC;IAEO,mBAAmB;QAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC;QACjC,IAAI,CAAC,YAAY,GAAG,SAAS,CAAC;QAC9B,IAAI,MAAM;YAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;IAEO,aAAa,CAAC,MAAuB;QAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;QAC/B,IAAI,WAAW,CAAC,MAAM,CAAC;YAAE,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;QAChD,IAAI,CAAC;YACJ,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACR,sEAAsE;QACvE,CAAC;IACF,CAAC;CACD","sourcesContent":["/** Extension-owned dialog host that keeps every /router TUI page in one modal lifecycle. */\n\nimport { type Component, Container, type Focusable, isFocusable, Spacer, Text, type TUI } from \"@earendil-works/pi-tui\";\nimport type { ExtensionCommandContext } from \"../../core/extensions/types.ts\";\nimport type { KeybindingsManager } from \"../../core/keybindings.ts\";\nimport { DynamicBorder } from \"../../modes/interactive/components/dynamic-border.ts\";\nimport { ExtensionInputComponent } from \"../../modes/interactive/components/extension-input.ts\";\nimport { ExtensionSelectorComponent } from \"../../modes/interactive/components/extension-selector.ts\";\nimport { keyLabel } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\n\nexport type RouterComponent = Component & { dispose?(): void };\n\nexport type RouterComponentFactory<T> = (\n\ttui: TUI,\n\ttheme: Theme,\n\tkeybindings: KeybindingsManager,\n\tdone: (result: T) => void,\n) => RouterComponent | Promise<RouterComponent>;\n\ninterface RouterDialogBase {\n\tinput(title: string, placeholder?: string): Promise<string | undefined>;\n\tconfirm(title: string, message: string): Promise<boolean>;\n}\n\nexport interface RouterNativeDialogs extends RouterDialogBase {\n\treadonly kind: \"native\";\n\tselect(title: string, options: string[]): Promise<string | undefined>;\n}\n\nexport interface RouterTuiDialogs extends RouterDialogBase {\n\treadonly kind: \"tui\";\n\tshow<T>(factory: RouterComponentFactory<T>): Promise<T>;\n}\n\nexport type RouterDialogs = RouterNativeDialogs | RouterTuiDialogs;\n\nexport class RouterTuiSessionClosedError extends Error {\n\tconstructor() {\n\t\tsuper(\"Router TUI session is closed.\");\n\t\tthis.name = \"RouterTuiSessionClosedError\";\n\t}\n}\n\nexport function createNativeRouterDialogs(ctx: ExtensionCommandContext): RouterNativeDialogs {\n\treturn {\n\t\tkind: \"native\",\n\t\tselect: (title, options) => ctx.ui.select(title, options),\n\t\tinput: (title, placeholder) => ctx.ui.input(title, placeholder),\n\t\tconfirm: (title, message) => ctx.ui.confirm(title, message),\n\t};\n}\n\n/**\n * Persistent root mounted by one ctx.ui.custom() call. Child dialogs resolve\n * without closing this root, so async flow continuations can replace them\n * without exposing the main editor between pages.\n */\nexport class RouterTuiSession extends Container implements Focusable, RouterTuiDialogs {\n\treadonly kind = \"tui\" as const;\n\n\tprivate readonly tui: TUI;\n\tprivate readonly theme: Theme;\n\tprivate readonly keybindings: KeybindingsManager;\n\tprivate readonly onTransitionClose: () => void;\n\tprivate activeScreen: RouterComponent | undefined;\n\tprivate pendingReject: ((error: Error) => void) | undefined;\n\tprivate transitionTimer: ReturnType<typeof setTimeout> | undefined;\n\tprivate acceptsInput = false;\n\tprivate closeRequested = false;\n\tprivate disposed = false;\n\tprivate _focused = false;\n\n\tconstructor(tui: TUI, theme: Theme, keybindings: KeybindingsManager, onTransitionClose: () => void) {\n\t\tsuper();\n\t\tthis.tui = tui;\n\t\tthis.theme = theme;\n\t\tthis.keybindings = keybindings;\n\t\tthis.onTransitionClose = onTransitionClose;\n\n\t\tconst loading = new Container();\n\t\tloading.addChild(new DynamicBorder((text) => theme.fg(\"border\", text)));\n\t\tloading.addChild(new Spacer(1));\n\t\tloading.addChild(new Text(theme.fg(\"muted\", \"Loading router…\"), 1, 0));\n\t\tloading.addChild(new Spacer(1));\n\t\tloading.addChild(new DynamicBorder((text) => theme.fg(\"border\", text)));\n\t\tthis.activeScreen = loading;\n\t\tthis.addChild(loading);\n\t}\n\n\tget focused(): boolean {\n\t\treturn this._focused;\n\t}\n\n\tset focused(value: boolean) {\n\t\tthis._focused = value;\n\t\tif (this.activeScreen && isFocusable(this.activeScreen)) {\n\t\t\tthis.activeScreen.focused = value && this.acceptsInput;\n\t\t}\n\t}\n\n\tshow<T>(factory: RouterComponentFactory<T>): Promise<T> {\n\t\tthis.clearTransitionTimer();\n\t\tif (this.disposed || this.closeRequested) return Promise.reject(new RouterTuiSessionClosedError());\n\t\tif (this.pendingReject) return Promise.reject(new Error(\"Router TUI session already has an active dialog.\"));\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tlet settled = false;\n\t\t\tconst fail = (error: unknown) => {\n\t\t\t\tif (settled || this.disposed) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.acceptsInput = false;\n\t\t\t\tif (this.pendingReject === reject) this.pendingReject = undefined;\n\t\t\t\treject(error instanceof Error ? error : new Error(String(error)));\n\t\t\t};\n\t\t\tconst done = (result: T) => {\n\t\t\t\tif (settled || this.disposed) return;\n\t\t\t\tsettled = true;\n\t\t\t\tthis.acceptsInput = false;\n\t\t\t\tif (this.activeScreen && isFocusable(this.activeScreen)) this.activeScreen.focused = false;\n\t\t\t\tif (this.pendingReject === reject) this.pendingReject = undefined;\n\t\t\t\tthis.tui.setFocus(this);\n\t\t\t\tthis.beginTransition();\n\t\t\t\tresolve(result);\n\t\t\t};\n\t\t\tthis.pendingReject = reject;\n\t\t\tlet pending: RouterComponent | Promise<RouterComponent>;\n\t\t\ttry {\n\t\t\t\tpending = factory(this.tui, this.theme, this.keybindings, done);\n\t\t\t} catch (error) {\n\t\t\t\tfail(error);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvoid Promise.resolve(pending).then((component) => {\n\t\t\t\tif (settled || this.disposed) {\n\t\t\t\t\tthis.disposeScreen(component);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tthis.setActiveScreen(component);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.disposeScreen(component);\n\t\t\t\t\tfail(error);\n\t\t\t\t}\n\t\t\t}, fail);\n\t\t});\n\t}\n\n\tinput(title: string, placeholder?: string): Promise<string | undefined> {\n\t\treturn this.show<string | undefined>(\n\t\t\t(tui, _theme, _keybindings, done) =>\n\t\t\t\tnew ExtensionInputComponent(title, placeholder, done, () => done(undefined), { tui }),\n\t\t);\n\t}\n\n\tasync confirm(title: string, message: string): Promise<boolean> {\n\t\tconst selected = await this.show<string | undefined>(\n\t\t\t(tui, _theme, _keybindings, done) =>\n\t\t\t\tnew ExtensionSelectorComponent(title, [\"Yes\", \"No\"], done, () => done(undefined), {\n\t\t\t\t\ttui,\n\t\t\t\t\tsubtitle: message,\n\t\t\t\t}),\n\t\t);\n\t\treturn selected === \"Yes\";\n\t}\n\n\thandleInput(data: string): void {\n\t\tif (this.acceptsInput) {\n\t\t\tthis.activeScreen?.handleInput?.(data);\n\t\t\treturn;\n\t\t}\n\t\tif (this.closeRequested || !this.keybindings.matches(data, \"tui.select.cancel\")) return;\n\t\tthis.closeRequested = true;\n\t\tthis.onTransitionClose();\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tthis.acceptsInput = false;\n\t\tthis.clearTransitionTimer();\n\t\tconst reject = this.pendingReject;\n\t\tthis.pendingReject = undefined;\n\t\tthis.disposeActiveScreen();\n\t\tthis.clear();\n\t\treject?.(new RouterTuiSessionClosedError());\n\t}\n\n\tprivate beginTransition(): void {\n\t\tthis.clearTransitionTimer();\n\t\tthis.transitionTimer = setTimeout(() => {\n\t\t\tthis.transitionTimer = undefined;\n\t\t\tif (this.disposed || this.closeRequested || this.acceptsInput) return;\n\t\t\tconst working = new Container();\n\t\t\tworking.addChild(new DynamicBorder((text) => this.theme.fg(\"border\", text)));\n\t\t\tworking.addChild(new Spacer(1));\n\t\t\tconst cancelKey = keyLabel(\"tui.select.cancel\", { keybindings: this.keybindings });\n\t\t\tconst closeHint = cancelKey ? `${cancelKey} closes /router` : \"Close /router to continue\";\n\t\t\tworking.addChild(new Text(this.theme.fg(\"muted\", `Working… ${closeHint}`), 1, 0));\n\t\t\tworking.addChild(new Spacer(1));\n\t\t\tworking.addChild(new DynamicBorder((text) => this.theme.fg(\"border\", text)));\n\t\t\tthis.disposeActiveScreen();\n\t\t\tthis.clear();\n\t\t\tthis.activeScreen = working;\n\t\t\tthis.addChild(working);\n\t\t\tthis.tui.requestRender();\n\t\t}, 150);\n\t}\n\n\tprivate clearTransitionTimer(): void {\n\t\tif (this.transitionTimer === undefined) return;\n\t\tclearTimeout(this.transitionTimer);\n\t\tthis.transitionTimer = undefined;\n\t}\n\n\tprivate setActiveScreen(component: RouterComponent): void {\n\t\tthis.disposeActiveScreen();\n\t\tthis.clear();\n\t\tthis.activeScreen = component;\n\t\tthis.addChild(component);\n\t\tthis.acceptsInput = true;\n\t\tthis.tui.setFocus(component);\n\t\tthis.tui.requestRender();\n\t}\n\n\tprivate disposeActiveScreen(): void {\n\t\tconst screen = this.activeScreen;\n\t\tthis.activeScreen = undefined;\n\t\tif (screen) this.disposeScreen(screen);\n\t}\n\n\tprivate disposeScreen(screen: RouterComponent): void {\n\t\tconst dispose = screen.dispose;\n\t\tif (isFocusable(screen)) screen.focused = false;\n\t\ttry {\n\t\t\tdispose?.call(screen);\n\t\t} catch {\n\t\t\t// A child cleanup failure must not strand the outer custom lifecycle.\n\t\t}\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/probe.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAIlE,MAAM,WAAW,UAAU;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,UAAU,EAAE,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"probe.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/probe.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAIlE,MAAM,WAAW,UAAU;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,UAAU,EAAE,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,WAAW,CAAC,CA0DvB"}
|
|
@@ -11,6 +11,8 @@ export async function probeRelayModels(opts) {
|
|
|
11
11
|
if (baseUrl.protocol !== "http:" && baseUrl.protocol !== "https:") {
|
|
12
12
|
return { ok: false, error: `Unsupported protocol: ${baseUrl.protocol}` };
|
|
13
13
|
}
|
|
14
|
+
if (opts.signal?.aborted)
|
|
15
|
+
return { ok: false, error: "Cancelled." };
|
|
14
16
|
const controller = new AbortController();
|
|
15
17
|
const timeoutMs = opts.timeoutMs ?? DEFAULTS.probeTimeoutMs;
|
|
16
18
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"probe.js","sourceRoot":"","sources":["../../../src/extensions/router/probe.ts"],"names":[],"mappings":"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","sourcesContent":["/** Fetch OpenAI-compatible model catalog from a relay baseUrl. */\n\nimport { DEFAULTS, formatError } from \"./constants.ts\";\n\nexport interface ProbeModel {\n\tid: string;\n\tname?: string;\n}\n\nexport type ProbeResult = { ok: true; models: ProbeModel[]; truncated: boolean } | { ok: false; error: string };\n\nexport async function probeRelayModels(opts: {\n\tbaseUrl: string;\n\tapiKey?: string;\n\tsignal?: AbortSignal;\n\ttimeoutMs?: number;\n}): Promise<ProbeResult> {\n\tlet baseUrl: URL;\n\ttry {\n\t\tbaseUrl = new URL(opts.baseUrl);\n\t} catch {\n\t\treturn { ok: false, error: \"Base URL is not a valid URL.\" };\n\t}\n\tif (baseUrl.protocol !== \"http:\" && baseUrl.protocol !== \"https:\") {\n\t\treturn { ok: false, error: `Unsupported protocol: ${baseUrl.protocol}` };\n\t}\n\n\tconst controller = new AbortController();\n\tconst timeoutMs = opts.timeoutMs ?? DEFAULTS.probeTimeoutMs;\n\tconst timer = setTimeout(() => controller.abort(), timeoutMs);\n\tconst onOuterAbort = () => controller.abort();\n\topts.signal?.addEventListener(\"abort\", onOuterAbort, { once: true });\n\n\ttry {\n\t\tconst url = appendPath(baseUrl, \"models\");\n\t\tconst headers: Record<string, string> = { Accept: \"application/json\" };\n\t\tif (opts.apiKey) headers.Authorization = `Bearer ${opts.apiKey}`;\n\n\t\tconst response = await fetch(url, { headers, signal: controller.signal });\n\t\tif (!response.ok) {\n\t\t\tconst body = await readTextBounded(response, 4_096);\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: `HTTP ${response.status}${body ? `: ${body.slice(0, 400)}` : \"\"}`,\n\t\t\t};\n\t\t}\n\t\tconst text = await readTextBounded(response, DEFAULTS.probeBodyBytes);\n\t\tlet json: unknown;\n\t\ttry {\n\t\t\tjson = JSON.parse(text);\n\t\t} catch {\n\t\t\treturn { ok: false, error: \"Model catalog response is not JSON.\" };\n\t\t}\n\t\tconst models = parseOpenAIModels(json);\n\t\tif (models === null) {\n\t\t\treturn { ok: false, error: \"JSON has no OpenAI-style `data` array of model ids.\" };\n\t\t}\n\t\tconst sorted = dedupeSort(models);\n\t\tconst truncated = sorted.length > DEFAULTS.probeMaxModels;\n\t\treturn {\n\t\t\tok: true,\n\t\t\tmodels: sorted.slice(0, DEFAULTS.probeMaxModels),\n\t\t\ttruncated,\n\t\t};\n\t} catch (error) {\n\t\tif (controller.signal.aborted) {\n\t\t\treturn { ok: false, error: opts.signal?.aborted ? \"Cancelled.\" : `Timed out after ${timeoutMs}ms.` };\n\t\t}\n\t\treturn { ok: false, error: formatError(error) };\n\t} finally {\n\t\tclearTimeout(timer);\n\t\topts.signal?.removeEventListener(\"abort\", onOuterAbort);\n\t}\n}\n\nfunction appendPath(base: URL, segment: string): URL {\n\tconst url = new URL(base.href);\n\tconst path = url.pathname.replace(/\\/+$/, \"\");\n\turl.pathname = `${path}/${segment}`;\n\treturn url;\n}\n\nfunction parseOpenAIModels(json: unknown): ProbeModel[] | null {\n\tif (!json || typeof json !== \"object\") return null;\n\tconst data = (json as { data?: unknown }).data;\n\tif (!Array.isArray(data)) return null;\n\tconst models: ProbeModel[] = [];\n\tfor (const item of data) {\n\t\tif (!item || typeof item !== \"object\") continue;\n\t\tconst record = item as Record<string, unknown>;\n\t\tconst id = typeof record.id === \"string\" ? record.id.trim() : \"\";\n\t\tif (!id) continue;\n\t\tconst name =\n\t\t\ttypeof record.name === \"string\" && record.name.trim() && record.name.trim() !== id\n\t\t\t\t? record.name.trim()\n\t\t\t\t: undefined;\n\t\tmodels.push(name ? { id, name } : { id });\n\t}\n\treturn models;\n}\n\nfunction dedupeSort(models: ProbeModel[]): ProbeModel[] {\n\tconst map = new Map<string, ProbeModel>();\n\tfor (const model of models) {\n\t\tif (!map.has(model.id)) map.set(model.id, model);\n\t}\n\treturn [...map.values()].sort((a, b) => a.id.localeCompare(b.id));\n}\n\nasync function readTextBounded(response: Response, maxBytes: number): Promise<string> {\n\tconst reader = response.body?.getReader();\n\tif (!reader) return await response.text();\n\tconst chunks: Uint8Array[] = [];\n\tlet total = 0;\n\twhile (true) {\n\t\tconst { done, value } = await reader.read();\n\t\tif (done) break;\n\t\tif (!value) continue;\n\t\ttotal += value.byteLength;\n\t\tif (total > maxBytes) {\n\t\t\tawait reader.cancel();\n\t\t\tthrow new Error(`Response exceeds ${maxBytes} bytes.`);\n\t\t}\n\t\tchunks.push(value);\n\t}\n\tconst merged = new Uint8Array(total);\n\tlet offset = 0;\n\tfor (const chunk of chunks) {\n\t\tmerged.set(chunk, offset);\n\t\toffset += chunk.byteLength;\n\t}\n\treturn new TextDecoder().decode(merged);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"probe.js","sourceRoot":"","sources":["../../../src/extensions/router/probe.ts"],"names":[],"mappings":"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","sourcesContent":["/** Fetch OpenAI-compatible model catalog from a relay baseUrl. */\n\nimport { DEFAULTS, formatError } from \"./constants.ts\";\n\nexport interface ProbeModel {\n\tid: string;\n\tname?: string;\n}\n\nexport type ProbeResult = { ok: true; models: ProbeModel[]; truncated: boolean } | { ok: false; error: string };\n\nexport async function probeRelayModels(opts: {\n\tbaseUrl: string;\n\tapiKey?: string;\n\tsignal?: AbortSignal;\n\ttimeoutMs?: number;\n}): Promise<ProbeResult> {\n\tlet baseUrl: URL;\n\ttry {\n\t\tbaseUrl = new URL(opts.baseUrl);\n\t} catch {\n\t\treturn { ok: false, error: \"Base URL is not a valid URL.\" };\n\t}\n\tif (baseUrl.protocol !== \"http:\" && baseUrl.protocol !== \"https:\") {\n\t\treturn { ok: false, error: `Unsupported protocol: ${baseUrl.protocol}` };\n\t}\n\n\tif (opts.signal?.aborted) return { ok: false, error: \"Cancelled.\" };\n\tconst controller = new AbortController();\n\tconst timeoutMs = opts.timeoutMs ?? DEFAULTS.probeTimeoutMs;\n\tconst timer = setTimeout(() => controller.abort(), timeoutMs);\n\tconst onOuterAbort = () => controller.abort();\n\topts.signal?.addEventListener(\"abort\", onOuterAbort, { once: true });\n\n\ttry {\n\t\tconst url = appendPath(baseUrl, \"models\");\n\t\tconst headers: Record<string, string> = { Accept: \"application/json\" };\n\t\tif (opts.apiKey) headers.Authorization = `Bearer ${opts.apiKey}`;\n\n\t\tconst response = await fetch(url, { headers, signal: controller.signal });\n\t\tif (!response.ok) {\n\t\t\tconst body = await readTextBounded(response, 4_096);\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: `HTTP ${response.status}${body ? `: ${body.slice(0, 400)}` : \"\"}`,\n\t\t\t};\n\t\t}\n\t\tconst text = await readTextBounded(response, DEFAULTS.probeBodyBytes);\n\t\tlet json: unknown;\n\t\ttry {\n\t\t\tjson = JSON.parse(text);\n\t\t} catch {\n\t\t\treturn { ok: false, error: \"Model catalog response is not JSON.\" };\n\t\t}\n\t\tconst models = parseOpenAIModels(json);\n\t\tif (models === null) {\n\t\t\treturn { ok: false, error: \"JSON has no OpenAI-style `data` array of model ids.\" };\n\t\t}\n\t\tconst sorted = dedupeSort(models);\n\t\tconst truncated = sorted.length > DEFAULTS.probeMaxModels;\n\t\treturn {\n\t\t\tok: true,\n\t\t\tmodels: sorted.slice(0, DEFAULTS.probeMaxModels),\n\t\t\ttruncated,\n\t\t};\n\t} catch (error) {\n\t\tif (controller.signal.aborted) {\n\t\t\treturn { ok: false, error: opts.signal?.aborted ? \"Cancelled.\" : `Timed out after ${timeoutMs}ms.` };\n\t\t}\n\t\treturn { ok: false, error: formatError(error) };\n\t} finally {\n\t\tclearTimeout(timer);\n\t\topts.signal?.removeEventListener(\"abort\", onOuterAbort);\n\t}\n}\n\nfunction appendPath(base: URL, segment: string): URL {\n\tconst url = new URL(base.href);\n\tconst path = url.pathname.replace(/\\/+$/, \"\");\n\turl.pathname = `${path}/${segment}`;\n\treturn url;\n}\n\nfunction parseOpenAIModels(json: unknown): ProbeModel[] | null {\n\tif (!json || typeof json !== \"object\") return null;\n\tconst data = (json as { data?: unknown }).data;\n\tif (!Array.isArray(data)) return null;\n\tconst models: ProbeModel[] = [];\n\tfor (const item of data) {\n\t\tif (!item || typeof item !== \"object\") continue;\n\t\tconst record = item as Record<string, unknown>;\n\t\tconst id = typeof record.id === \"string\" ? record.id.trim() : \"\";\n\t\tif (!id) continue;\n\t\tconst name =\n\t\t\ttypeof record.name === \"string\" && record.name.trim() && record.name.trim() !== id\n\t\t\t\t? record.name.trim()\n\t\t\t\t: undefined;\n\t\tmodels.push(name ? { id, name } : { id });\n\t}\n\treturn models;\n}\n\nfunction dedupeSort(models: ProbeModel[]): ProbeModel[] {\n\tconst map = new Map<string, ProbeModel>();\n\tfor (const model of models) {\n\t\tif (!map.has(model.id)) map.set(model.id, model);\n\t}\n\treturn [...map.values()].sort((a, b) => a.id.localeCompare(b.id));\n}\n\nasync function readTextBounded(response: Response, maxBytes: number): Promise<string> {\n\tconst reader = response.body?.getReader();\n\tif (!reader) return await response.text();\n\tconst chunks: Uint8Array[] = [];\n\tlet total = 0;\n\twhile (true) {\n\t\tconst { done, value } = await reader.read();\n\t\tif (done) break;\n\t\tif (!value) continue;\n\t\ttotal += value.byteLength;\n\t\tif (total > maxBytes) {\n\t\t\tawait reader.cancel();\n\t\t\tthrow new Error(`Response exceeds ${maxBytes} bytes.`);\n\t\t}\n\t\tchunks.push(value);\n\t}\n\tconst merged = new Uint8Array(total);\n\tlet offset = 0;\n\tfor (const chunk of chunks) {\n\t\tmerged.set(chunk, offset);\n\t\toffset += chunk.byteLength;\n\t}\n\treturn new TextDecoder().decode(merged);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/ui.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../../src/extensions/router/ui.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AA6F5F,wBAAgB,oBAAoB,CACnC,OAAO,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,EACrD,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACb,OAAO,CAET;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,uBAAuB,EAAE,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBlH;AAqtBD,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAiBrF"}
|