@yagr/agent 0.2.9 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +251 -9
- package/dist/cli.js.map +1 -1
- package/dist/config/n8n-config-service.d.ts +2 -1
- package/dist/config/n8n-config-service.d.ts.map +1 -1
- package/dist/config/n8n-config-service.js +2 -1
- package/dist/config/n8n-config-service.js.map +1 -1
- package/dist/config/yagr-config-service.d.ts +1 -1
- package/dist/config/yagr-config-service.d.ts.map +1 -1
- package/dist/config/yagr-home.d.ts +7 -0
- package/dist/config/yagr-home.d.ts.map +1 -1
- package/dist/config/yagr-home.js +19 -0
- package/dist/config/yagr-home.js.map +1 -1
- package/dist/gateway/format-message.d.ts +3 -0
- package/dist/gateway/format-message.d.ts.map +1 -1
- package/dist/gateway/format-message.js +63 -10
- package/dist/gateway/format-message.js.map +1 -1
- package/dist/gateway/interactive-ui.d.ts.map +1 -1
- package/dist/gateway/interactive-ui.js +49 -4
- package/dist/gateway/interactive-ui.js.map +1 -1
- package/dist/gateway/local-open-bridge.d.ts +3 -0
- package/dist/gateway/local-open-bridge.d.ts.map +1 -0
- package/dist/gateway/local-open-bridge.js +54 -0
- package/dist/gateway/local-open-bridge.js.map +1 -0
- package/dist/gateway/webui.d.ts.map +1 -1
- package/dist/gateway/webui.js +50 -53
- package/dist/gateway/webui.js.map +1 -1
- package/dist/gateway/workflow-links.d.ts +12 -0
- package/dist/gateway/workflow-links.d.ts.map +1 -0
- package/dist/gateway/workflow-links.js +53 -0
- package/dist/gateway/workflow-links.js.map +1 -0
- package/dist/llm/anthropic-account.d.ts +20 -0
- package/dist/llm/anthropic-account.d.ts.map +1 -0
- package/dist/llm/anthropic-account.js +111 -0
- package/dist/llm/anthropic-account.js.map +1 -0
- package/dist/llm/copilot-account.d.ts +36 -0
- package/dist/llm/copilot-account.d.ts.map +1 -0
- package/dist/llm/copilot-account.js +573 -0
- package/dist/llm/copilot-account.js.map +1 -0
- package/dist/llm/create-language-model.d.ts +2 -2
- package/dist/llm/create-language-model.d.ts.map +1 -1
- package/dist/llm/create-language-model.js +187 -38
- package/dist/llm/create-language-model.js.map +1 -1
- package/dist/llm/google-account.d.ts +31 -0
- package/dist/llm/google-account.d.ts.map +1 -0
- package/dist/llm/google-account.js +851 -0
- package/dist/llm/google-account.js.map +1 -0
- package/dist/llm/model-catalog-cache.d.ts +4 -0
- package/dist/llm/model-catalog-cache.d.ts.map +1 -0
- package/dist/llm/model-catalog-cache.js +46 -0
- package/dist/llm/model-catalog-cache.js.map +1 -0
- package/dist/llm/openai-account.d.ts +33 -0
- package/dist/llm/openai-account.d.ts.map +1 -0
- package/dist/llm/openai-account.js +578 -0
- package/dist/llm/openai-account.js.map +1 -0
- package/dist/llm/provider-discovery.d.ts +3 -0
- package/dist/llm/provider-discovery.d.ts.map +1 -0
- package/dist/llm/provider-discovery.js +40 -0
- package/dist/llm/provider-discovery.js.map +1 -0
- package/dist/llm/provider-registry.d.ts +37 -0
- package/dist/llm/provider-registry.d.ts.map +1 -0
- package/dist/llm/provider-registry.js +186 -0
- package/dist/llm/provider-registry.js.map +1 -0
- package/dist/llm/proxy-runtime.d.ts +37 -0
- package/dist/llm/proxy-runtime.d.ts.map +1 -0
- package/dist/llm/proxy-runtime.js +462 -0
- package/dist/llm/proxy-runtime.js.map +1 -0
- package/dist/llm/test-model-policy.d.ts +3 -0
- package/dist/llm/test-model-policy.d.ts.map +1 -0
- package/dist/llm/test-model-policy.js +16 -0
- package/dist/llm/test-model-policy.js.map +1 -0
- package/dist/n8n-local/bootstrap.d.ts +12 -0
- package/dist/n8n-local/bootstrap.d.ts.map +1 -0
- package/dist/n8n-local/bootstrap.js +281 -0
- package/dist/n8n-local/bootstrap.js.map +1 -0
- package/dist/n8n-local/browser-auth.d.ts +12 -0
- package/dist/n8n-local/browser-auth.d.ts.map +1 -0
- package/dist/n8n-local/browser-auth.js +159 -0
- package/dist/n8n-local/browser-auth.js.map +1 -0
- package/dist/n8n-local/detect.d.ts +50 -0
- package/dist/n8n-local/detect.d.ts.map +1 -0
- package/dist/n8n-local/detect.js +207 -0
- package/dist/n8n-local/detect.js.map +1 -0
- package/dist/n8n-local/direct-manager.d.ts +15 -0
- package/dist/n8n-local/direct-manager.d.ts.map +1 -0
- package/dist/n8n-local/direct-manager.js +232 -0
- package/dist/n8n-local/direct-manager.js.map +1 -0
- package/dist/n8n-local/docker-manager.d.ts +18 -0
- package/dist/n8n-local/docker-manager.d.ts.map +1 -0
- package/dist/n8n-local/docker-manager.js +217 -0
- package/dist/n8n-local/docker-manager.js.map +1 -0
- package/dist/n8n-local/managed-runtime.d.ts +17 -0
- package/dist/n8n-local/managed-runtime.d.ts.map +1 -0
- package/dist/n8n-local/managed-runtime.js +122 -0
- package/dist/n8n-local/managed-runtime.js.map +1 -0
- package/dist/n8n-local/owner-credentials.d.ts +15 -0
- package/dist/n8n-local/owner-credentials.d.ts.map +1 -0
- package/dist/n8n-local/owner-credentials.js +50 -0
- package/dist/n8n-local/owner-credentials.js.map +1 -0
- package/dist/n8n-local/plan.d.ts +16 -0
- package/dist/n8n-local/plan.d.ts.map +1 -0
- package/dist/n8n-local/plan.js +48 -0
- package/dist/n8n-local/plan.js.map +1 -0
- package/dist/n8n-local/state.d.ts +42 -0
- package/dist/n8n-local/state.d.ts.map +1 -0
- package/dist/n8n-local/state.js +108 -0
- package/dist/n8n-local/state.js.map +1 -0
- package/dist/n8n-local/workflow-open.d.ts +21 -0
- package/dist/n8n-local/workflow-open.d.ts.map +1 -0
- package/dist/n8n-local/workflow-open.js +50 -0
- package/dist/n8n-local/workflow-open.js.map +1 -0
- package/dist/runtime/context-compaction.d.ts.map +1 -1
- package/dist/runtime/context-compaction.js +7 -0
- package/dist/runtime/context-compaction.js.map +1 -1
- package/dist/runtime/run-engine.d.ts.map +1 -1
- package/dist/runtime/run-engine.js +52 -1
- package/dist/runtime/run-engine.js.map +1 -1
- package/dist/setup/setup-wizard.d.ts +36 -3
- package/dist/setup/setup-wizard.d.ts.map +1 -1
- package/dist/setup/setup-wizard.js +470 -62
- package/dist/setup/setup-wizard.js.map +1 -1
- package/dist/setup.d.ts +2 -1
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +204 -89
- package/dist/setup.js.map +1 -1
- package/dist/system/open-external.d.ts +2 -0
- package/dist/system/open-external.d.ts.map +1 -0
- package/dist/system/open-external.js +25 -0
- package/dist/system/open-external.js.map +1 -0
- package/dist/system/package-manager.d.ts +6 -0
- package/dist/system/package-manager.d.ts.map +1 -0
- package/dist/system/package-manager.js +13 -0
- package/dist/system/package-manager.js.map +1 -0
- package/dist/tools/build-tools.d.ts +110 -65
- package/dist/tools/build-tools.d.ts.map +1 -1
- package/dist/tools/deploy.d.ts +14 -14
- package/dist/tools/generate-workflow.d.ts +5 -5
- package/dist/tools/n8nac.d.ts +96 -53
- package/dist/tools/n8nac.d.ts.map +1 -1
- package/dist/tools/n8nac.js +52 -20
- package/dist/tools/n8nac.js.map +1 -1
- package/dist/tools/observer.d.ts +1 -0
- package/dist/tools/observer.d.ts.map +1 -1
- package/dist/tools/observer.js.map +1 -1
- package/dist/tools/present-workflow-result.d.ts +2 -0
- package/dist/tools/present-workflow-result.d.ts.map +1 -1
- package/dist/tools/present-workflow-result.js +11 -2
- package/dist/tools/present-workflow-result.js.map +1 -1
- package/dist/tools/request-required-action.d.ts +7 -7
- package/dist/tools/request-required-action.js +4 -4
- package/dist/tools/request-required-action.js.map +1 -1
- package/dist/tools/validate.d.ts +14 -14
- package/dist/tools/write-workspace-file.d.ts +5 -5
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/webui/app.js +14 -1
- package/dist/webui/app.js.map +2 -2
- package/package.json +15 -2
|
@@ -1,20 +1,31 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text, render, useApp, useInput, useStdout } from 'ink';
|
|
3
3
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { getProviderDisplayName, getProviderSetupHint, isExperimentalProvider, isOAuthAccountProvider, providerRequiresApiKey, YAGR_MODEL_PROVIDERS, } from '../llm/provider-registry.js';
|
|
4
5
|
// ─── Palette ──────────────────────────────────────────────────────────────────
|
|
5
6
|
const CURSOR = '▸';
|
|
6
7
|
const CHECK = '✓';
|
|
7
8
|
const DOT = '·';
|
|
8
9
|
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
9
|
-
const
|
|
10
|
-
'
|
|
10
|
+
const PROVIDER_WIZARD_ORDER = [
|
|
11
|
+
'openai',
|
|
12
|
+
'openai-proxy',
|
|
13
|
+
'anthropic',
|
|
14
|
+
'anthropic-proxy',
|
|
15
|
+
'google',
|
|
16
|
+
'google-proxy',
|
|
17
|
+
'copilot-proxy',
|
|
18
|
+
'groq',
|
|
19
|
+
'mistral',
|
|
20
|
+
'openrouter',
|
|
11
21
|
];
|
|
22
|
+
const VALID_PROVIDERS = PROVIDER_WIZARD_ORDER.filter((provider) => YAGR_MODEL_PROVIDERS.includes(provider));
|
|
12
23
|
const SURFACE_OPTIONS = [
|
|
13
24
|
{ value: 'telegram', label: 'Telegram', hint: 'Bot-based chat gateway' },
|
|
14
25
|
];
|
|
15
|
-
export function runSetupWizard(callbacks) {
|
|
26
|
+
export function runSetupWizard(callbacks, options = {}) {
|
|
16
27
|
return new Promise((resolve) => {
|
|
17
|
-
const { unmount } = render(_jsx(SetupWizard, { callbacks: callbacks, onDone: (result) => { unmount(); resolve(result); } }));
|
|
28
|
+
const { unmount } = render(_jsx(SetupWizard, { callbacks: callbacks, options: options, onDone: (result) => { unmount(); resolve(result); } }));
|
|
18
29
|
});
|
|
19
30
|
}
|
|
20
31
|
function sectionFor(phase) {
|
|
@@ -33,15 +44,65 @@ function sectionIndex(phase) {
|
|
|
33
44
|
return 2;
|
|
34
45
|
return 3;
|
|
35
46
|
}
|
|
47
|
+
function getProviderAuthCopy(provider) {
|
|
48
|
+
if (provider === 'openai-proxy') {
|
|
49
|
+
return {
|
|
50
|
+
title: 'Connect OpenAI account',
|
|
51
|
+
body: [
|
|
52
|
+
'Yagr will open your browser to sign you in with your ChatGPT account.',
|
|
53
|
+
'This uses your ChatGPT subscription — no API credits are consumed.',
|
|
54
|
+
],
|
|
55
|
+
continueLabel: 'Sign in with ChatGPT',
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (provider === 'anthropic-proxy') {
|
|
59
|
+
return {
|
|
60
|
+
title: 'Connect Claude token',
|
|
61
|
+
body: [
|
|
62
|
+
'Generate a setup-token on a machine where Claude CLI is installed and logged in:',
|
|
63
|
+
'`claude setup-token`',
|
|
64
|
+
'Paste the generated setup-token below.',
|
|
65
|
+
],
|
|
66
|
+
continueLabel: 'Paste setup-token',
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (provider === 'google-proxy') {
|
|
70
|
+
return {
|
|
71
|
+
title: 'Connect Gemini account',
|
|
72
|
+
body: [
|
|
73
|
+
'Yagr runs a native Google OAuth flow for your Gemini account.',
|
|
74
|
+
'It will show a browser URL and ask you to paste the redirect URL back here.',
|
|
75
|
+
],
|
|
76
|
+
continueLabel: 'Continue with Gemini sign-in',
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
if (provider === 'copilot-proxy') {
|
|
80
|
+
return {
|
|
81
|
+
title: 'Connect GitHub Copilot account',
|
|
82
|
+
body: [
|
|
83
|
+
'Yagr runs a native GitHub device login and exchanges it for a Copilot runtime token.',
|
|
84
|
+
'It will show a verification URL and code in the terminal.',
|
|
85
|
+
],
|
|
86
|
+
continueLabel: 'Continue with GitHub sign-in',
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
title: `Connect ${getProviderDisplayName(provider)}`,
|
|
91
|
+
body: ['Yagr will verify your account session before loading models.'],
|
|
92
|
+
continueLabel: 'Continue',
|
|
93
|
+
};
|
|
94
|
+
}
|
|
36
95
|
// ─── Primitive UI components ──────────────────────────────────────────────────
|
|
37
96
|
function Rule() {
|
|
38
97
|
return _jsx(Text, { dimColor: true, children: '─'.repeat(56) });
|
|
39
98
|
}
|
|
40
|
-
function Header({ phase }) {
|
|
99
|
+
function Header({ phase, mode }) {
|
|
41
100
|
const section = sectionFor(phase);
|
|
42
101
|
const idx = sectionIndex(phase);
|
|
43
102
|
const isDone = phase.kind === 'done' || phase.kind === 'cancelled' || phase.kind === 'error';
|
|
44
|
-
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { color: "cyan", bold: true, children: "\u25C8 Yagr Setup" }), !isDone && (_jsx(Text, { dimColor: true, children:
|
|
103
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { color: "cyan", bold: true, children: "\u25C8 Yagr Setup" }), !isDone && (_jsx(Text, { dimColor: true, children: mode === 'llm-only'
|
|
104
|
+
? '● step 1 / 1'
|
|
105
|
+
: `${idx === 1 ? '●' : '○'}${idx === 2 ? '●' : '○'}${idx === 3 ? '●' : '○'} step ${idx} / 3` }))] }), section ? (_jsx(Text, { color: "cyan", dimColor: true, children: section })) : null, _jsx(Rule, {})] }));
|
|
45
106
|
}
|
|
46
107
|
function HintBar({ hints }) {
|
|
47
108
|
return (_jsxs(Box, { marginTop: 1, children: [_jsx(Rule, {}), _jsx(Box, { children: hints.map((hint, i) => (_jsxs(Text, { dimColor: true, children: [hint, i < hints.length - 1 ? ' ' : ''] }, i))) })] }));
|
|
@@ -165,11 +226,16 @@ function SelectList({ options, cursor, getLabel, getHint, maxVisibleRows, maxLin
|
|
|
165
226
|
const active = i === cursor;
|
|
166
227
|
const hint = getHint?.(opt);
|
|
167
228
|
const prefix = active ? ` ${CURSOR} ` : ' ';
|
|
168
|
-
const
|
|
169
|
-
const line = truncateTerminalLine(`${prefix}${getLabel(opt)}${suffix}`, availableWidth);
|
|
229
|
+
const line = truncateTerminalLine(formatOptionLineWithHint(prefix, getLabel(opt), hint, availableWidth), availableWidth);
|
|
170
230
|
return (_jsx(Box, { children: _jsx(Text, { color: active ? 'cyan' : undefined, bold: active, children: line }) }, i));
|
|
171
231
|
}), end < options.length ? _jsx(Text, { dimColor: true, children: truncateTerminalLine(` ↓ ${options.length - end} more`, availableWidth) }) : null] }));
|
|
172
232
|
}
|
|
233
|
+
function formatOptionLineWithHint(prefix, label, hint, width) {
|
|
234
|
+
if (!hint) {
|
|
235
|
+
return `${prefix}${label}`;
|
|
236
|
+
}
|
|
237
|
+
return `${prefix}${label} ${DOT} ${hint}`;
|
|
238
|
+
}
|
|
173
239
|
function MultiSelectList({ options, cursor, selected, maxVisibleRows, maxLineWidth, }) {
|
|
174
240
|
const visibleRows = Math.max(1, maxVisibleRows ?? options.length);
|
|
175
241
|
const { start, end } = getVisibleWindow(options.length, cursor, visibleRows);
|
|
@@ -186,21 +252,41 @@ function MultiSelectList({ options, cursor, selected, maxVisibleRows, maxLineWid
|
|
|
186
252
|
}), end < options.length ? _jsx(Text, { dimColor: true, children: truncateTerminalLine(` ↓ ${options.length - end} more`, availableWidth) }) : null] }));
|
|
187
253
|
}
|
|
188
254
|
// ─── Main wizard component ────────────────────────────────────────────────────
|
|
189
|
-
function SetupWizard({ callbacks, onDone }) {
|
|
255
|
+
function SetupWizard({ callbacks, options, onDone }) {
|
|
190
256
|
const app = useApp();
|
|
191
257
|
const { stdout } = useStdout();
|
|
192
258
|
const n8nDef = callbacks.getN8nDefaults();
|
|
193
259
|
const llmDef = callbacks.getLlmDefaults();
|
|
194
260
|
const surfDef = callbacks.getSurfaceDefaults();
|
|
195
|
-
const
|
|
196
|
-
const [
|
|
261
|
+
const mode = options?.mode ?? 'full';
|
|
262
|
+
const [phase, setPhase] = useState(() => {
|
|
263
|
+
if (mode === 'llm-only') {
|
|
264
|
+
const llmProvider = llmDef.provider;
|
|
265
|
+
if (llmProvider) {
|
|
266
|
+
const existingApiKey = llmDef.getApiKey(llmProvider);
|
|
267
|
+
const existingModel = llmDef.getDefaultModel(llmProvider);
|
|
268
|
+
if (existingModel && (existingApiKey || !providerRequiresApiKey(llmProvider))) {
|
|
269
|
+
return { kind: 'llm-reuse-config', provider: llmProvider, apiKey: existingApiKey ?? '', model: existingModel, cursor: 0 };
|
|
270
|
+
}
|
|
271
|
+
return {
|
|
272
|
+
kind: 'llm-provider',
|
|
273
|
+
initial: llmProvider,
|
|
274
|
+
cursor: Math.max(0, VALID_PROVIDERS.indexOf(llmProvider)),
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
return { kind: 'llm-provider', cursor: 0 };
|
|
278
|
+
}
|
|
279
|
+
return { kind: 'n8n-mode', cursor: 0 };
|
|
280
|
+
});
|
|
281
|
+
const [textValue, setTextValue] = useState('');
|
|
197
282
|
const [spinnerFrame, setSpinnerFrame] = useState(0);
|
|
198
283
|
const asyncGuard = useRef(0);
|
|
199
284
|
const llmApiKeyDraftsRef = useRef({});
|
|
285
|
+
const llmBaseUrlDraftsRef = useRef({});
|
|
200
286
|
const terminalRows = stdout?.rows ?? process.stdout.rows ?? 24;
|
|
201
287
|
const terminalColumns = stdout?.columns ?? process.stdout.columns ?? 80;
|
|
202
288
|
const listLineWidth = Math.max(12, terminalColumns - 6);
|
|
203
|
-
const isLoading = phase.kind === 'n8n-connecting' || phase.kind === 'n8n-saving'
|
|
289
|
+
const isLoading = phase.kind === 'n8n-connecting' || phase.kind === 'n8n-saving' || phase.kind === 'n8n-local-installing'
|
|
204
290
|
|| phase.kind === 'llm-models-loading' || phase.kind === 'telegram-connecting';
|
|
205
291
|
useEffect(() => {
|
|
206
292
|
if (!isLoading)
|
|
@@ -217,6 +303,45 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
217
303
|
cancel('Setup cancelled.');
|
|
218
304
|
}
|
|
219
305
|
});
|
|
306
|
+
useEffect(() => {
|
|
307
|
+
if (phase.kind !== 'n8n-local-installing')
|
|
308
|
+
return;
|
|
309
|
+
const guard = ++asyncGuard.current;
|
|
310
|
+
void (async () => {
|
|
311
|
+
try {
|
|
312
|
+
const state = await callbacks.installManagedLocalN8n(phase.strategy);
|
|
313
|
+
if (guard !== asyncGuard.current)
|
|
314
|
+
return;
|
|
315
|
+
const bootstrap = await callbacks.bootstrapManagedLocalN8n(state.url);
|
|
316
|
+
if (guard !== asyncGuard.current)
|
|
317
|
+
return;
|
|
318
|
+
if (bootstrap.mode === 'silent' && bootstrap.apiKey) {
|
|
319
|
+
setPhase({ kind: 'n8n-connecting', url: state.url, apiKey: bootstrap.apiKey, runtimeSource: 'managed-local' });
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
const existing = callbacks.getN8nDefaults(state.url).apiKey;
|
|
323
|
+
if (existing) {
|
|
324
|
+
setPhase({ kind: 'n8n-connecting', url: state.url, apiKey: existing, runtimeSource: 'managed-local' });
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
setPhase({
|
|
328
|
+
kind: 'n8n-local-ready',
|
|
329
|
+
url: state.url,
|
|
330
|
+
cursor: 0,
|
|
331
|
+
note: bootstrap.reason ? `Silent bootstrap fallback: ${bootstrap.reason}` : undefined,
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
catch (err) {
|
|
335
|
+
if (guard !== asyncGuard.current)
|
|
336
|
+
return;
|
|
337
|
+
setPhase({
|
|
338
|
+
kind: 'n8n-mode',
|
|
339
|
+
cursor: phase.strategy === 'docker' ? 0 : 1,
|
|
340
|
+
err: err instanceof Error ? err.message : String(err),
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
})();
|
|
344
|
+
}, [phase.kind]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
220
345
|
useEffect(() => {
|
|
221
346
|
if (phase.kind !== 'n8n-connecting')
|
|
222
347
|
return;
|
|
@@ -229,14 +354,14 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
229
354
|
if (projects.length === 1) {
|
|
230
355
|
setPhase({
|
|
231
356
|
kind: 'n8n-syncfolder',
|
|
232
|
-
url: phase.url, apiKey: phase.apiKey,
|
|
357
|
+
url: phase.url, apiKey: phase.apiKey, runtimeSource: phase.runtimeSource,
|
|
233
358
|
project: projects[0],
|
|
234
359
|
def: n8nDef.syncFolder ?? 'workflows',
|
|
235
360
|
});
|
|
236
361
|
setTextValue(n8nDef.syncFolder ?? 'workflows');
|
|
237
362
|
}
|
|
238
363
|
else {
|
|
239
|
-
setPhase({ kind: 'n8n-project', url: phase.url, apiKey: phase.apiKey, projects, cursor: 0 });
|
|
364
|
+
setPhase({ kind: 'n8n-project', url: phase.url, apiKey: phase.apiKey, runtimeSource: phase.runtimeSource, projects, cursor: 0 });
|
|
240
365
|
}
|
|
241
366
|
}
|
|
242
367
|
catch (err) {
|
|
@@ -253,15 +378,15 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
253
378
|
const guard = ++asyncGuard.current;
|
|
254
379
|
void (async () => {
|
|
255
380
|
try {
|
|
256
|
-
await callbacks.saveN8nConfig({ url: phase.url, apiKey: phase.apiKey, project: phase.project, syncFolder: phase.syncFolder });
|
|
381
|
+
await callbacks.saveN8nConfig({ url: phase.url, apiKey: phase.apiKey, project: phase.project, syncFolder: phase.syncFolder, runtimeSource: phase.runtimeSource });
|
|
257
382
|
if (guard !== asyncGuard.current)
|
|
258
383
|
return;
|
|
259
384
|
const llmProvider = llmDef.provider;
|
|
260
385
|
if (llmProvider) {
|
|
261
386
|
const existingApiKey = llmDef.getApiKey(llmProvider);
|
|
262
387
|
const existingModel = llmDef.getDefaultModel(llmProvider);
|
|
263
|
-
if (
|
|
264
|
-
setPhase({ kind: 'llm-reuse-config', provider: llmProvider, apiKey: existingApiKey, model: existingModel, cursor: 0 });
|
|
388
|
+
if (existingModel && (existingApiKey || !providerRequiresApiKey(llmProvider))) {
|
|
389
|
+
setPhase({ kind: 'llm-reuse-config', provider: llmProvider, apiKey: existingApiKey ?? '', model: existingModel, cursor: 0 });
|
|
265
390
|
return;
|
|
266
391
|
}
|
|
267
392
|
}
|
|
@@ -281,16 +406,56 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
281
406
|
const guard = ++asyncGuard.current;
|
|
282
407
|
void (async () => {
|
|
283
408
|
try {
|
|
284
|
-
|
|
409
|
+
let models = [];
|
|
410
|
+
let resolvedApiKey = phase.apiKey;
|
|
411
|
+
let note = phase.note;
|
|
412
|
+
const prepared = await callbacks.prepareProvider(phase.provider, phase.apiKey || undefined);
|
|
413
|
+
if (guard !== asyncGuard.current)
|
|
414
|
+
return;
|
|
415
|
+
if (prepared.ready) {
|
|
416
|
+
if (prepared.baseUrl) {
|
|
417
|
+
llmBaseUrlDraftsRef.current[phase.provider] = prepared.baseUrl;
|
|
418
|
+
}
|
|
419
|
+
if (prepared.apiKey !== undefined) {
|
|
420
|
+
resolvedApiKey = prepared.apiKey;
|
|
421
|
+
llmApiKeyDraftsRef.current[phase.provider] = prepared.apiKey;
|
|
422
|
+
}
|
|
423
|
+
if (prepared.notes && prepared.notes.length > 0) {
|
|
424
|
+
note = prepared.notes.join(' ');
|
|
425
|
+
}
|
|
426
|
+
models = prepared.models ?? [];
|
|
427
|
+
}
|
|
428
|
+
else if (isOAuthAccountProvider(phase.provider)) {
|
|
429
|
+
const preparedError = prepared.error?.toLowerCase() ?? '';
|
|
430
|
+
if (preparedError.includes('insufficient authentication scopes') || preparedError.includes('http 403')) {
|
|
431
|
+
setTextValue('');
|
|
432
|
+
setPhase({ kind: 'llm-account-auth', provider: phase.provider, cursor: 0 });
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
setPhase({
|
|
436
|
+
kind: 'llm-model',
|
|
437
|
+
provider: phase.provider,
|
|
438
|
+
apiKey: phase.apiKey,
|
|
439
|
+
models: [],
|
|
440
|
+
defModel: phase.defModel,
|
|
441
|
+
cursor: 0,
|
|
442
|
+
note: prepared.error || note,
|
|
443
|
+
});
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
if (models.length === 0) {
|
|
447
|
+
models = await callbacks.fetchModels(phase.provider, resolvedApiKey || undefined);
|
|
448
|
+
}
|
|
285
449
|
if (guard !== asyncGuard.current)
|
|
286
450
|
return;
|
|
287
451
|
const displayedOptions = getDisplayedModelOptions(models);
|
|
288
452
|
const idx = phase.defModel ? displayedOptions.indexOf(phase.defModel) : -1;
|
|
289
453
|
setPhase({
|
|
290
454
|
kind: 'llm-model',
|
|
291
|
-
provider: phase.provider, apiKey:
|
|
455
|
+
provider: phase.provider, apiKey: resolvedApiKey,
|
|
292
456
|
models, defModel: phase.defModel,
|
|
293
457
|
cursor: idx >= 0 ? idx : 0,
|
|
458
|
+
note,
|
|
294
459
|
});
|
|
295
460
|
}
|
|
296
461
|
catch {
|
|
@@ -299,7 +464,7 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
299
464
|
setPhase({
|
|
300
465
|
kind: 'llm-model',
|
|
301
466
|
provider: phase.provider, apiKey: phase.apiKey,
|
|
302
|
-
models: [], defModel: phase.defModel, cursor: 0,
|
|
467
|
+
models: [], defModel: phase.defModel, cursor: 0, note: phase.note,
|
|
303
468
|
});
|
|
304
469
|
}
|
|
305
470
|
})();
|
|
@@ -357,26 +522,16 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
357
522
|
setPhase((p) => ({ ...p, err: 'API key is required.' }));
|
|
358
523
|
return;
|
|
359
524
|
}
|
|
360
|
-
setPhase({ kind: 'n8n-connecting', url, apiKey: key });
|
|
525
|
+
setPhase({ kind: 'n8n-connecting', url, apiKey: key, runtimeSource: 'external' });
|
|
361
526
|
}, []);
|
|
362
|
-
const handleSyncFolderSubmit = useCallback((url, apiKey, project) => (value) => {
|
|
527
|
+
const handleSyncFolderSubmit = useCallback((url, apiKey, runtimeSource, project) => (value) => {
|
|
363
528
|
const folder = value.trim();
|
|
364
529
|
if (!folder) {
|
|
365
530
|
setPhase((p) => ({ ...p, err: 'Sync folder is required.' }));
|
|
366
531
|
return;
|
|
367
532
|
}
|
|
368
|
-
setPhase({ kind: 'n8n-saving', url, apiKey, project, syncFolder: folder });
|
|
533
|
+
setPhase({ kind: 'n8n-saving', url, apiKey, runtimeSource, project, syncFolder: folder });
|
|
369
534
|
}, []);
|
|
370
|
-
const handleLlmApiKeySubmit = useCallback((provider) => (value) => {
|
|
371
|
-
const key = value.trim();
|
|
372
|
-
if (!key) {
|
|
373
|
-
setPhase((p) => ({ ...p, err: 'API key is required.' }));
|
|
374
|
-
return;
|
|
375
|
-
}
|
|
376
|
-
llmApiKeyDraftsRef.current[provider] = key;
|
|
377
|
-
const defModel = llmDef.getDefaultModel(provider);
|
|
378
|
-
setPhase({ kind: 'llm-models-loading', provider, apiKey: key, defModel });
|
|
379
|
-
}, [llmDef]);
|
|
380
535
|
const handleBaseUrlSubmit = useCallback((provider, apiKey, model) => (value) => {
|
|
381
536
|
const url = value.trim();
|
|
382
537
|
if (url) {
|
|
@@ -400,15 +555,125 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
400
555
|
}
|
|
401
556
|
setPhase({ kind: 'telegram-connecting', surfaces, token });
|
|
402
557
|
}, []);
|
|
558
|
+
const transitionToLlmModelsLoading = useCallback((provider, apiKey, defModel, note) => {
|
|
559
|
+
setTextValue('');
|
|
560
|
+
setPhase({
|
|
561
|
+
kind: 'llm-models-loading',
|
|
562
|
+
provider,
|
|
563
|
+
apiKey,
|
|
564
|
+
defModel,
|
|
565
|
+
...(note ? { note } : {}),
|
|
566
|
+
});
|
|
567
|
+
}, []);
|
|
568
|
+
const handleLlmApiKeySubmit = useCallback((provider) => (value) => {
|
|
569
|
+
const key = value.trim();
|
|
570
|
+
if (!key && providerRequiresApiKey(provider)) {
|
|
571
|
+
setPhase((p) => ({ ...p, err: 'API key is required.' }));
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
llmApiKeyDraftsRef.current[provider] = key;
|
|
575
|
+
const defModel = llmDef.getDefaultModel(provider);
|
|
576
|
+
transitionToLlmModelsLoading(provider, key, defModel);
|
|
577
|
+
}, [llmDef, transitionToLlmModelsLoading]);
|
|
578
|
+
const handleAccountAuthSubmit = useCallback((provider, state) => (value) => {
|
|
579
|
+
void (async () => {
|
|
580
|
+
try {
|
|
581
|
+
const result = await callbacks.completeAccountAuth(provider, value, state);
|
|
582
|
+
if (!result.ok) {
|
|
583
|
+
setPhase((current) => current.kind === 'llm-account-input'
|
|
584
|
+
? { ...current, err: result.error || 'Authentication failed.' }
|
|
585
|
+
: current);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
const defModel = llmDef.getDefaultModel(provider);
|
|
589
|
+
transitionToLlmModelsLoading(provider, result.apiKey ?? '', defModel);
|
|
590
|
+
}
|
|
591
|
+
catch (error) {
|
|
592
|
+
setPhase((current) => current.kind === 'llm-account-input'
|
|
593
|
+
? { ...current, err: error instanceof Error ? error.message : String(error) }
|
|
594
|
+
: current);
|
|
595
|
+
}
|
|
596
|
+
})();
|
|
597
|
+
}, [callbacks, llmDef, transitionToLlmModelsLoading]);
|
|
598
|
+
const saveLlmAndContinue = useCallback((provider, apiKey, model, note) => {
|
|
599
|
+
const draftedBaseUrl = llmBaseUrlDraftsRef.current[provider];
|
|
600
|
+
callbacks.saveLlmConfig({ provider, apiKey, model, baseUrl: draftedBaseUrl || undefined });
|
|
601
|
+
setTextValue('');
|
|
602
|
+
if (mode === 'llm-only') {
|
|
603
|
+
setPhase({ kind: 'done', n8nHost: '', n8nProject: '', provider, model, surfaces: surfDef.surfaces });
|
|
604
|
+
setTimeout(() => { onDone({ ok: true }); app.exit(); }, 250);
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
setPhase({ kind: 'surfaces', cursor: 0, selected: surfDef.surfaces });
|
|
608
|
+
}, [app, callbacks, mode, onDone, surfDef]);
|
|
403
609
|
const handleSelectKey = useCallback((input, key) => {
|
|
404
|
-
if (phase.kind === 'n8n-
|
|
610
|
+
if (phase.kind === 'n8n-mode') {
|
|
611
|
+
if (key.upArrow)
|
|
612
|
+
setPhase({ ...phase, cursor: Math.max(0, phase.cursor - 1), err: undefined });
|
|
613
|
+
else if (key.downArrow)
|
|
614
|
+
setPhase({ ...phase, cursor: Math.min(2, phase.cursor + 1), err: undefined });
|
|
615
|
+
else if (key.return) {
|
|
616
|
+
if (phase.cursor === 0) {
|
|
617
|
+
setPhase({ kind: 'n8n-local-installing', startedAt: Date.now(), strategy: 'docker' });
|
|
618
|
+
}
|
|
619
|
+
else if (phase.cursor === 1) {
|
|
620
|
+
setPhase({ kind: 'n8n-local-installing', startedAt: Date.now(), strategy: 'direct' });
|
|
621
|
+
}
|
|
622
|
+
else {
|
|
623
|
+
setPhase({ kind: 'n8n-url', def: n8nDef.url });
|
|
624
|
+
setTextValue(n8nDef.url);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
else if (key.escape)
|
|
628
|
+
cancel('Setup cancelled.');
|
|
629
|
+
}
|
|
630
|
+
else if (phase.kind === 'n8n-local-ready') {
|
|
631
|
+
if (key.upArrow)
|
|
632
|
+
setPhase({ ...phase, cursor: Math.max(0, phase.cursor - 1) });
|
|
633
|
+
else if (key.downArrow)
|
|
634
|
+
setPhase({ ...phase, cursor: Math.min(1, phase.cursor + 1) });
|
|
635
|
+
else if (key.return) {
|
|
636
|
+
if (phase.cursor === 0) {
|
|
637
|
+
void (async () => {
|
|
638
|
+
try {
|
|
639
|
+
await callbacks.openUrl(phase.url);
|
|
640
|
+
}
|
|
641
|
+
catch {
|
|
642
|
+
// Leave the flow available even if browser opening fails.
|
|
643
|
+
}
|
|
644
|
+
const existing = callbacks.getN8nDefaults(phase.url).apiKey;
|
|
645
|
+
if (existing) {
|
|
646
|
+
setPhase({ kind: 'n8n-connecting', url: phase.url, apiKey: existing, runtimeSource: 'managed-local' });
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
setPhase({
|
|
650
|
+
kind: 'n8n-local-auth',
|
|
651
|
+
url: phase.url,
|
|
652
|
+
message: 'The local n8n editor is ready. Create the owner account, then open Settings > n8n API, generate a key for Yagr, and paste it here.',
|
|
653
|
+
});
|
|
654
|
+
setTextValue('');
|
|
655
|
+
})();
|
|
656
|
+
}
|
|
657
|
+
else {
|
|
658
|
+
setPhase({
|
|
659
|
+
kind: 'n8n-local-auth',
|
|
660
|
+
url: phase.url,
|
|
661
|
+
message: 'Open the local n8n URL in your browser, create the owner account, then generate a key in Settings > n8n API and paste it here.',
|
|
662
|
+
});
|
|
663
|
+
setTextValue('');
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
else if (key.escape)
|
|
667
|
+
cancel('Setup cancelled.');
|
|
668
|
+
}
|
|
669
|
+
else if (phase.kind === 'n8n-reuse-apikey') {
|
|
405
670
|
if (key.upArrow)
|
|
406
671
|
setPhase({ ...phase, cursor: Math.max(0, phase.cursor - 1) });
|
|
407
672
|
else if (key.downArrow)
|
|
408
673
|
setPhase({ ...phase, cursor: Math.min(1, phase.cursor + 1) });
|
|
409
674
|
else if (key.return) {
|
|
410
675
|
if (phase.cursor === 0) {
|
|
411
|
-
setPhase({ kind: 'n8n-connecting', url: phase.url, apiKey: phase.existing });
|
|
676
|
+
setPhase({ kind: 'n8n-connecting', url: phase.url, apiKey: phase.existing, runtimeSource: 'external' });
|
|
412
677
|
}
|
|
413
678
|
else {
|
|
414
679
|
setPhase({ kind: 'n8n-apikey', url: phase.url });
|
|
@@ -425,7 +690,7 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
425
690
|
setPhase({ ...phase, cursor: Math.min(phase.projects.length - 1, phase.cursor + 1) });
|
|
426
691
|
else if (key.return) {
|
|
427
692
|
const project = phase.projects[phase.cursor];
|
|
428
|
-
setPhase({ kind: 'n8n-syncfolder', url: phase.url, apiKey: phase.apiKey, project, def: n8nDef.syncFolder ?? 'workflows' });
|
|
693
|
+
setPhase({ kind: 'n8n-syncfolder', url: phase.url, apiKey: phase.apiKey, runtimeSource: phase.runtimeSource, project, def: n8nDef.syncFolder ?? 'workflows' });
|
|
429
694
|
setTextValue(n8nDef.syncFolder ?? 'workflows');
|
|
430
695
|
}
|
|
431
696
|
else if (key.escape)
|
|
@@ -439,10 +704,13 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
439
704
|
else if (key.return) {
|
|
440
705
|
if (phase.cursor === 0) {
|
|
441
706
|
llmApiKeyDraftsRef.current[phase.provider] = phase.apiKey;
|
|
442
|
-
|
|
707
|
+
const draftedBaseUrl = llmBaseUrlDraftsRef.current[phase.provider] ?? llmDef.getBaseUrl(phase.provider);
|
|
708
|
+
callbacks.saveLlmConfig({ provider: phase.provider, apiKey: phase.apiKey, model: phase.model, baseUrl: draftedBaseUrl });
|
|
709
|
+
setTextValue('');
|
|
443
710
|
setPhase({ kind: 'surfaces', cursor: 0, selected: surfDef.surfaces });
|
|
444
711
|
}
|
|
445
712
|
else {
|
|
713
|
+
setTextValue('');
|
|
446
714
|
setPhase({ kind: 'llm-provider', initial: phase.provider, cursor: VALID_PROVIDERS.indexOf(phase.provider) });
|
|
447
715
|
}
|
|
448
716
|
}
|
|
@@ -457,7 +725,16 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
457
725
|
else if (key.return) {
|
|
458
726
|
const provider = VALID_PROVIDERS[phase.cursor];
|
|
459
727
|
const existing = llmApiKeyDraftsRef.current[provider] ?? llmDef.getApiKey(provider);
|
|
460
|
-
if (
|
|
728
|
+
if (isOAuthAccountProvider(provider)) {
|
|
729
|
+
setTextValue('');
|
|
730
|
+
setPhase({ kind: 'llm-account-auth', provider, cursor: 0 });
|
|
731
|
+
}
|
|
732
|
+
else if (!providerRequiresApiKey(provider)) {
|
|
733
|
+
const defModel = llmDef.getDefaultModel(provider);
|
|
734
|
+
transitionToLlmModelsLoading(provider, existing ?? '', defModel);
|
|
735
|
+
}
|
|
736
|
+
else if (existing) {
|
|
737
|
+
setTextValue('');
|
|
461
738
|
setPhase({ kind: 'llm-reuse-apikey', provider, existing, cursor: 0 });
|
|
462
739
|
}
|
|
463
740
|
else {
|
|
@@ -468,6 +745,81 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
468
745
|
else if (key.escape)
|
|
469
746
|
cancel('Setup cancelled.');
|
|
470
747
|
}
|
|
748
|
+
else if (phase.kind === 'llm-account-auth') {
|
|
749
|
+
const maxCursor = 1;
|
|
750
|
+
if (key.upArrow)
|
|
751
|
+
setPhase({ ...phase, cursor: Math.max(0, phase.cursor - 1) });
|
|
752
|
+
else if (key.downArrow)
|
|
753
|
+
setPhase({ ...phase, cursor: Math.min(maxCursor, phase.cursor + 1) });
|
|
754
|
+
else if (key.return) {
|
|
755
|
+
if (phase.provider === 'anthropic-proxy' && phase.cursor === 0) {
|
|
756
|
+
setPhase({
|
|
757
|
+
kind: 'llm-account-input',
|
|
758
|
+
provider: 'anthropic-proxy',
|
|
759
|
+
title: 'Claude setup-token',
|
|
760
|
+
instructions: [
|
|
761
|
+
'On a machine where Claude CLI is installed and logged in, run:',
|
|
762
|
+
'claude setup-token',
|
|
763
|
+
'Copy the generated setup-token and paste it below.',
|
|
764
|
+
],
|
|
765
|
+
placeholder: 'Paste setup-token',
|
|
766
|
+
submitLabel: 'Continue with setup-token',
|
|
767
|
+
state: 'anthropic:setup-token',
|
|
768
|
+
});
|
|
769
|
+
setTextValue('');
|
|
770
|
+
}
|
|
771
|
+
else if (phase.cursor === 0) {
|
|
772
|
+
void (async () => {
|
|
773
|
+
try {
|
|
774
|
+
const authStep = await callbacks.startAccountAuth(phase.provider);
|
|
775
|
+
const authUrl = (authStep.instructions ?? [])
|
|
776
|
+
.map((line) => line.match(/https?:\/\/\S+/)?.[0])
|
|
777
|
+
.find(Boolean);
|
|
778
|
+
if (authUrl) {
|
|
779
|
+
void callbacks.openUrl(authUrl).catch(() => {
|
|
780
|
+
// Browser auto-open is best effort only.
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
if (authStep.kind === 'input') {
|
|
784
|
+
setPhase({
|
|
785
|
+
kind: 'llm-account-input',
|
|
786
|
+
provider: phase.provider,
|
|
787
|
+
title: authStep.title ?? getProviderAuthCopy(phase.provider).title,
|
|
788
|
+
instructions: authStep.instructions ?? [],
|
|
789
|
+
placeholder: authStep.placeholder,
|
|
790
|
+
submitLabel: authStep.submitLabel ?? 'Continue',
|
|
791
|
+
state: authStep.state,
|
|
792
|
+
});
|
|
793
|
+
setTextValue('');
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
796
|
+
const defModel = llmDef.getDefaultModel(phase.provider);
|
|
797
|
+
const authCopy = getProviderAuthCopy(phase.provider);
|
|
798
|
+
transitionToLlmModelsLoading(phase.provider, '', defModel, authCopy.body.join(' '));
|
|
799
|
+
}
|
|
800
|
+
catch (error) {
|
|
801
|
+
setPhase({
|
|
802
|
+
kind: 'llm-account-input',
|
|
803
|
+
provider: phase.provider,
|
|
804
|
+
title: getProviderAuthCopy(phase.provider).title,
|
|
805
|
+
instructions: getProviderAuthCopy(phase.provider).body,
|
|
806
|
+
submitLabel: 'Continue',
|
|
807
|
+
err: error instanceof Error ? error.message : String(error),
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
})();
|
|
811
|
+
}
|
|
812
|
+
else {
|
|
813
|
+
setPhase({ kind: 'llm-provider', initial: phase.provider, cursor: VALID_PROVIDERS.indexOf(phase.provider) });
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
else if (key.escape)
|
|
817
|
+
cancel('Setup cancelled.');
|
|
818
|
+
}
|
|
819
|
+
else if (phase.kind === 'llm-account-input') {
|
|
820
|
+
if (key.escape)
|
|
821
|
+
cancel('Setup cancelled.');
|
|
822
|
+
}
|
|
471
823
|
else if (phase.kind === 'llm-reuse-apikey') {
|
|
472
824
|
if (key.upArrow)
|
|
473
825
|
setPhase({ ...phase, cursor: Math.max(0, phase.cursor - 1) });
|
|
@@ -477,7 +829,7 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
477
829
|
if (phase.cursor === 0) {
|
|
478
830
|
const defModel = llmDef.getDefaultModel(phase.provider);
|
|
479
831
|
llmApiKeyDraftsRef.current[phase.provider] = phase.existing;
|
|
480
|
-
|
|
832
|
+
transitionToLlmModelsLoading(phase.provider, phase.existing, defModel);
|
|
481
833
|
}
|
|
482
834
|
else {
|
|
483
835
|
setPhase({ kind: 'llm-apikey', provider: phase.provider });
|
|
@@ -501,14 +853,18 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
501
853
|
return;
|
|
502
854
|
}
|
|
503
855
|
const model = selected;
|
|
856
|
+
const draftedBaseUrl = llmBaseUrlDraftsRef.current[phase.provider];
|
|
857
|
+
const defaultBaseUrl = draftedBaseUrl ?? llmDef.getBaseUrl(phase.provider);
|
|
504
858
|
const needsUrl = llmDef.needsBaseUrl(phase.provider);
|
|
505
|
-
if (
|
|
506
|
-
|
|
507
|
-
|
|
859
|
+
if (draftedBaseUrl) {
|
|
860
|
+
saveLlmAndContinue(phase.provider, phase.apiKey, model, phase.note);
|
|
861
|
+
}
|
|
862
|
+
else if (needsUrl || defaultBaseUrl) {
|
|
863
|
+
setPhase({ kind: 'llm-baseurl', provider: phase.provider, apiKey: phase.apiKey, model, def: defaultBaseUrl ?? '' });
|
|
864
|
+
setTextValue(defaultBaseUrl ?? '');
|
|
508
865
|
}
|
|
509
866
|
else {
|
|
510
|
-
|
|
511
|
-
setPhase({ kind: 'surfaces', cursor: 0, selected: surfDef.surfaces });
|
|
867
|
+
saveLlmAndContinue(phase.provider, phase.apiKey, model, phase.note);
|
|
512
868
|
}
|
|
513
869
|
}
|
|
514
870
|
else if (key.escape)
|
|
@@ -568,7 +924,7 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
568
924
|
cancel('Setup cancelled.');
|
|
569
925
|
}
|
|
570
926
|
}, [phase, cancel, callbacks, llmDef, surfDef, n8nDef.syncFolder, app, onDone]);
|
|
571
|
-
const isSelectPhase = ['n8n-reuse-apikey', 'n8n-project', 'llm-provider', 'llm-reuse-config', 'llm-reuse-apikey', 'surfaces', 'telegram-reuse-token'].includes(phase.kind)
|
|
927
|
+
const isSelectPhase = ['n8n-mode', 'n8n-local-ready', 'n8n-reuse-apikey', 'n8n-project', 'llm-provider', 'llm-account-auth', 'llm-reuse-config', 'llm-reuse-apikey', 'surfaces', 'telegram-reuse-token'].includes(phase.kind)
|
|
572
928
|
|| (phase.kind === 'llm-model' && phase.models.length > 0);
|
|
573
929
|
useInput((input, key) => {
|
|
574
930
|
if (key.ctrl && input === 'c')
|
|
@@ -576,9 +932,23 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
576
932
|
if (isSelectPhase)
|
|
577
933
|
handleSelectKey(input, key);
|
|
578
934
|
}, { isActive: isSelectPhase });
|
|
579
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsx(Header, { phase: phase }), renderPhase()] }));
|
|
935
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsx(Header, { phase: phase, mode: mode }), renderPhase()] }));
|
|
580
936
|
function renderPhase() {
|
|
581
937
|
switch (phase.kind) {
|
|
938
|
+
case 'n8n-mode':
|
|
939
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: "n8n setup path" }), _jsx(Text, { dimColor: true, children: " Choose the lowest-friction way to connect Yagr to n8n." }), _jsx(SelectList, { options: [
|
|
940
|
+
'Install a Yagr-managed n8n with Docker',
|
|
941
|
+
'Install a Yagr-managed local n8n',
|
|
942
|
+
'Use an existing n8n instance and API key',
|
|
943
|
+
], cursor: phase.cursor, getLabel: (v) => v, getHint: (v) => {
|
|
944
|
+
if (v === 'Install a Yagr-managed n8n with Docker') {
|
|
945
|
+
return 'Recommended if Docker is installed and running';
|
|
946
|
+
}
|
|
947
|
+
if (v === 'Install a Yagr-managed local n8n') {
|
|
948
|
+
return 'Managed local runtime without Docker';
|
|
949
|
+
}
|
|
950
|
+
return 'Cloud or self-managed n8n';
|
|
951
|
+
}, maxVisibleRows: getListViewportHeight(terminalRows, 13), maxLineWidth: listLineWidth }), phase.err ? _jsx(ErrorLine, { message: phase.err }) : null, _jsx(HintBar, { hints: ['↑↓ move', 'Enter ↵ confirm', 'Ctrl+C cancel'] })] }));
|
|
582
952
|
case 'n8n-url':
|
|
583
953
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: "Instance URL" }), _jsx(Box, { marginLeft: 2, children: _jsx(WizardTextInput, { value: textValue, onChange: setTextValue, onSubmit: handleN8nUrlSubmit, placeholder: "https://your-n8n.example.com" }) }), phase.err ? _jsx(ErrorLine, { message: phase.err }) : null, _jsx(HintBar, { hints: ['Enter ↵ confirm', 'Ctrl+C cancel'] })] }));
|
|
584
954
|
case 'n8n-reuse-apikey':
|
|
@@ -587,44 +957,82 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
587
957
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: "n8n API key" }), _jsx(Box, { marginLeft: 2, children: _jsx(WizardTextInput, { value: textValue, onChange: setTextValue, onSubmit: handleN8nApiKeySubmit(phase.url), mask: "\u25CF", placeholder: "your-api-key" }) }), phase.err ? _jsx(ErrorLine, { message: phase.err }) : null, _jsx(HintBar, { hints: ['Enter ↵ confirm', 'Ctrl+C cancel'] })] }));
|
|
588
958
|
case 'n8n-connecting':
|
|
589
959
|
return (_jsx(Box, { flexDirection: "column", children: _jsx(SpinnerDisplay, { message: `Connecting to ${phase.url}…`, frame: spinnerFrame }) }));
|
|
960
|
+
case 'n8n-local-installing':
|
|
961
|
+
{
|
|
962
|
+
const elapsedSeconds = Math.max(0, Math.round((Date.now() - phase.startedAt) / 1000));
|
|
963
|
+
const elapsedLabel = elapsedSeconds < 60
|
|
964
|
+
? `${elapsedSeconds}s`
|
|
965
|
+
: `${Math.floor(elapsedSeconds / 60)}m ${String(elapsedSeconds % 60).padStart(2, '0')}s`;
|
|
966
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(SpinnerDisplay, { message: "Installing and starting a Yagr-managed local n8n instance\u2026", frame: spinnerFrame }), _jsx(Text, { dimColor: true, children: " Yagr is waiting for the n8n API and editor to become ready before continuing." }), _jsx(Text, { dimColor: true, children: " First run can take 1 to 3 minutes depending on Docker, npm downloads, and machine speed." }), _jsxs(Text, { dimColor: true, children: [" Elapsed: ", elapsedLabel] })] }));
|
|
967
|
+
}
|
|
968
|
+
case 'n8n-local-ready':
|
|
969
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: "Local n8n is ready" }), _jsxs(Text, { dimColor: true, children: [" Instance URL: ", phase.url] }), _jsx(Text, { dimColor: true, children: " Yagr waited for the n8n editor to finish starting before showing this step." }), _jsx(Text, { dimColor: true, children: " Yagr attempted a silent owner/API bootstrap first." }), phase.note ? _jsxs(Text, { dimColor: true, children: [" ", phase.note] }) : null, _jsx(Text, { dimColor: true, children: " You will first create the owner account, then create an API key for Yagr." }), _jsx(SelectList, { options: ['Open n8n in the browser', 'I will open it myself'], cursor: phase.cursor, getLabel: (v) => v, getHint: (v) => v.startsWith('Open') ? 'recommended' : phase.url, maxVisibleRows: getListViewportHeight(terminalRows, 12), maxLineWidth: listLineWidth }), _jsx(HintBar, { hints: ['↑↓ move', 'Enter ↵ confirm', 'Ctrl+C cancel'] })] }));
|
|
970
|
+
case 'n8n-local-auth':
|
|
971
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: "Local n8n API key" }), _jsxs(Text, { dimColor: true, children: [" Local instance URL: ", phase.url] }), _jsxs(Text, { dimColor: true, children: [" ", phase.message] }), _jsx(Text, { dimColor: true, children: " If the browser is not already open, run `yagr n8n local open` or open the URL manually." }), _jsx(Box, { marginLeft: 2, marginTop: 1, children: _jsx(WizardTextInput, { value: textValue, onChange: setTextValue, onSubmit: handleN8nApiKeySubmit(phase.url), mask: "\u25CF", placeholder: "Paste the new n8n API key" }) }), _jsx(HintBar, { hints: ['Enter ↵ confirm', 'Ctrl+C cancel'] })] }));
|
|
590
972
|
case 'n8n-project':
|
|
591
973
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: "n8n project" }), _jsxs(Text, { dimColor: true, children: [" ", phase.projects.length, " project(s) found"] }), _jsx(SelectList, { options: phase.projects, cursor: phase.cursor, getLabel: (p) => p.name ?? p.id, getHint: (p) => p.id, maxVisibleRows: getListViewportHeight(terminalRows, 11), maxLineWidth: listLineWidth }), _jsx(HintBar, { hints: ['↑↓ move', 'Enter ↵ select', 'Ctrl+C cancel'] })] }));
|
|
592
974
|
case 'n8n-syncfolder':
|
|
593
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: "Local workflow sync folder" }), _jsx(Box, { marginLeft: 2, children: _jsx(WizardTextInput, { value: textValue, onChange: setTextValue, onSubmit: handleSyncFolderSubmit(phase.url, phase.apiKey, phase.project), placeholder: "workflows" }) }), phase.err ? _jsx(ErrorLine, { message: phase.err }) : null, _jsx(HintBar, { hints: ['Enter ↵ confirm', 'Ctrl+C cancel'] })] }));
|
|
975
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: "Local workflow sync folder" }), _jsx(Box, { marginLeft: 2, children: _jsx(WizardTextInput, { value: textValue, onChange: setTextValue, onSubmit: handleSyncFolderSubmit(phase.url, phase.apiKey, phase.runtimeSource, phase.project), placeholder: "workflows" }) }), phase.err ? _jsx(ErrorLine, { message: phase.err }) : null, _jsx(HintBar, { hints: ['Enter ↵ confirm', 'Ctrl+C cancel'] })] }));
|
|
594
976
|
case 'n8n-saving':
|
|
595
977
|
return (_jsx(Box, { flexDirection: "column", children: _jsx(SpinnerDisplay, { message: "Saving n8n configuration and refreshing workspace\u2026", frame: spinnerFrame }) }));
|
|
596
978
|
case 'llm-reuse-config':
|
|
597
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: "LLM configuration" }), _jsxs(Text, { dimColor: true, children: [" Currently configured: ", phase.provider, " / ", phase.model] }), _jsx(SelectList, { options: ['Keep current configuration', 'Change provider or model'], cursor: phase.cursor, getLabel: (v) => v, maxVisibleRows: getListViewportHeight(terminalRows, 11), maxLineWidth: listLineWidth }), _jsx(HintBar, { hints: ['↑↓ move', 'Enter ↵ confirm', 'Ctrl+C cancel'] })] }));
|
|
979
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: "LLM configuration" }), _jsxs(Text, { dimColor: true, children: [" Currently configured: ", getProviderDisplayName(phase.provider), " / ", phase.model] }), _jsx(SelectList, { options: ['Keep current configuration', 'Change provider or model'], cursor: phase.cursor, getLabel: (v) => v, maxVisibleRows: getListViewportHeight(terminalRows, 11), maxLineWidth: listLineWidth }), _jsx(HintBar, { hints: ['↑↓ move', 'Enter ↵ confirm', 'Ctrl+C cancel'] })] }));
|
|
598
980
|
case 'llm-provider':
|
|
599
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: "Default LLM provider" }), _jsx(SelectList, { options: VALID_PROVIDERS, cursor: phase.cursor, getLabel: (v) => v, getHint: (v) =>
|
|
981
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: "Default LLM provider" }), _jsx(SelectList, { options: VALID_PROVIDERS, cursor: phase.cursor, getLabel: (v) => getProviderDisplayName(v), getHint: (v) => {
|
|
982
|
+
const parts = [
|
|
983
|
+
getProviderSetupHint(v),
|
|
984
|
+
isExperimentalProvider(v) ? 'experimental' : undefined,
|
|
985
|
+
v === phase.initial ? 'currently configured' : undefined,
|
|
986
|
+
].filter(Boolean);
|
|
987
|
+
return parts.length > 0 ? parts.join(' · ') : undefined;
|
|
988
|
+
}, maxVisibleRows: getListViewportHeight(terminalRows, 10), maxLineWidth: listLineWidth }), _jsx(HintBar, { hints: ['↑↓ move', 'Enter ↵ select', 'Ctrl+C cancel'] })] }));
|
|
989
|
+
case 'llm-account-auth':
|
|
990
|
+
{
|
|
991
|
+
const authCopy = getProviderAuthCopy(phase.provider);
|
|
992
|
+
const authOptions = [authCopy.continueLabel, 'Back to providers'];
|
|
993
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: authCopy.title }), authCopy.body.map((line) => (_jsxs(Text, { dimColor: true, children: [" ", line] }, line))), _jsx(SelectList, { options: authOptions, cursor: phase.cursor, getLabel: (v) => v, getHint: (v) => {
|
|
994
|
+
return (v.startsWith('Continue') || v.startsWith('Paste')) ? 'recommended' : undefined;
|
|
995
|
+
}, maxVisibleRows: getListViewportHeight(terminalRows, 11), maxLineWidth: listLineWidth }), _jsx(HintBar, { hints: ['↑↓ move', 'Enter ↵ confirm', 'Ctrl+C cancel'] })] }));
|
|
996
|
+
}
|
|
997
|
+
case 'llm-account-input':
|
|
998
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: phase.title }), phase.instructions.map((line, index) => (_jsxs(Text, { dimColor: true, children: [" ", line] }, `${index}-${line}`))), _jsx(Box, { marginLeft: 2, marginTop: 1, children: _jsx(WizardTextInput, { value: textValue, onChange: setTextValue, onSubmit: handleAccountAuthSubmit(phase.provider, phase.state), placeholder: phase.placeholder }) }), phase.err ? _jsx(ErrorLine, { message: phase.err }) : null, _jsx(HintBar, { hints: [`${phase.submitLabel} (Enter ↵)`, 'Ctrl+C cancel'] })] }));
|
|
600
999
|
case 'llm-reuse-apikey':
|
|
601
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: `${phase.provider} API key` }), _jsxs(Text, { dimColor: true, children: [" A saved key exists for ", phase.provider] }), _jsx(SelectList, { options: ['Keep the saved key', 'Enter a new key'], cursor: phase.cursor, getLabel: (v) => v, maxVisibleRows: getListViewportHeight(terminalRows, 11), maxLineWidth: listLineWidth }), _jsx(HintBar, { hints: ['↑↓ move', 'Enter ↵ confirm', 'Ctrl+C cancel'] })] }));
|
|
1000
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: `${getProviderDisplayName(phase.provider)} API key` }), _jsxs(Text, { dimColor: true, children: [" A saved key exists for ", getProviderDisplayName(phase.provider)] }), _jsx(SelectList, { options: ['Keep the saved key', 'Enter a new key'], cursor: phase.cursor, getLabel: (v) => v, maxVisibleRows: getListViewportHeight(terminalRows, 11), maxLineWidth: listLineWidth }), _jsx(HintBar, { hints: ['↑↓ move', 'Enter ↵ confirm', 'Ctrl+C cancel'] })] }));
|
|
602
1001
|
case 'llm-apikey':
|
|
603
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: `${phase.provider} API key` }), _jsx(Box, { marginLeft: 2, children: _jsx(WizardTextInput, { value: textValue, onChange: (nextValue) => {
|
|
1002
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: `${getProviderDisplayName(phase.provider)} API key` }), !providerRequiresApiKey(phase.provider) ? (_jsx(Text, { dimColor: true, children: " Optional for local proxy providers. Leave empty if your proxy handles account auth." })) : null, _jsx(Box, { marginLeft: 2, children: _jsx(WizardTextInput, { value: textValue, onChange: (nextValue) => {
|
|
604
1003
|
setTextValue(nextValue);
|
|
605
1004
|
llmApiKeyDraftsRef.current[phase.provider] = nextValue;
|
|
606
|
-
}, onSubmit: handleLlmApiKeySubmit(phase.provider), mask: "\u25CF", placeholder:
|
|
1005
|
+
}, onSubmit: handleLlmApiKeySubmit(phase.provider), mask: "\u25CF", placeholder: providerRequiresApiKey(phase.provider) ? 'your-api-key' : 'optional' }) }), phase.err ? _jsx(ErrorLine, { message: phase.err }) : null, _jsx(HintBar, { hints: ['Enter ↵ confirm', 'Ctrl+C cancel'] })] }));
|
|
607
1006
|
case 'llm-models-loading':
|
|
608
|
-
|
|
1007
|
+
const loadingMessage = isOAuthAccountProvider(phase.provider)
|
|
1008
|
+
? `Finalizing ${getProviderDisplayName(phase.provider)} account and fetching models…`
|
|
1009
|
+
: `Fetching available models for ${getProviderDisplayName(phase.provider)}…`;
|
|
1010
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(SpinnerDisplay, { message: loadingMessage, frame: spinnerFrame }), phase.note ? _jsxs(Text, { dimColor: true, children: [" ", phase.note] }) : null] }));
|
|
609
1011
|
case 'llm-model': {
|
|
610
1012
|
const modelOptions = getDisplayedModelOptions(phase.models);
|
|
611
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: `Default model · ${phase.provider}` }), phase.models.length === 0 ? (_jsx(Box, { marginLeft: 2, children: _jsx(WizardTextInput, { value: textValue, onChange: setTextValue, onSubmit: (v) => {
|
|
1013
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: `Default model · ${getProviderDisplayName(phase.provider)}` }), phase.note ? _jsxs(Text, { dimColor: true, children: [" ", phase.note] }) : null, phase.models.length === 0 ? (_jsx(Box, { marginLeft: 2, children: _jsx(WizardTextInput, { value: textValue, onChange: setTextValue, onSubmit: (v) => {
|
|
612
1014
|
const m = v.trim() || phase.defModel || '';
|
|
613
1015
|
if (!m)
|
|
614
1016
|
return;
|
|
1017
|
+
const draftedBaseUrl = llmBaseUrlDraftsRef.current[phase.provider];
|
|
1018
|
+
const defaultBaseUrl = draftedBaseUrl ?? llmDef.getBaseUrl(phase.provider);
|
|
615
1019
|
const needsUrl = llmDef.needsBaseUrl(phase.provider);
|
|
616
|
-
if (
|
|
617
|
-
|
|
618
|
-
|
|
1020
|
+
if (draftedBaseUrl) {
|
|
1021
|
+
saveLlmAndContinue(phase.provider, phase.apiKey, m, phase.note);
|
|
1022
|
+
}
|
|
1023
|
+
else if (needsUrl || defaultBaseUrl) {
|
|
1024
|
+
setPhase({ kind: 'llm-baseurl', provider: phase.provider, apiKey: phase.apiKey, model: m, def: defaultBaseUrl ?? '' });
|
|
1025
|
+
setTextValue(defaultBaseUrl ?? '');
|
|
619
1026
|
}
|
|
620
1027
|
else {
|
|
621
|
-
|
|
622
|
-
setPhase({ kind: 'surfaces', cursor: 0, selected: surfDef.surfaces });
|
|
1028
|
+
saveLlmAndContinue(phase.provider, phase.apiKey, m, phase.note);
|
|
623
1029
|
}
|
|
624
|
-
}, placeholder: phase.defModel }) })) : (_jsx(SelectList, { options: modelOptions, cursor: phase.cursor, getLabel: (v) => v === '__custom__' ? '⌨ enter manually…' : v, getHint: (v) => (phase.defModel && v === phase.defModel) ? 'previously selected' : undefined, maxVisibleRows: getListViewportHeight(terminalRows, 10), maxLineWidth: listLineWidth })), _jsx(HintBar, { hints: phase.models.length > 0
|
|
1030
|
+
}, placeholder: phase.defModel }) })) : (_jsx(SelectList, { options: modelOptions, cursor: phase.cursor, getLabel: (v) => v === '__custom__' ? '⌨ enter manually…' : v, getHint: (v) => (phase.defModel && v === phase.defModel) ? 'previously selected' : undefined, maxVisibleRows: getListViewportHeight(terminalRows, 10), maxLineWidth: listLineWidth })), _jsx(HintBar, { hints: phase.models.length > 0
|
|
1031
|
+
? ['↑↓ move', 'Enter ↵ select', 'Ctrl+C cancel']
|
|
1032
|
+
: ['Enter ↵ confirm', 'Ctrl+C cancel'] })] }));
|
|
625
1033
|
}
|
|
626
1034
|
case 'llm-baseurl':
|
|
627
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: `${phase.provider} base URL` }), _jsx(Text, { dimColor: true, children: " Leave empty to use the default endpoint" }), _jsx(Box, { marginLeft: 2, children: _jsx(WizardTextInput, { value: textValue, onChange: setTextValue, onSubmit: handleBaseUrlSubmit(phase.provider, phase.apiKey, phase.model), placeholder: phase.def || 'https://api.example.com/v1' }) }), phase.err ? _jsx(ErrorLine, { message: phase.err }) : null, _jsx(HintBar, { hints: ['Enter ↵ confirm (empty = default)', 'Ctrl+C cancel'] })] }));
|
|
1035
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: `${getProviderDisplayName(phase.provider)} base URL` }), _jsx(Text, { dimColor: true, children: " Leave empty to use the default endpoint" }), _jsx(Box, { marginLeft: 2, children: _jsx(WizardTextInput, { value: textValue, onChange: setTextValue, onSubmit: handleBaseUrlSubmit(phase.provider, phase.apiKey, phase.model), placeholder: phase.def || 'https://api.example.com/v1' }) }), phase.err ? _jsx(ErrorLine, { message: phase.err }) : null, _jsx(HintBar, { hints: ['Enter ↵ confirm (empty = default)', 'Ctrl+C cancel'] })] }));
|
|
628
1036
|
case 'surfaces':
|
|
629
1037
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(FieldLabel, { label: "Optional messaging gateways" }), _jsx(Text, { dimColor: true, children: " These enable Yagr to receive work from external channels" }), _jsx(Box, { marginTop: 1, children: _jsx(MultiSelectList, { options: SURFACE_OPTIONS, cursor: phase.cursor, selected: phase.selected, maxVisibleRows: getListViewportHeight(terminalRows, 11), maxLineWidth: listLineWidth }) }), _jsx(HintBar, { hints: ['↑↓ move', 'Space toggle', 'Enter ↵ confirm', 'Ctrl+C cancel'] })] }));
|
|
630
1038
|
case 'telegram-reuse-token':
|
|
@@ -634,7 +1042,7 @@ function SetupWizard({ callbacks, onDone }) {
|
|
|
634
1042
|
case 'telegram-connecting':
|
|
635
1043
|
return (_jsx(Box, { flexDirection: "column", children: _jsx(SpinnerDisplay, { message: "Verifying Telegram bot token\u2026", frame: spinnerFrame }) }));
|
|
636
1044
|
case 'done':
|
|
637
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: "green", bold: true, children: [CHECK, " Setup complete"] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [phase.n8nHost ? _jsxs(Text, { dimColor: true, children: [" n8n ", DOT, " ", phase.n8nHost] }) : null, phase.provider ? _jsxs(Text, { dimColor: true, children: [" LLM ", DOT, " ", phase.provider, phase.model ? ` / ${phase.model}` : ''] }) : null, phase.surfaces.length > 0
|
|
1045
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: "green", bold: true, children: [CHECK, " Setup complete"] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [phase.n8nHost ? _jsxs(Text, { dimColor: true, children: [" n8n ", DOT, " ", phase.n8nHost] }) : null, phase.provider ? _jsxs(Text, { dimColor: true, children: [" LLM ", DOT, " ", getProviderDisplayName(phase.provider), phase.model ? ` / ${phase.model}` : ''] }) : null, phase.surfaces.length > 0
|
|
638
1046
|
? _jsxs(Text, { dimColor: true, children: [" Gates ", DOT, " ", phase.surfaces.join(', ')] })
|
|
639
1047
|
: _jsxs(Text, { dimColor: true, children: [" Gates ", DOT, " none"] })] }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Next: " }), _jsx(Text, { color: "cyan", children: "yagr start" })] })] }));
|
|
640
1048
|
case 'cancelled':
|