snow-flow 10.0.120 → 10.0.122
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/cli/cmd/tui/app.tsx +61 -99
- package/src/provider/provider.ts +20 -1
- package/src/pty/index.ts +0 -1
- package/src/server/routes/tui-ws.ts +0 -1
package/package.json
CHANGED
package/src/cli/cmd/tui/app.tsx
CHANGED
|
@@ -118,115 +118,77 @@ export function tui(input: {
|
|
|
118
118
|
const skipThemeDetection = !!process.env.OPENCODE_SKIP_THEME_DETECTION || !!process.env.OPENCODE_REMOTE_TUI
|
|
119
119
|
// promise to prevent immediate exit
|
|
120
120
|
return new Promise<void>(async (resolve) => {
|
|
121
|
-
// Crash handlers for debugging PTY rendering issues
|
|
122
|
-
process.on("uncaughtException", (err) => {
|
|
123
|
-
console.error("[snow-flow] UNCAUGHT:", err.message, err.stack)
|
|
124
|
-
})
|
|
125
|
-
process.on("unhandledRejection", (err) => {
|
|
126
|
-
console.error("[snow-flow] UNHANDLED:", err)
|
|
127
|
-
})
|
|
128
|
-
process.on("exit", (code) => {
|
|
129
|
-
if (code !== 0) console.error("[snow-flow] EXIT code:", code)
|
|
130
|
-
})
|
|
131
|
-
|
|
132
121
|
let mode: "dark" | "light" = "dark"
|
|
133
|
-
if (skipThemeDetection) {
|
|
134
|
-
console.log("[snow-flow] skipping theme detection")
|
|
135
|
-
} else {
|
|
136
|
-
console.log("[snow-flow] detecting theme...")
|
|
122
|
+
if (!skipThemeDetection) {
|
|
137
123
|
mode = await getTerminalBackgroundColor()
|
|
138
|
-
console.log(`[snow-flow] theme: ${mode}`)
|
|
139
124
|
}
|
|
140
125
|
const onExit = async () => {
|
|
141
126
|
await input.onExit?.()
|
|
142
127
|
resolve()
|
|
143
128
|
}
|
|
144
129
|
|
|
145
|
-
//
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
130
|
+
// Clear screen before render — ensures terminal viewport starts at row 0
|
|
131
|
+
// so @opentui's absolute ANSI positioning aligns with visible area
|
|
132
|
+
process.stdout.write("\x1b[2J\x1b[H")
|
|
133
|
+
|
|
134
|
+
await render(
|
|
135
|
+
() => (
|
|
136
|
+
<ErrorBoundary
|
|
137
|
+
fallback={(error, reset) => <ErrorComponent error={error} reset={reset} onExit={onExit} mode={mode} />}
|
|
138
|
+
>
|
|
139
|
+
<ArgsProvider {...input.args}>
|
|
140
|
+
<ExitProvider onExit={onExit}>
|
|
141
|
+
<KVProvider>
|
|
142
|
+
<ToastProvider>
|
|
143
|
+
<RouteProvider>
|
|
144
|
+
<SDKProvider
|
|
145
|
+
url={input.url}
|
|
146
|
+
directory={input.directory}
|
|
147
|
+
fetch={input.fetch}
|
|
148
|
+
events={input.events}
|
|
149
|
+
>
|
|
150
|
+
<SyncProvider>
|
|
151
|
+
<ThemeProvider mode={mode}>
|
|
152
|
+
<LocalProvider>
|
|
153
|
+
<KeybindProvider>
|
|
154
|
+
<PromptStashProvider>
|
|
155
|
+
<DialogProvider>
|
|
156
|
+
<CommandProvider>
|
|
157
|
+
<FrecencyProvider>
|
|
158
|
+
<PromptHistoryProvider>
|
|
159
|
+
<PromptRefProvider>
|
|
160
|
+
<App />
|
|
161
|
+
</PromptRefProvider>
|
|
162
|
+
</PromptHistoryProvider>
|
|
163
|
+
</FrecencyProvider>
|
|
164
|
+
</CommandProvider>
|
|
165
|
+
</DialogProvider>
|
|
166
|
+
</PromptStashProvider>
|
|
167
|
+
</KeybindProvider>
|
|
168
|
+
</LocalProvider>
|
|
169
|
+
</ThemeProvider>
|
|
170
|
+
</SyncProvider>
|
|
171
|
+
</SDKProvider>
|
|
172
|
+
</RouteProvider>
|
|
173
|
+
</ToastProvider>
|
|
174
|
+
</KVProvider>
|
|
175
|
+
</ExitProvider>
|
|
176
|
+
</ArgsProvider>
|
|
177
|
+
</ErrorBoundary>
|
|
178
|
+
),
|
|
179
|
+
{
|
|
180
|
+
targetFps: 60,
|
|
181
|
+
gatherStats: false,
|
|
182
|
+
exitOnCtrlC: false,
|
|
183
|
+
useKittyKeyboard: process.env.OPENCODE_DISABLE_KITTY_KEYBOARD ? undefined : {},
|
|
184
|
+
consoleOptions: {
|
|
185
|
+
keyBindings: [{ name: "y", ctrl: true, action: "copy-selection" }],
|
|
186
|
+
onCopySelection: (text: string) => {
|
|
187
|
+
Clipboard.copy(text).catch(() => {})
|
|
188
|
+
},
|
|
166
189
|
},
|
|
167
190
|
},
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
log("step 2: creating CliRenderer...")
|
|
171
|
-
const cliRenderer = await createRenderer(renderConfig as any)
|
|
172
|
-
log("step 3: CliRenderer created! Starting render...")
|
|
173
|
-
|
|
174
|
-
try {
|
|
175
|
-
await render(
|
|
176
|
-
() => {
|
|
177
|
-
log("step 4: component factory invoked")
|
|
178
|
-
return (
|
|
179
|
-
<ErrorBoundary
|
|
180
|
-
fallback={(error, reset) => <ErrorComponent error={error} reset={reset} onExit={onExit} mode={mode} />}
|
|
181
|
-
>
|
|
182
|
-
<ArgsProvider {...input.args}>
|
|
183
|
-
<ExitProvider onExit={onExit}>
|
|
184
|
-
<KVProvider>
|
|
185
|
-
<ToastProvider>
|
|
186
|
-
<RouteProvider>
|
|
187
|
-
<SDKProvider
|
|
188
|
-
url={input.url}
|
|
189
|
-
directory={input.directory}
|
|
190
|
-
fetch={input.fetch}
|
|
191
|
-
events={input.events}
|
|
192
|
-
>
|
|
193
|
-
<SyncProvider>
|
|
194
|
-
<ThemeProvider mode={mode}>
|
|
195
|
-
<LocalProvider>
|
|
196
|
-
<KeybindProvider>
|
|
197
|
-
<PromptStashProvider>
|
|
198
|
-
<DialogProvider>
|
|
199
|
-
<CommandProvider>
|
|
200
|
-
<FrecencyProvider>
|
|
201
|
-
<PromptHistoryProvider>
|
|
202
|
-
<PromptRefProvider>
|
|
203
|
-
<App />
|
|
204
|
-
</PromptRefProvider>
|
|
205
|
-
</PromptHistoryProvider>
|
|
206
|
-
</FrecencyProvider>
|
|
207
|
-
</CommandProvider>
|
|
208
|
-
</DialogProvider>
|
|
209
|
-
</PromptStashProvider>
|
|
210
|
-
</KeybindProvider>
|
|
211
|
-
</LocalProvider>
|
|
212
|
-
</ThemeProvider>
|
|
213
|
-
</SyncProvider>
|
|
214
|
-
</SDKProvider>
|
|
215
|
-
</RouteProvider>
|
|
216
|
-
</ToastProvider>
|
|
217
|
-
</KVProvider>
|
|
218
|
-
</ExitProvider>
|
|
219
|
-
</ArgsProvider>
|
|
220
|
-
</ErrorBoundary>
|
|
221
|
-
)
|
|
222
|
-
},
|
|
223
|
-
cliRenderer,
|
|
224
|
-
)
|
|
225
|
-
} catch (e) {
|
|
226
|
-
console.error("[snow-flow] render failed:", e instanceof Error ? e.message : e)
|
|
227
|
-
if (e instanceof Error && e.stack) console.error(e.stack)
|
|
228
|
-
resolve()
|
|
229
|
-
}
|
|
191
|
+
)
|
|
230
192
|
})
|
|
231
193
|
}
|
|
232
194
|
|
package/src/provider/provider.ts
CHANGED
|
@@ -568,6 +568,25 @@ export namespace Provider {
|
|
|
568
568
|
const data = (await response.json()) as { models?: Array<{ name: string; details?: { parameter_size?: string; family?: string } }> }
|
|
569
569
|
if (!data.models?.length) return { autoload: false }
|
|
570
570
|
|
|
571
|
+
// Check tool support per model via /api/show (parallel, best-effort)
|
|
572
|
+
const toolSupport = new Map<string, boolean>()
|
|
573
|
+
await Promise.all(
|
|
574
|
+
data.models.map(async (m) => {
|
|
575
|
+
try {
|
|
576
|
+
const res = await fetch(`${host}/api/show`, {
|
|
577
|
+
method: "POST",
|
|
578
|
+
body: JSON.stringify({ name: m.name }),
|
|
579
|
+
signal: AbortSignal.timeout(2000),
|
|
580
|
+
})
|
|
581
|
+
if (!res.ok) return
|
|
582
|
+
const info = (await res.json()) as { template?: string }
|
|
583
|
+
toolSupport.set(m.name, info.template?.includes(".Tools") ?? false)
|
|
584
|
+
} catch {
|
|
585
|
+
// assume no tool support if check fails
|
|
586
|
+
}
|
|
587
|
+
}),
|
|
588
|
+
)
|
|
589
|
+
|
|
571
590
|
for (const model of data.models) {
|
|
572
591
|
if (input.models[model.name]) continue
|
|
573
592
|
input.models[model.name] = fromModelsDevModel(
|
|
@@ -578,7 +597,7 @@ export namespace Provider {
|
|
|
578
597
|
family: model.details?.family ?? model.name.split(":")[0],
|
|
579
598
|
attachment: false,
|
|
580
599
|
reasoning: false,
|
|
581
|
-
tool_call:
|
|
600
|
+
tool_call: toolSupport.get(model.name) ?? false,
|
|
582
601
|
temperature: true,
|
|
583
602
|
release_date: "2024-01-01",
|
|
584
603
|
modalities: { input: ["text"], output: ["text"] },
|
package/src/pty/index.ts
CHANGED