ultracontext 1.4.13 → 1.6.0
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/entry.mjs +9 -3
- package/dist/cli/entry.mjs.map +1 -1
- package/dist/cli/onboarding.mjs +268 -111
- package/dist/cli/onboarding.mjs.map +1 -1
- package/dist/cli/sdk-sync.mjs +199 -939
- package/dist/cli/sdk-sync.mjs.map +1 -1
- package/dist/cli/switch.mjs +168 -0
- package/dist/cli/switch.mjs.map +1 -0
- package/dist/{ctl-CXfNEPN8.mjs → ctl-DTQZxn3N.mjs} +2 -2
- package/dist/{ctl-CXfNEPN8.mjs.map → ctl-DTQZxn3N.mjs.map} +1 -1
- package/dist/hero-art-C03HmDXN.mjs +46 -0
- package/dist/hero-art-C03HmDXN.mjs.map +1 -0
- package/dist/index.d.mts +21 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +25 -3
- package/dist/index.mjs.map +1 -1
- package/dist/{launcher-BMMjzr5k.mjs → launcher-ZylswrpR.mjs} +3 -3
- package/dist/{launcher-BMMjzr5k.mjs.map → launcher-ZylswrpR.mjs.map} +1 -1
- package/dist/{lock-5aJnda81.mjs → lock-BhZX2aF3.mjs} +2 -2
- package/dist/{lock-5aJnda81.mjs.map → lock-BhZX2aF3.mjs.map} +1 -1
- package/dist/onboarding-preferences-Alhblobi.mjs +76 -0
- package/dist/onboarding-preferences-Alhblobi.mjs.map +1 -0
- package/dist/src-Bovo1ukU.mjs +1200 -0
- package/dist/src-Bovo1ukU.mjs.map +1 -0
- package/dist/{tui-DZ1SDOH2.mjs → tui-DLEjew3K.mjs} +334 -115
- package/dist/tui-DLEjew3K.mjs.map +1 -0
- package/dist/utils-BTfShW0g.mjs +36 -0
- package/dist/utils-BTfShW0g.mjs.map +1 -0
- package/dist/{utils-CmuIYHtm.mjs → utils-D9CKnbke.mjs} +26 -34
- package/dist/utils-D9CKnbke.mjs.map +1 -0
- package/lib/register-skills.mjs +96 -0
- package/package.json +8 -3
- package/plugin/.claude-plugin/plugin.json +6 -0
- package/plugin/README.md +112 -0
- package/plugin/marketplace.json +17 -0
- package/plugin/skills/switch/SKILL.md +27 -0
- package/postinstall.mjs +35 -2
- package/dist/Spinner-CwBjkXHv.mjs +0 -153
- package/dist/Spinner-CwBjkXHv.mjs.map +0 -1
- package/dist/tui-DZ1SDOH2.mjs.map +0 -1
- package/dist/utils-CmuIYHtm.mjs.map +0 -1
package/dist/cli/onboarding.mjs
CHANGED
|
@@ -1,39 +1,118 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { t as heroArtForWidth } from "../hero-art-C03HmDXN.mjs";
|
|
2
|
+
import { i as buildOnboardingConfigPatch, n as ONBOARDING_AGENT_OPTIONS, r as ONBOARDING_CAPTURE_OPTIONS, t as ONBOARDING_AGENT_ALL_OPTION } from "../onboarding-preferences-Alhblobi.mjs";
|
|
3
|
+
import process$1 from "node:process";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import fs from "node:fs";
|
|
5
|
-
import { spawn } from "node:child_process";
|
|
6
6
|
import React from "react";
|
|
7
7
|
import { Box, Text, render, useInput, useStdout } from "ink";
|
|
8
8
|
import { TitledBox } from "@mishieck/ink-titled-box";
|
|
9
9
|
|
|
10
|
+
//#region ../sync/src/recent-projects.mjs
|
|
11
|
+
function safeStat(p) {
|
|
12
|
+
try {
|
|
13
|
+
return fs.statSync(p);
|
|
14
|
+
} catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function safeReaddir(dir) {
|
|
19
|
+
try {
|
|
20
|
+
return fs.readdirSync(dir, { withFileTypes: true });
|
|
21
|
+
} catch {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function firstJsonlFile(dir) {
|
|
26
|
+
return safeReaddir(dir).filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => {
|
|
27
|
+
const full = path.join(dir, e.name);
|
|
28
|
+
const stat = safeStat(full);
|
|
29
|
+
return {
|
|
30
|
+
full,
|
|
31
|
+
mtime: stat ? stat.mtimeMs : 0
|
|
32
|
+
};
|
|
33
|
+
}).sort((a, b) => b.mtime - a.mtime)[0]?.full ?? null;
|
|
34
|
+
}
|
|
35
|
+
function readCwdFromJsonl(file, maxLines = 10) {
|
|
36
|
+
try {
|
|
37
|
+
const lines = fs.readFileSync(file, "utf8").split("\n", maxLines + 1).slice(0, maxLines);
|
|
38
|
+
for (const line of lines) {
|
|
39
|
+
if (!line) continue;
|
|
40
|
+
try {
|
|
41
|
+
const obj = JSON.parse(line);
|
|
42
|
+
if (typeof obj.cwd === "string" && obj.cwd) return obj.cwd;
|
|
43
|
+
if (obj.payload && typeof obj.payload.cwd === "string" && obj.payload.cwd) return obj.payload.cwd;
|
|
44
|
+
} catch {}
|
|
45
|
+
}
|
|
46
|
+
} catch {}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
function decodeDirNameWithLeadingSlash(name) {
|
|
50
|
+
return "/" + name.replace(/^-/, "").replace(/-/g, "/");
|
|
51
|
+
}
|
|
52
|
+
function decodeCursorDirName(name) {
|
|
53
|
+
return "/" + name.replace(/-/g, "/");
|
|
54
|
+
}
|
|
55
|
+
function collect(rootDir, decode) {
|
|
56
|
+
return safeReaddir(rootDir).filter((entry) => entry.isDirectory()).map((entry) => {
|
|
57
|
+
const dir = path.join(rootDir, entry.name);
|
|
58
|
+
const stat = safeStat(dir);
|
|
59
|
+
const mtime = stat ? stat.mtimeMs : 0;
|
|
60
|
+
const jsonl = firstJsonlFile(dir);
|
|
61
|
+
return {
|
|
62
|
+
path: (jsonl ? readCwdFromJsonl(jsonl) : null) || decode(entry.name),
|
|
63
|
+
mtime
|
|
64
|
+
};
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
function discoverRecentProjects({ home = process.env.HOME } = {}) {
|
|
68
|
+
if (!home) return [];
|
|
69
|
+
const candidates = [...collect(path.join(home, ".claude", "projects"), decodeDirNameWithLeadingSlash), ...collect(path.join(home, ".cursor", "projects"), decodeCursorDirName)];
|
|
70
|
+
const best = /* @__PURE__ */ new Map();
|
|
71
|
+
for (const c of candidates) {
|
|
72
|
+
if (!c.path || !c.path.startsWith("/")) continue;
|
|
73
|
+
const stat = safeStat(c.path);
|
|
74
|
+
if (!stat || !stat.isDirectory()) continue;
|
|
75
|
+
const prev = best.get(c.path);
|
|
76
|
+
if (!prev || prev.mtime < c.mtime) best.set(c.path, c);
|
|
77
|
+
}
|
|
78
|
+
return [...best.values()].sort((a, b) => b.mtime - a.mtime).map((c) => c.path);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
//#endregion
|
|
10
82
|
//#region src/cli/onboarding.mjs
|
|
11
|
-
const
|
|
12
|
-
|
|
83
|
+
const AGENT_ROWS = [ONBOARDING_AGENT_ALL_OPTION, ...ONBOARDING_AGENT_OPTIONS];
|
|
84
|
+
function ListRow({ focused, checked, label, multi = false, keyProp }) {
|
|
85
|
+
const line = `${focused ? "❯ " : " "}${multi ? checked ? "✓ " : " " : ""}${label}`;
|
|
86
|
+
return React.createElement(Text, {
|
|
87
|
+
key: keyProp,
|
|
88
|
+
color: focused ? "white" : "gray",
|
|
89
|
+
bold: focused
|
|
90
|
+
}, line);
|
|
91
|
+
}
|
|
92
|
+
function configPaths() {
|
|
93
|
+
const home = process$1.env.ULTRACONTEXT_CONFIG_HOME || process$1.env.HOME || process$1.env.USERPROFILE || "~";
|
|
94
|
+
const dir = path.join(home, ".ultracontext");
|
|
95
|
+
return {
|
|
96
|
+
dir,
|
|
97
|
+
path: path.join(dir, "config.json")
|
|
98
|
+
};
|
|
99
|
+
}
|
|
13
100
|
function readConfig() {
|
|
14
101
|
try {
|
|
15
|
-
return JSON.parse(fs.readFileSync(
|
|
102
|
+
return JSON.parse(fs.readFileSync(configPaths().path, "utf8"));
|
|
16
103
|
} catch {
|
|
17
104
|
return {};
|
|
18
105
|
}
|
|
19
106
|
}
|
|
20
107
|
function writeConfig(patch) {
|
|
21
108
|
const existing = readConfig();
|
|
22
|
-
|
|
23
|
-
fs.
|
|
109
|
+
const { dir, path: file } = configPaths();
|
|
110
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
111
|
+
fs.writeFileSync(file, JSON.stringify({
|
|
24
112
|
...existing,
|
|
25
113
|
...patch
|
|
26
114
|
}, null, 2) + "\n", "utf8");
|
|
27
115
|
}
|
|
28
|
-
function openUrl(url) {
|
|
29
|
-
const cmd = process.platform === "darwin" ? "open" : "xdg-open";
|
|
30
|
-
try {
|
|
31
|
-
spawn(cmd, [url], {
|
|
32
|
-
detached: true,
|
|
33
|
-
stdio: "ignore"
|
|
34
|
-
}).unref();
|
|
35
|
-
} catch {}
|
|
36
|
-
}
|
|
37
116
|
function isValidKey(key) {
|
|
38
117
|
return /^uc_(live|test)_/.test(key);
|
|
39
118
|
}
|
|
@@ -44,20 +123,6 @@ const MODE_OPTIONS = [{
|
|
|
44
123
|
label: "Self-host",
|
|
45
124
|
value: "selfhost"
|
|
46
125
|
}];
|
|
47
|
-
const BOOTSTRAP_OPTIONS = [
|
|
48
|
-
{
|
|
49
|
-
label: "New only (recommended)",
|
|
50
|
-
value: "new_only"
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
label: "Last 24h",
|
|
54
|
-
value: "last_24h"
|
|
55
|
-
},
|
|
56
|
-
{
|
|
57
|
-
label: "All",
|
|
58
|
-
value: "all"
|
|
59
|
-
}
|
|
60
|
-
];
|
|
61
126
|
const LAUNCH_OPTIONS = [{
|
|
62
127
|
label: "Yes, open the TUI (recommended)",
|
|
63
128
|
value: true
|
|
@@ -69,42 +134,70 @@ function stepNumber(step) {
|
|
|
69
134
|
if (step === "welcome") return 1;
|
|
70
135
|
if (step === "mode") return 2;
|
|
71
136
|
if (step === "url" || step === "key") return 3;
|
|
72
|
-
if (step === "
|
|
73
|
-
if (step === "
|
|
74
|
-
return
|
|
137
|
+
if (step === "agents") return 4;
|
|
138
|
+
if (step === "projects") return 5;
|
|
139
|
+
if (step === "capture") return 6;
|
|
140
|
+
if (step === "launch") return 7;
|
|
141
|
+
return 7;
|
|
75
142
|
}
|
|
76
|
-
const TOTAL_STEPS =
|
|
143
|
+
const TOTAL_STEPS = 7;
|
|
77
144
|
function Onboarding({ onDone }) {
|
|
78
145
|
const { stdout } = useStdout();
|
|
79
|
-
const cols = stdout?.columns ?? process.stdout.columns ?? 80;
|
|
146
|
+
const cols = stdout?.columns ?? process$1.stdout.columns ?? 80;
|
|
80
147
|
const [step, setStep] = React.useState("welcome");
|
|
148
|
+
const [history, setHistory] = React.useState([]);
|
|
81
149
|
const [hosting, setHosting] = React.useState("cloud");
|
|
82
150
|
const [baseUrl, setBaseUrl] = React.useState("https://api.ultracontext.ai");
|
|
83
151
|
const [apiKey, setApiKey] = React.useState("");
|
|
84
|
-
const [
|
|
152
|
+
const [captureAgents, setCaptureAgents] = React.useState(ONBOARDING_AGENT_OPTIONS.map((o) => o.id));
|
|
153
|
+
const [projectPaths, setProjectPaths] = React.useState([]);
|
|
154
|
+
const [autoCaptureMode, setAutoCaptureMode] = React.useState("all");
|
|
85
155
|
const [selectedIndex, setSelectedIndex] = React.useState(0);
|
|
86
156
|
const [keyInput, setKeyInput] = React.useState("");
|
|
87
157
|
const [urlInput, setUrlInput] = React.useState("https://");
|
|
88
158
|
const [error, setError] = React.useState("");
|
|
89
|
-
const
|
|
90
|
-
const
|
|
159
|
+
const inferredProjects = React.useMemo(() => discoverRecentProjects(), []);
|
|
160
|
+
const ALL_PROJECTS = "__all__";
|
|
161
|
+
const projectRows = React.useMemo(() => [ALL_PROJECTS, ...inferredProjects], [inferredProjects]);
|
|
162
|
+
const [pickedProjects, setPickedProjects] = React.useState([ALL_PROJECTS]);
|
|
163
|
+
const pushStep = React.useCallback((nextStep) => {
|
|
164
|
+
setHistory((h) => [...h, step]);
|
|
165
|
+
setStep(nextStep);
|
|
166
|
+
setSelectedIndex(0);
|
|
167
|
+
setError("");
|
|
168
|
+
}, [step]);
|
|
169
|
+
const goBack = React.useCallback(() => {
|
|
170
|
+
setHistory((h) => {
|
|
171
|
+
if (h.length === 0) return h;
|
|
172
|
+
setStep(h[h.length - 1]);
|
|
173
|
+
setSelectedIndex(0);
|
|
174
|
+
setError("");
|
|
175
|
+
return h.slice(0, -1);
|
|
176
|
+
});
|
|
177
|
+
}, []);
|
|
178
|
+
const finish = React.useCallback((finalKey, finalUrl, preferences) => {
|
|
91
179
|
writeConfig({
|
|
92
180
|
apiKey: finalKey,
|
|
93
181
|
baseUrl: finalUrl,
|
|
94
|
-
|
|
182
|
+
...buildOnboardingConfigPatch(preferences)
|
|
95
183
|
});
|
|
96
|
-
process.env.ULTRACONTEXT_API_KEY = finalKey;
|
|
97
|
-
process.env.ULTRACONTEXT_BASE_URL = finalUrl;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}, []);
|
|
184
|
+
process$1.env.ULTRACONTEXT_API_KEY = finalKey;
|
|
185
|
+
process$1.env.ULTRACONTEXT_BASE_URL = finalUrl;
|
|
186
|
+
pushStep("launch");
|
|
187
|
+
}, [pushStep]);
|
|
101
188
|
useInput((input, key) => {
|
|
102
|
-
if (
|
|
189
|
+
if (input === "c" && key.ctrl) process$1.exit(0);
|
|
190
|
+
if (key.escape) {
|
|
191
|
+
if (step === "welcome") process$1.exit(0);
|
|
192
|
+
goBack();
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (key.leftArrow && step !== "welcome") {
|
|
196
|
+
goBack();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
103
199
|
if (step === "welcome") {
|
|
104
|
-
if (key.return)
|
|
105
|
-
setStep("mode");
|
|
106
|
-
setSelectedIndex(0);
|
|
107
|
-
}
|
|
200
|
+
if (key.return) pushStep("mode");
|
|
108
201
|
return;
|
|
109
202
|
}
|
|
110
203
|
if (step === "mode") {
|
|
@@ -115,18 +208,11 @@ function Onboarding({ onDone }) {
|
|
|
115
208
|
if (key.return || input === " ") {
|
|
116
209
|
const chosen = MODE_OPTIONS[selectedIndex].value;
|
|
117
210
|
setHosting(chosen);
|
|
118
|
-
if (chosen === "selfhost")
|
|
119
|
-
|
|
120
|
-
setUrlInput("https://");
|
|
121
|
-
setError("");
|
|
122
|
-
} else {
|
|
211
|
+
if (chosen === "selfhost") pushStep("url");
|
|
212
|
+
else {
|
|
123
213
|
setBaseUrl("https://api.ultracontext.ai");
|
|
124
|
-
|
|
125
|
-
setStep("key");
|
|
126
|
-
setKeyInput("");
|
|
127
|
-
setError("");
|
|
214
|
+
pushStep("key");
|
|
128
215
|
}
|
|
129
|
-
setSelectedIndex(0);
|
|
130
216
|
}
|
|
131
217
|
return;
|
|
132
218
|
}
|
|
@@ -138,9 +224,7 @@ function Onboarding({ onDone }) {
|
|
|
138
224
|
return;
|
|
139
225
|
}
|
|
140
226
|
setBaseUrl(trimmed);
|
|
141
|
-
|
|
142
|
-
setKeyInput("");
|
|
143
|
-
setError("");
|
|
227
|
+
pushStep("key");
|
|
144
228
|
return;
|
|
145
229
|
}
|
|
146
230
|
if (key.backspace || key.delete) {
|
|
@@ -166,9 +250,7 @@ function Onboarding({ onDone }) {
|
|
|
166
250
|
return;
|
|
167
251
|
}
|
|
168
252
|
setApiKey(trimmed);
|
|
169
|
-
|
|
170
|
-
setSelectedIndex(0);
|
|
171
|
-
setError("");
|
|
253
|
+
pushStep("agents");
|
|
172
254
|
return;
|
|
173
255
|
}
|
|
174
256
|
if (key.backspace || key.delete) {
|
|
@@ -182,16 +264,63 @@ function Onboarding({ onDone }) {
|
|
|
182
264
|
}
|
|
183
265
|
return;
|
|
184
266
|
}
|
|
185
|
-
if (step === "
|
|
267
|
+
if (step === "agents") {
|
|
268
|
+
if (key.upArrow) setSelectedIndex((i) => Math.max(i - 1, 0));
|
|
269
|
+
if (key.downArrow) setSelectedIndex((i) => Math.min(i + 1, AGENT_ROWS.length - 1));
|
|
270
|
+
if (input === " ") {
|
|
271
|
+
setError("");
|
|
272
|
+
const row = AGENT_ROWS[selectedIndex];
|
|
273
|
+
if (row.id === "all") {
|
|
274
|
+
const allIds = ONBOARDING_AGENT_OPTIONS.map((o) => o.id);
|
|
275
|
+
setCaptureAgents((current) => current.length === allIds.length ? [] : allIds);
|
|
276
|
+
} else setCaptureAgents((current) => current.includes(row.id) ? current.filter((x) => x !== row.id) : [...current, row.id]);
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (key.return) {
|
|
280
|
+
if (captureAgents.length === 0) {
|
|
281
|
+
setError("Select at least one agent");
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
pushStep("projects");
|
|
285
|
+
}
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (step === "projects") {
|
|
186
289
|
if (key.upArrow) setSelectedIndex((i) => Math.max(i - 1, 0));
|
|
187
|
-
if (key.downArrow) setSelectedIndex((i) => Math.min(i + 1,
|
|
290
|
+
if (key.downArrow) setSelectedIndex((i) => Math.min(i + 1, projectRows.length - 1));
|
|
291
|
+
if (input === " ") {
|
|
292
|
+
const row = projectRows[selectedIndex];
|
|
293
|
+
setPickedProjects((current) => {
|
|
294
|
+
if (row === ALL_PROJECTS) return current.includes(ALL_PROJECTS) ? [] : [ALL_PROJECTS];
|
|
295
|
+
const without = current.filter((p) => p !== ALL_PROJECTS && p !== row);
|
|
296
|
+
return current.includes(row) ? without : [...without, row];
|
|
297
|
+
});
|
|
298
|
+
setError("");
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
if (key.return) {
|
|
302
|
+
if (pickedProjects.length === 0) {
|
|
303
|
+
setError("Select at least one project (or 'All projects')");
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
setProjectPaths(pickedProjects.includes(ALL_PROJECTS) ? [] : pickedProjects.slice());
|
|
307
|
+
pushStep("capture");
|
|
308
|
+
}
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (step === "capture") {
|
|
312
|
+
if (key.upArrow) setSelectedIndex((i) => Math.max(i - 1, 0));
|
|
313
|
+
if (key.downArrow) setSelectedIndex((i) => Math.min(i + 1, ONBOARDING_CAPTURE_OPTIONS.length - 1));
|
|
188
314
|
if (input === "1") setSelectedIndex(0);
|
|
189
315
|
if (input === "2") setSelectedIndex(1);
|
|
190
|
-
if (input === "3") setSelectedIndex(2);
|
|
191
316
|
if (key.return || input === " ") {
|
|
192
|
-
const chosen =
|
|
193
|
-
|
|
194
|
-
finish(apiKey, baseUrl,
|
|
317
|
+
const chosen = ONBOARDING_CAPTURE_OPTIONS[selectedIndex].id;
|
|
318
|
+
setAutoCaptureMode(chosen);
|
|
319
|
+
finish(apiKey, baseUrl, {
|
|
320
|
+
captureAgents,
|
|
321
|
+
projectPaths,
|
|
322
|
+
autoCaptureMode: chosen
|
|
323
|
+
});
|
|
195
324
|
}
|
|
196
325
|
return;
|
|
197
326
|
}
|
|
@@ -202,8 +331,7 @@ function Onboarding({ onDone }) {
|
|
|
202
331
|
if (input === "2") setSelectedIndex(1);
|
|
203
332
|
if (key.return || input === " ") {
|
|
204
333
|
const chosen = LAUNCH_OPTIONS[selectedIndex].value;
|
|
205
|
-
|
|
206
|
-
setStep("done");
|
|
334
|
+
pushStep("done");
|
|
207
335
|
setTimeout(() => onDone(chosen), 80);
|
|
208
336
|
}
|
|
209
337
|
return;
|
|
@@ -212,67 +340,93 @@ function Onboarding({ onDone }) {
|
|
|
212
340
|
const heroLines = heroArtForWidth(cols - 4);
|
|
213
341
|
const stepNum = stepNumber(step);
|
|
214
342
|
const hero = React.createElement(Box, {
|
|
215
|
-
flexDirection: "row",
|
|
216
|
-
justifyContent: "center",
|
|
217
|
-
width: "100%"
|
|
218
|
-
}, React.createElement(Spinner, { color: UC_BLUE_LIGHT }), React.createElement(Box, { width: 3 }), React.createElement(Box, {
|
|
219
343
|
flexDirection: "column",
|
|
220
|
-
|
|
344
|
+
alignItems: "center",
|
|
345
|
+
width: "100%"
|
|
221
346
|
}, ...heroLines.map((line, i) => React.createElement(Text, {
|
|
222
347
|
key: `h${i}`,
|
|
223
348
|
color: "white",
|
|
224
349
|
bold: true
|
|
225
|
-
}, line)))
|
|
350
|
+
}, line)));
|
|
226
351
|
let content = null;
|
|
227
352
|
if (step === "welcome") content = React.createElement(Box, { flexDirection: "column" }, React.createElement(Text, {
|
|
228
353
|
color: "white",
|
|
229
354
|
bold: true
|
|
230
|
-
}, "Welcome to UltraContext"), React.createElement(
|
|
355
|
+
}, "Welcome to UltraContext"), React.createElement(Box, { height: 1 }), React.createElement(Text, { color: "white" }, "Press Enter to begin setup..."));
|
|
231
356
|
if (step === "mode") content = React.createElement(Box, { flexDirection: "column" }, React.createElement(Text, {
|
|
232
357
|
color: "white",
|
|
233
358
|
bold: true
|
|
234
|
-
}, "How do you want to connect?"), React.createElement(Box, { height: 1 }), ...MODE_OPTIONS.map((opt, i) => {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}, sel ? "[•]" : "[ ]", ` ${i + 1}. ${opt.label}`);
|
|
240
|
-
}), React.createElement(Box, { height: 1 }), React.createElement(Text, { color: "gray" }, "Navigate: up/down, 1/2 | Confirm: Enter"));
|
|
359
|
+
}, "How do you want to connect?"), React.createElement(Box, { height: 1 }), ...MODE_OPTIONS.map((opt, i) => ListRow({
|
|
360
|
+
keyProp: `m${i}`,
|
|
361
|
+
focused: i === selectedIndex,
|
|
362
|
+
label: opt.label
|
|
363
|
+
})), React.createElement(Box, { height: 1 }), React.createElement(Text, { color: "gray" }, "↑↓ navigate · enter select"));
|
|
241
364
|
if (step === "url") content = React.createElement(Box, { flexDirection: "column" }, React.createElement(Text, {
|
|
242
365
|
color: "white",
|
|
243
366
|
bold: true
|
|
244
|
-
}, "Enter your API base URL:"), React.createElement(Box, { height: 1 }), React.createElement(Text, {
|
|
367
|
+
}, "Enter your API base URL:"), React.createElement(Box, { height: 1 }), React.createElement(Text, {
|
|
368
|
+
color: "white",
|
|
369
|
+
bold: true
|
|
370
|
+
}, `> ${urlInput}_`), error ? React.createElement(Text, { color: "red" }, error) : null, React.createElement(Box, { height: 1 }), React.createElement(Text, { color: "gray" }, "Enter to confirm | Esc to go back"));
|
|
245
371
|
if (step === "key") {
|
|
246
|
-
const keyPrompt = hosting === "cloud" ? "Paste your API key
|
|
372
|
+
const keyPrompt = hosting === "cloud" ? "Paste your API key from ultracontext.ai:" : "Enter your API key:";
|
|
247
373
|
content = React.createElement(Box, { flexDirection: "column" }, React.createElement(Text, {
|
|
248
374
|
color: "white",
|
|
249
375
|
bold: true
|
|
250
|
-
}, keyPrompt), React.createElement(Box, { height: 1 }), React.createElement(Text, {
|
|
376
|
+
}, keyPrompt), React.createElement(Box, { height: 1 }), React.createElement(Text, {
|
|
377
|
+
color: "white",
|
|
378
|
+
bold: true
|
|
379
|
+
}, `> ${keyInput}_`), error ? React.createElement(Text, { color: "red" }, error) : null, React.createElement(Box, { height: 1 }), React.createElement(Text, { color: "gray" }, "Format: uc_live_... or uc_test_... | Enter to confirm"));
|
|
251
380
|
}
|
|
252
|
-
if (step === "
|
|
381
|
+
if (step === "agents") {
|
|
382
|
+
const allChecked = ONBOARDING_AGENT_OPTIONS.every((o) => captureAgents.includes(o.id));
|
|
383
|
+
const selectedCount = captureAgents.length;
|
|
384
|
+
const totalCount = ONBOARDING_AGENT_OPTIONS.length;
|
|
385
|
+
content = React.createElement(Box, { flexDirection: "column" }, React.createElement(Text, {
|
|
386
|
+
color: "white",
|
|
387
|
+
bold: true
|
|
388
|
+
}, "Which agents should UltraContext watch?"), React.createElement(Text, { color: "gray" }, `${selectedCount} of ${totalCount} selected`), React.createElement(Box, { height: 1 }), ...AGENT_ROWS.map((opt, i) => ListRow({
|
|
389
|
+
keyProp: `a${i}`,
|
|
390
|
+
focused: i === selectedIndex,
|
|
391
|
+
checked: opt.id === "all" ? allChecked : captureAgents.includes(opt.id),
|
|
392
|
+
label: opt.label,
|
|
393
|
+
multi: true
|
|
394
|
+
})), error ? React.createElement(Text, { color: "red" }, error) : null, React.createElement(Box, { height: 1 }), React.createElement(Text, { color: "gray" }, "↑↓ navigate · space toggle · enter confirm"));
|
|
395
|
+
}
|
|
396
|
+
if (step === "projects") {
|
|
397
|
+
const specificsPicked = pickedProjects.filter((p) => p !== ALL_PROJECTS).length;
|
|
398
|
+
const summary = pickedProjects.includes(ALL_PROJECTS) ? "all projects" : `${specificsPicked} of ${inferredProjects.length} selected`;
|
|
399
|
+
content = React.createElement(Box, { flexDirection: "column" }, React.createElement(Text, {
|
|
400
|
+
color: "white",
|
|
401
|
+
bold: true
|
|
402
|
+
}, "Which projects should UltraContext auto-capture?"), React.createElement(Text, { color: "gray" }, `${summary} \u00B7 their agent sessions will be ingested`), React.createElement(Box, { height: 1 }), ...projectRows.map((row, i) => ListRow({
|
|
403
|
+
keyProp: `pr${i}`,
|
|
404
|
+
focused: i === selectedIndex,
|
|
405
|
+
checked: pickedProjects.includes(row),
|
|
406
|
+
label: row === ALL_PROJECTS ? "All projects (recommended)" : row,
|
|
407
|
+
multi: true
|
|
408
|
+
})), inferredProjects.length === 0 ? React.createElement(Text, { color: "gray" }, "(no recent Claude/Cursor projects found — all will be captured)") : null, error ? React.createElement(Text, { color: "red" }, error) : null, React.createElement(Box, { height: 1 }), React.createElement(Text, { color: "gray" }, "↑↓ navigate · space toggle · enter confirm"));
|
|
409
|
+
}
|
|
410
|
+
if (step === "capture") content = React.createElement(Box, { flexDirection: "column" }, React.createElement(Text, {
|
|
253
411
|
color: "white",
|
|
254
412
|
bold: true
|
|
255
|
-
}, "
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}, sel ? "[•]" : "[ ]", ` ${i + 1}. ${opt.label}`);
|
|
261
|
-
}), React.createElement(Box, { height: 1 }), React.createElement(Text, { color: "gray" }, "Navigate: up/down, 1/2/3 | Confirm: Enter"));
|
|
413
|
+
}, "Auto-capture mode:"), React.createElement(Box, { height: 1 }), ...ONBOARDING_CAPTURE_OPTIONS.map((opt, i) => ListRow({
|
|
414
|
+
keyProp: `c${i}`,
|
|
415
|
+
focused: i === selectedIndex,
|
|
416
|
+
label: opt.label
|
|
417
|
+
})), React.createElement(Box, { height: 1 }), React.createElement(Text, { color: "gray" }, "↑↓ navigate · enter select"));
|
|
262
418
|
if (step === "launch") content = React.createElement(Box, { flexDirection: "column" }, React.createElement(Text, {
|
|
263
419
|
color: "white",
|
|
264
420
|
bold: true
|
|
265
|
-
}, "Launch the TUI dashboard?"), React.createElement(Box, { height: 1 }), ...LAUNCH_OPTIONS.map((opt, i) => {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
}, sel ? "[•]" : "[ ]", ` ${i + 1}. ${opt.label}`);
|
|
271
|
-
}), React.createElement(Box, { height: 1 }), React.createElement(Text, { color: "gray" }, "Navigate: up/down, 1/2 | Confirm: Enter"));
|
|
421
|
+
}, "Launch the TUI dashboard?"), React.createElement(Box, { height: 1 }), ...LAUNCH_OPTIONS.map((opt, i) => ListRow({
|
|
422
|
+
keyProp: `l${i}`,
|
|
423
|
+
focused: i === selectedIndex,
|
|
424
|
+
label: opt.label
|
|
425
|
+
})), React.createElement(Box, { height: 1 }), React.createElement(Text, { color: "gray" }, "↑↓ navigate · enter select"));
|
|
272
426
|
if (step === "done") content = React.createElement(Box, { flexDirection: "column" }, React.createElement(Text, {
|
|
273
427
|
color: "green",
|
|
274
428
|
bold: true
|
|
275
|
-
}, "Setup complete!"), React.createElement(Text, { color: "gray" }, `Config saved to ${
|
|
429
|
+
}, "Setup complete!"), React.createElement(Text, { color: "gray" }, `Config saved to ${configPaths().path}`));
|
|
276
430
|
const boxWidth = Math.min(cols - 2, 60);
|
|
277
431
|
return React.createElement(Box, {
|
|
278
432
|
flexDirection: "column",
|
|
@@ -281,13 +435,13 @@ function Onboarding({ onDone }) {
|
|
|
281
435
|
paddingY: 1,
|
|
282
436
|
width: cols
|
|
283
437
|
}, hero, React.createElement(Text, {
|
|
284
|
-
color:
|
|
438
|
+
color: "white",
|
|
285
439
|
bold: true
|
|
286
|
-
}, "[
|
|
440
|
+
}, "[ Same context, everywhere ]"), React.createElement(Box, { height: 1 }), React.createElement(TitledBox, {
|
|
287
441
|
borderStyle: "single",
|
|
288
442
|
titles: ["Setup"],
|
|
289
443
|
titleJustify: "flex-start",
|
|
290
|
-
borderColor:
|
|
444
|
+
borderColor: "white",
|
|
291
445
|
flexDirection: "column",
|
|
292
446
|
paddingX: 2,
|
|
293
447
|
paddingY: 1,
|
|
@@ -295,7 +449,10 @@ function Onboarding({ onDone }) {
|
|
|
295
449
|
}, React.createElement(Text, {
|
|
296
450
|
color: "gray",
|
|
297
451
|
dimColor: true
|
|
298
|
-
}, step !== "done" ? `Step ${stepNum} of ${TOTAL_STEPS}` : "Done"), React.createElement(
|
|
452
|
+
}, step !== "done" ? `Step ${stepNum} of ${TOTAL_STEPS}` : "Done"), step !== "done" && step !== "welcome" ? React.createElement(Text, {
|
|
453
|
+
color: "gray",
|
|
454
|
+
dimColor: true
|
|
455
|
+
}, "← / Esc: back · Ctrl+C: quit") : null, React.createElement(Box, { height: 1 }), content));
|
|
299
456
|
}
|
|
300
457
|
function onboard() {
|
|
301
458
|
return new Promise((resolve) => {
|