umbrella-context 0.1.39 → 0.1.41
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/README.md +80 -0
- package/dist/adapters/byterover-runtime-bridge.js +47 -35
- package/dist/adapters/umbrella-provider-runtime.d.ts +9 -2
- package/dist/adapters/umbrella-provider-runtime.js +86 -7
- package/dist/adaptive/runtime.d.ts +27 -0
- package/dist/adaptive/runtime.js +154 -0
- package/dist/commands/adaptive.d.ts +7 -0
- package/dist/commands/adaptive.js +92 -0
- package/dist/commands/connectors.js +96 -1
- package/dist/commands/curate.js +2 -0
- package/dist/commands/logout.js +1 -0
- package/dist/commands/model.js +30 -5
- package/dist/commands/providers.js +9 -3
- package/dist/commands/search.d.ts +1 -0
- package/dist/commands/search.js +51 -12
- package/dist/commands/setup.js +1 -1
- package/dist/commands/source.d.ts +11 -0
- package/dist/commands/source.js +152 -0
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.js +18 -3
- package/dist/commands/swarm.d.ts +16 -0
- package/dist/commands/swarm.js +211 -0
- package/dist/commands/tui.js +223 -52
- package/dist/commands/worktree.d.ts +12 -0
- package/dist/commands/worktree.js +141 -0
- package/dist/index.js +8 -0
- package/dist/repo-state.d.ts +71 -0
- package/dist/repo-state.js +260 -7
- package/dist/swarm/runtime.d.ts +502 -0
- package/dist/swarm/runtime.js +957 -0
- package/package.json +1 -1
package/dist/commands/tui.js
CHANGED
|
@@ -4,15 +4,16 @@ import { Box, render, Text, useApp, useInput } from "ink";
|
|
|
4
4
|
import TextInput from "ink-text-input";
|
|
5
5
|
import Spinner from "ink-spinner";
|
|
6
6
|
import chalk from "chalk";
|
|
7
|
-
import {
|
|
7
|
+
import { getAdaptiveKnowledgeSummary } from "../adaptive/runtime.js";
|
|
8
|
+
import { createDefaultUmbrellaAuthSnapshot, formatUmbrellaAuthStatus } from "../auth-state.js";
|
|
8
9
|
import { getUmbrellaContextRuntimeSummary, useUmbrellaContextRuntimeBridgeStore, hydrateUmbrellaContextRuntimeBridgeFromSnapshot, } from "../adapters/byterover-context-runtime-store.js";
|
|
9
10
|
import { getUmbrellaTransportTaskBridgeSummary, useUmbrellaTransportTaskBridgeStore, hydrateUmbrellaTransportTaskBridgeFromSnapshot, } from "../adapters/byterover-transport-task-store.js";
|
|
10
11
|
import { buildVendorRuntimeBridgeSnapshot, } from "../adapters/byterover-runtime-bridge.js";
|
|
11
|
-
import { addPendingMemory, completeTask, createTask, ensureRepoContext, getContextTreeState, ensureSessionState, getConnectorRuns, getInstalledConnectors, getInstalledHubEntries, getPendingMemories, getPulledFixes, getPulledMemories, getRepoContext, removeTask, getSessionState, getTasks, getTransportState, recordSessionEvent, setSessionPanel, summarizeLocalMemoryMatches, } from "../repo-state.js";
|
|
12
|
+
import { addPendingMemory, completeTask, createTask, ensureRepoContext, getContextTreeState, ensureSessionState, getConnectorRuns, getInstalledConnectors, getInstalledHubEntries, getPendingMemories, getPulledFixes, getPulledMemories, getRepoContext, getRepoResolution, removeTask, getSessionState, getTasks, getTransportState, listKnowledgeSources, listRegisteredWorktrees, recordSessionEvent, setSessionPanel, summarizeLocalMemoryMatches, } from "../repo-state.js";
|
|
12
13
|
import { configManager } from "../config.js";
|
|
13
14
|
import { getStoredUmbrellaAuthSnapshot, setUmbrellaAuthAuthorized, setUmbrellaAuthChecking, setUmbrellaAuthFailure, } from "../adapters/umbrella-auth-runtime.js";
|
|
14
15
|
import { checkUmbrellaOnboardingServer, connectUmbrellaDevice, createUmbrellaOnboardingCompany, createUmbrellaOnboardingSpace, loadUmbrellaOnboardingSpaces, signInUmbrellaOnboarding, } from "../adapters/umbrella-onboarding.js";
|
|
15
|
-
import { buildProviderDraftValue, connectSavedProviderFromDraft, createEmptyProviderConnectDraft, UMBRELLA_PROVIDER_CHOICES, updateProviderDraftValue, } from "../adapters/umbrella-provider-runtime.js";
|
|
16
|
+
import { buildProviderDraftValue, connectSavedProviderFromDraft, createEmptyProviderConnectDraft, getProviderChoice, UMBRELLA_PROVIDER_CHOICES, updateProviderDraftValue, } from "../adapters/umbrella-provider-runtime.js";
|
|
16
17
|
import { connectorsCommandAction, listConnectorTemplates } from "./connectors.js";
|
|
17
18
|
import { hubCommandAction, listHubRegistryEntries } from "./hub.js";
|
|
18
19
|
import { modelCommandAction } from "./model.js";
|
|
@@ -21,6 +22,7 @@ import { pushCommandAction } from "./push.js";
|
|
|
21
22
|
import { getProviderReadinessSummary, providersCommandAction } from "./providers.js";
|
|
22
23
|
import { spaceCommandAction } from "./space.js";
|
|
23
24
|
import { buildConnectionPresentation } from "./status.js";
|
|
25
|
+
import { getSwarmStatus } from "../swarm/runtime.js";
|
|
24
26
|
const PANELS = [
|
|
25
27
|
{ id: "home", title: "Home", description: "Repo status, sync, and next steps" },
|
|
26
28
|
{ id: "tasks", title: "Tasks", description: "Live local task activity from .um" },
|
|
@@ -43,6 +45,23 @@ const PANEL_SHORTCUTS = [
|
|
|
43
45
|
{ id: "connectors", key: "c", label: "Connectors" },
|
|
44
46
|
{ id: "session", key: "u", label: "Session" },
|
|
45
47
|
];
|
|
48
|
+
const SESSION_ACTIONS = [
|
|
49
|
+
{
|
|
50
|
+
id: "repair-setup",
|
|
51
|
+
title: "Repair setup / switch server or company",
|
|
52
|
+
description: "Restart the setup flow so you can choose the live server, sign in again, and pick a different company if needed.",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: "switch-space",
|
|
56
|
+
title: "Switch to another space",
|
|
57
|
+
description: "Open the Spaces panel for this company and pick a different space for this repo.",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: "sign-out",
|
|
61
|
+
title: "Sign out this device and start over",
|
|
62
|
+
description: "Clear the saved Umbrella link on this computer, then restart setup from the beginning.",
|
|
63
|
+
},
|
|
64
|
+
];
|
|
46
65
|
const DEFAULT_UMBRELLA_SERVER_URL = "http://5.161.55.138:3100";
|
|
47
66
|
const LOCAL_UMBRELLA_SERVER_URL = "http://127.0.0.1:3100";
|
|
48
67
|
const SETUP_SERVER_CHOICES = [
|
|
@@ -62,6 +81,16 @@ const SETUP_SERVER_CHOICES = [
|
|
|
62
81
|
description: "Type a different Umbrella server URL yourself.",
|
|
63
82
|
},
|
|
64
83
|
];
|
|
84
|
+
function inferSetupServerChoiceIndex(serverUrl) {
|
|
85
|
+
const normalized = trimSlash(serverUrl ?? "");
|
|
86
|
+
if (!normalized)
|
|
87
|
+
return 0;
|
|
88
|
+
if (normalized === DEFAULT_UMBRELLA_SERVER_URL)
|
|
89
|
+
return 0;
|
|
90
|
+
if (normalized === LOCAL_UMBRELLA_SERVER_URL)
|
|
91
|
+
return 1;
|
|
92
|
+
return 2;
|
|
93
|
+
}
|
|
65
94
|
function trimSlash(value) {
|
|
66
95
|
return value.trim().replace(/\/+$/, "");
|
|
67
96
|
}
|
|
@@ -148,6 +177,34 @@ function formatAgo(value) {
|
|
|
148
177
|
return "Never";
|
|
149
178
|
return new Date(value).toLocaleString();
|
|
150
179
|
}
|
|
180
|
+
function summarizeNames(items, emptyLabel) {
|
|
181
|
+
if (items.length === 0)
|
|
182
|
+
return emptyLabel;
|
|
183
|
+
if (items.length <= 3)
|
|
184
|
+
return items.join(", ");
|
|
185
|
+
return `${items.slice(0, 3).join(", ")} +${items.length - 3} more`;
|
|
186
|
+
}
|
|
187
|
+
function isAutoBootstrappedSwarm(sw) {
|
|
188
|
+
return sw.suggestions.some((suggestion) => suggestion.toLowerCase().includes("auto-created config"));
|
|
189
|
+
}
|
|
190
|
+
function hasLiveSourceProvider(sw) {
|
|
191
|
+
return sw.providers.some((provider) => provider.type === "umbrella-source" && provider.available);
|
|
192
|
+
}
|
|
193
|
+
function getSwarmReadinessLabel(sw, sourceCount) {
|
|
194
|
+
if (sourceCount === 0)
|
|
195
|
+
return "No linked source repos yet";
|
|
196
|
+
if (hasLiveSourceProvider(sw))
|
|
197
|
+
return "Cross-repo search is live";
|
|
198
|
+
if (sw.configured)
|
|
199
|
+
return "Sources linked, but not all searchable yet";
|
|
200
|
+
return "Sources linked, but swarm still needs setup";
|
|
201
|
+
}
|
|
202
|
+
function getSwarmHealthyCount(sw) {
|
|
203
|
+
return sw.providers.filter((provider) => provider.available).length;
|
|
204
|
+
}
|
|
205
|
+
function getSwarmWritableCount(sw) {
|
|
206
|
+
return sw.providers.filter((provider) => provider.available && provider.writable).length;
|
|
207
|
+
}
|
|
151
208
|
function StatusLine({ label, value }) {
|
|
152
209
|
return (_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: "cyan", children: label.padEnd(18) }), _jsx(Text, { children: value })] }));
|
|
153
210
|
}
|
|
@@ -168,7 +225,7 @@ function SpacePanelView(props) {
|
|
|
168
225
|
function ProviderPanelView(props) {
|
|
169
226
|
const { activeModel, activeProviderId, connectDraftValue, connectKindIndex, mode, onConnectDraftChange, providers, recentProviderId, readinessState, selectedIndex, } = props;
|
|
170
227
|
if (mode === "connect-kind") {
|
|
171
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Connect a Provider" }), _jsx(Text, { color: "gray", children: "Pick the model company you want this device to use for Context work." }), _jsx(Section, { title: "Provider Types", children: UMBRELLA_PROVIDER_CHOICES.map((choice, index) => (_jsxs(Text, { color: index === connectKindIndex ? "yellow" : "white", children: [index === connectKindIndex ? ">" : " ", " ", choice.name] }, choice.kind))) }), _jsx(Text, { color: "gray", children: "Up and down move through provider types. Enter confirms. Esc goes back." })] }));
|
|
228
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Connect a Provider" }), _jsx(Text, { color: "gray", children: "Pick the model company you want this device to use for Context work." }), _jsx(Section, { title: "Provider Types", children: UMBRELLA_PROVIDER_CHOICES.map((choice, index) => (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { color: index === connectKindIndex ? "yellow" : "white", children: [index === connectKindIndex ? ">" : " ", " ", choice.name] }), _jsx(Text, { color: "gray", children: choice.description }), choice.baseUrl ? _jsxs(Text, { color: "gray", children: ["Base URL: ", choice.baseUrl] }) : null, _jsxs(Text, { color: "gray", children: ["Examples: ", choice.exampleModels.join(", ")] })] }, choice.kind))) }), _jsx(Text, { color: "gray", children: "Up and down move through provider types. Enter confirms. Esc goes back." })] }));
|
|
172
229
|
}
|
|
173
230
|
if (mode === "connect-label" || mode === "connect-key" || mode === "connect-base-url") {
|
|
174
231
|
const label = mode === "connect-label"
|
|
@@ -180,7 +237,7 @@ function ProviderPanelView(props) {
|
|
|
180
237
|
? "Give this provider a simple name you will recognize later."
|
|
181
238
|
: mode === "connect-key"
|
|
182
239
|
? "This key stays on this device and is used for terminal Context work."
|
|
183
|
-
: "This is only needed
|
|
240
|
+
: "This is only needed when you chose the custom compatible provider option.";
|
|
184
241
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Connect a Provider" }), _jsx(Text, { color: "gray", children: help }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "yellow", children: label }), _jsx(TextInput, { value: connectDraftValue, onChange: onConnectDraftChange })] }), _jsx(Text, { color: "gray", children: "Press Enter to continue. Esc goes back one step." })] }));
|
|
185
242
|
}
|
|
186
243
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Provider Runtime" }), _jsx(Text, { color: "gray", children: "This is the device-side runtime picker for Context work." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Connected providers", value: String(providers.length) }), _jsx(StatusLine, { label: "Active provider", value: providers.find((entry) => entry.id === activeProviderId)?.name ?? "Not connected" }), _jsx(StatusLine, { label: "Active model", value: activeModel ?? "Not selected" }), _jsx(StatusLine, { label: "State", value: readinessState })] }), _jsx(Section, { title: "Select a Provider", children: providers.length === 0 ? (_jsx(Text, { color: "yellow", children: "No providers are connected yet. Press c to start the live connect flow." })) : providers.map((provider, index) => {
|
|
@@ -188,11 +245,11 @@ function ProviderPanelView(props) {
|
|
|
188
245
|
const active = provider.id === activeProviderId;
|
|
189
246
|
const recent = provider.id === recentProviderId;
|
|
190
247
|
return (_jsxs(Text, { color: highlighted ? "yellow" : active ? "green" : "white", children: [highlighted ? ">" : " ", " ", provider.name, " (", provider.kind, ")", active ? " (active)" : "", recent ? " (recent)" : ""] }, provider.id));
|
|
191
|
-
}) }), _jsx(Text, { color: "gray", children: "Up and down move through providers. Enter or w makes one active. c connects a new provider. d disconnects the highlighted one." }), _jsx(Text, { color: "gray", children: "t tests the runtime, i inspects the recent provider, g runs the full guided setup, and m jumps to models." })] }));
|
|
248
|
+
}) }), _jsx(Text, { color: "gray", children: "Providers are the AI companies, like OpenAI, Anthropic, Google, MiniMax, or OpenRouter." }), _jsx(Text, { color: "gray", children: "Up and down move through providers. Enter or w makes one active. c connects a new provider. d disconnects the highlighted one." }), _jsx(Text, { color: "gray", children: "t tests the runtime, i inspects the recent provider, g runs the full guided setup, and m jumps to models." })] }));
|
|
192
249
|
}
|
|
193
250
|
function ModelPanelView(props) {
|
|
194
251
|
const { activeModel, providerName, recentModel, selectedIndex, models } = props;
|
|
195
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Model Runtime" }), _jsx(Text, { color: "gray", children: "
|
|
252
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Model Runtime" }), _jsx(Text, { color: "gray", children: "Models are the specific AI brains offered by the active provider. First pick a provider, then pick the model you want it to use." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Provider", value: providerName }), _jsx(StatusLine, { label: "Active model", value: activeModel ?? "Not selected" }), _jsx(StatusLine, { label: "Available models", value: String(models.length) })] }), _jsx(Section, { title: "Select a Model", children: models.length === 0 ? (_jsx(Text, { color: "yellow", children: "No models are available for the active provider yet." })) : models.map((model, index) => {
|
|
196
253
|
const highlighted = index === selectedIndex;
|
|
197
254
|
const active = model === activeModel;
|
|
198
255
|
const recent = model === recentModel;
|
|
@@ -201,22 +258,22 @@ function ModelPanelView(props) {
|
|
|
201
258
|
}
|
|
202
259
|
function HubPanelView(props) {
|
|
203
260
|
const { installedSlugs, recentSlug, registryEntries, selectedIndex } = props;
|
|
204
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Hub" }), _jsx(Text, { color: "gray", children: "
|
|
261
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Hub" }), _jsx(Text, { color: "gray", children: "Hub is the install shelf for bigger repo packs. Think of it like bundles of reusable setup, skills, and connector kits." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Available entries", value: String(registryEntries.length) }), _jsx(StatusLine, { label: "Installed entries", value: String(installedSlugs.length) })] }), _jsx(Section, { title: "Browse Hub Registry", children: registryEntries.map((entry, index) => {
|
|
205
262
|
const highlighted = index === selectedIndex;
|
|
206
263
|
const installed = installedSlugs.includes(entry.slug);
|
|
207
264
|
const recent = recentSlug === entry.slug;
|
|
208
265
|
return (_jsxs(Text, { color: highlighted ? "yellow" : installed ? "green" : "white", children: [highlighted ? ">" : " ", " ", entry.name, " [", entry.type, "]", installed ? " (installed)" : "", recent ? " (recent)" : ""] }, entry.slug));
|
|
209
|
-
}) }), _jsx(Section, { title: "Selected Entry", children: registryEntries[selectedIndex] ? (_jsxs(_Fragment, { children: [_jsx(Text, { children: registryEntries[selectedIndex].description }), _jsxs(Text, { color: "gray", children: ["Includes: ", registryEntries[selectedIndex].includes.join(", ")] }), _jsxs(Text, { color: "gray", children: ["Next: ", registryEntries[selectedIndex].nextSteps[0] ?? "Review and install"] })] })) : (_jsx(Text, { color: "yellow", children: "No Hub entries are available right now." })) }), _jsx(Text, { color: "gray", children: "Up and down move through hub entries. Enter or n installs the selected entry. i inspects it. b opens the guided browse flow. l refreshes installed items." })] }));
|
|
266
|
+
}) }), _jsx(Section, { title: "Selected Entry", children: registryEntries[selectedIndex] ? (_jsxs(_Fragment, { children: [_jsx(Text, { children: registryEntries[selectedIndex].description }), _jsx(Text, { color: "gray", children: "A Hub entry can include more than one thing at once, like skills plus connectors plus setup files." }), _jsxs(Text, { color: "gray", children: ["Includes: ", registryEntries[selectedIndex].includes.join(", ")] }), _jsxs(Text, { color: "gray", children: ["Next: ", registryEntries[selectedIndex].nextSteps[0] ?? "Review and install"] })] })) : (_jsx(Text, { color: "yellow", children: "No Hub entries are available right now." })) }), _jsx(Text, { color: "gray", children: "Up and down move through hub entries. Enter or n installs the selected entry. i inspects it. b opens the guided browse flow. l refreshes installed items." })] }));
|
|
210
267
|
}
|
|
211
268
|
function ConnectorsPanelView(props) {
|
|
212
269
|
const { installedSources, recentSource, recentRunSource, registryEntries, selectedIndex } = props;
|
|
213
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Connectors" }), _jsx(Text, { color: "gray", children: "
|
|
270
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Connectors" }), _jsx(Text, { color: "gray", children: "A connector is a repo helper. MCP, rule, hook, and skill are the four connector types shown here." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Available connectors", value: String(registryEntries.length) }), _jsx(StatusLine, { label: "Installed connectors", value: String(installedSources.length) })] }), _jsx(Section, { title: "Browse Connector Registry", children: registryEntries.map((entry, index) => {
|
|
214
271
|
const highlighted = index === selectedIndex;
|
|
215
272
|
const installed = installedSources.includes(entry.key);
|
|
216
273
|
const recent = recentSource === entry.key;
|
|
217
274
|
const recentRun = recentRunSource === entry.key;
|
|
218
275
|
return (_jsxs(Text, { color: highlighted ? "yellow" : installed ? "green" : "white", children: [highlighted ? ">" : " ", " ", entry.name, " [", entry.type, "]", installed ? " (installed)" : "", recent ? " (recent)" : "", recentRun ? " (ran)" : ""] }, entry.key));
|
|
219
|
-
}) }), _jsx(Section, { title: "Selected Connector", children: registryEntries[selectedIndex] ? (_jsxs(_Fragment, { children: [_jsx(Text, { children: registryEntries[selectedIndex].description }), _jsxs(Text, { color: "gray", children: ["
|
|
276
|
+
}) }), _jsx(Section, { title: "Selected Connector", children: registryEntries[selectedIndex] ? (_jsxs(_Fragment, { children: [_jsx(Text, { children: registryEntries[selectedIndex].description }), _jsxs(Text, { color: "gray", children: ["Type: ", registryEntries[selectedIndex].type, ". This is one flavor of connector, not a separate product."] }), _jsx(Text, { color: "gray", children: "Next: install it, then run it to apply repo changes or stage local Context output." })] })) : (_jsx(Text, { color: "yellow", children: "No connector templates are available right now." })) }), _jsx(Text, { color: "gray", children: "Up and down move through connectors. Enter or i installs the selected connector. r runs it. o opens its outputs. v inspects the recent connector." })] }));
|
|
220
277
|
}
|
|
221
278
|
function TasksPanelView(props) {
|
|
222
279
|
const { mode, selectedIndex, tasks, transportStatus, queueLength, activeTaskId } = props;
|
|
@@ -247,14 +304,25 @@ function PanelShell({ activePanel, children, footer, message, navigationFocus, s
|
|
|
247
304
|
}
|
|
248
305
|
function SetupView(props) {
|
|
249
306
|
const { busyLabel, companies, config, authSnapshot, inputValue, message, onInputChange, selectedCompanyIndex, selectedServerChoiceIndex, selectedSpaceIndex, serverUrl, spaces, step, } = props;
|
|
250
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: config ? "Connected Device" : "Connect This Device" }), _jsx(Text, { color: "gray", children: "Sign into Umbrella, choose a company, then choose the team space for this repo." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Server", value: serverUrl || "Not set" }), _jsx(StatusLine, { label: "Step", value: step }), _jsx(StatusLine, { label: "Auth state", value: formatUmbrellaAuthStatus(authSnapshot.status) }), _jsx(StatusLine, { label: "Auth message", value: authSnapshot.message ?? "No auth check yet" }), _jsx(StatusLine, { label: "Auth hint", value: authSnapshot.hint ?? "No auth hint yet" }), config ? _jsx(StatusLine, { label: "Current link", value: `${config.companyName} / ${config.projectName}` }) : null] }), busyLabel ? (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "cyan", children: [_jsx(Spinner, { type: "dots" }), " ", busyLabel] }) })) : null, message ? (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "green", children: message }) })) : null, step === "server-choice" ? (_jsx(Section, { title: "Choose an Umbrella Server", children: SETUP_SERVER_CHOICES.map((choice, index) => (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { color: index === selectedServerChoiceIndex ? "yellow" : "white", children: [index === selectedServerChoiceIndex ? ">" : " ", " ", choice.title] }), _jsx(Text, { color: "gray", children: choice.description })] }, choice.value))) })) : null, (step === "server" || step === "email" || step === "password" || step === "company-create" || step === "space-create") ? (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "yellow", children: step === "server" ? "Server URL" :
|
|
307
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: config ? "Connected Device" : "Connect This Device" }), _jsx(Text, { color: "gray", children: "Sign into Umbrella, choose a company, then choose the team space for this repo." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Server", value: serverUrl || "Not set" }), _jsx(StatusLine, { label: "Step", value: step }), _jsx(StatusLine, { label: "Auth state", value: formatUmbrellaAuthStatus(authSnapshot.status) }), _jsx(StatusLine, { label: "Auth message", value: authSnapshot.message ?? "No auth check yet" }), _jsx(StatusLine, { label: "Auth hint", value: authSnapshot.hint ?? "No auth hint yet" }), config ? _jsx(StatusLine, { label: "Current link", value: `${config.companyName} / ${config.projectName}` }) : null, config?.umbrellaUrl ? _jsx(StatusLine, { label: "Saved app URL", value: config.umbrellaUrl }) : null, config ? _jsx(StatusLine, { label: "Saved backend URL", value: config.serverUrl }) : null] }), busyLabel ? (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "cyan", children: [_jsx(Spinner, { type: "dots" }), " ", busyLabel] }) })) : null, message ? (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "green", children: message }) })) : null, step === "server-choice" ? (_jsx(Section, { title: "Choose an Umbrella Server", children: SETUP_SERVER_CHOICES.map((choice, index) => (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { color: index === selectedServerChoiceIndex ? "yellow" : "white", children: [index === selectedServerChoiceIndex ? ">" : " ", " ", choice.title] }), _jsx(Text, { color: "gray", children: choice.description })] }, choice.value))) })) : null, (step === "server" || step === "email" || step === "password" || step === "company-create" || step === "space-create") ? (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "yellow", children: step === "server" ? "Server URL" :
|
|
251
308
|
step === "email" ? "Umbrella email" :
|
|
252
309
|
step === "password" ? "Umbrella password" :
|
|
253
310
|
step === "company-create" ? "New company name" :
|
|
254
|
-
"New space name" }), _jsx(TextInput, { value: inputValue, onChange: onInputChange })] })) : null, step === "company" ? (_jsxs(Section, { title: "Companies", children: [companies.map((company, index) => (_jsxs(Text, { color: index === selectedCompanyIndex ? "yellow" : "white", children: [index === selectedCompanyIndex ? ">" : " ", " ", company.name, " (", company.issuePrefix, ")"] }, company.id))), _jsxs(Text, { color: selectedCompanyIndex === companies.length ? "yellow" : "white", children: [selectedCompanyIndex === companies.length ? ">" : " ", " + Create new company"] })] })) : null, step === "space" ? (_jsxs(Section, { title: "Spaces", children: [spaces.map((space, index) => (_jsxs(Text, { color: index === selectedSpaceIndex ? "yellow" : "white", children: [index === selectedSpaceIndex ? ">" : " ", " ", space.name, space.isPrimary ? " (core)" : ""] }, space.id))), _jsxs(Text, { color: selectedSpaceIndex === spaces.length ? "yellow" : "white", children: [selectedSpaceIndex === spaces.length ? ">" : " ", " + Create new space"] })] })) : null, _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "gray", children: "Enter confirms the current step. Up and down move through server choices, companies, or spaces." }), _jsx(Text, { color: "gray", children: "Esc leaves setup.
|
|
311
|
+
"New space name" }), _jsx(TextInput, { value: inputValue, onChange: onInputChange, mask: step === "password" ? "*" : undefined })] })) : null, step === "company" ? (_jsxs(Section, { title: "Companies", children: [companies.map((company, index) => (_jsxs(Text, { color: index === selectedCompanyIndex ? "yellow" : "white", children: [index === selectedCompanyIndex ? ">" : " ", " ", company.name, " (", company.issuePrefix, ")"] }, company.id))), _jsxs(Text, { color: selectedCompanyIndex === companies.length ? "yellow" : "white", children: [selectedCompanyIndex === companies.length ? ">" : " ", " + Create new company"] })] })) : null, step === "space" ? (_jsxs(Section, { title: "Spaces", children: [spaces.map((space, index) => (_jsxs(Text, { color: index === selectedSpaceIndex ? "yellow" : "white", children: [index === selectedSpaceIndex ? ">" : " ", " ", space.name, space.isPrimary ? " (core)" : ""] }, space.id))), _jsxs(Text, { color: selectedSpaceIndex === spaces.length ? "yellow" : "white", children: [selectedSpaceIndex === spaces.length ? ">" : " ", " + Create new space"] })] })) : null, _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "gray", children: "Enter confirms the current step. Up and down move through server choices, companies, or spaces." }), _jsx(Text, { color: "gray", children: "Esc leaves setup. Press x to sign out on this device and start over from the beginning." })] })] }));
|
|
255
312
|
}
|
|
256
313
|
function App() {
|
|
257
314
|
const { exit } = useApp();
|
|
315
|
+
const initialConfig = configManager.config;
|
|
316
|
+
const initialAuthSnapshot = getStoredUmbrellaAuthSnapshot();
|
|
317
|
+
const initialConnectionPresentation = initialConfig
|
|
318
|
+
? buildConnectionPresentation({
|
|
319
|
+
umbrellaUrl: initialConfig.umbrellaUrl ?? undefined,
|
|
320
|
+
serverUrl: initialConfig.serverUrl,
|
|
321
|
+
}, initialAuthSnapshot)
|
|
322
|
+
: null;
|
|
323
|
+
const needsSetupRepair = !initialConfig ||
|
|
324
|
+
(initialConnectionPresentation?.connectionMode === "saved_local_config" ||
|
|
325
|
+
(initialConnectionPresentation?.warnings.length ?? 0) > 0);
|
|
258
326
|
const vendorTaskStore = useUmbrellaTransportTaskBridgeStore((state) => state.taskStore);
|
|
259
327
|
const vendorTransportStore = useUmbrellaTransportTaskBridgeStore((state) => state.transportStore);
|
|
260
328
|
const vendorTreeStore = useUmbrellaContextRuntimeBridgeStore((state) => state.treeStore);
|
|
@@ -264,7 +332,7 @@ function App() {
|
|
|
264
332
|
const vendorHubStore = useUmbrellaContextRuntimeBridgeStore((state) => state.hubStore);
|
|
265
333
|
const vendorConnectorsStore = useUmbrellaContextRuntimeBridgeStore((state) => state.connectorsStore);
|
|
266
334
|
const [selectedPanelIndex, setSelectedPanelIndex] = useState(0);
|
|
267
|
-
const [activePanel, setActivePanel] = useState(
|
|
335
|
+
const [activePanel, setActivePanel] = useState(needsSetupRepair ? "setup" : "home");
|
|
268
336
|
const [navigationFocus, setNavigationFocus] = useState("sidebar");
|
|
269
337
|
const [refreshTick, setRefreshTick] = useState(0);
|
|
270
338
|
const [message, setMessage] = useState(null);
|
|
@@ -273,11 +341,12 @@ function App() {
|
|
|
273
341
|
const [inputValue, setInputValue] = useState("");
|
|
274
342
|
const [queryResult, setQueryResult] = useState(null);
|
|
275
343
|
const [refreshState, setRefreshState] = useState(null);
|
|
276
|
-
const [
|
|
277
|
-
const [
|
|
278
|
-
const [
|
|
344
|
+
const [refreshError, setRefreshError] = useState(null);
|
|
345
|
+
const [setupStep, setSetupStep] = useState(needsSetupRepair ? "server-choice" : "done");
|
|
346
|
+
const [serverUrl, setServerUrl] = useState(initialConfig?.umbrellaUrl ?? initialConfig?.serverUrl ?? DEFAULT_UMBRELLA_SERVER_URL);
|
|
347
|
+
const [selectedServerChoiceIndex, setSelectedServerChoiceIndex] = useState(inferSetupServerChoiceIndex(initialConfig?.umbrellaUrl ?? initialConfig?.serverUrl ?? null));
|
|
279
348
|
const [setupEmail, setSetupEmail] = useState("");
|
|
280
|
-
const [authSnapshot, setAuthSnapshot] = useState(
|
|
349
|
+
const [authSnapshot, setAuthSnapshot] = useState(initialAuthSnapshot);
|
|
281
350
|
const [setupCookie, setSetupCookie] = useState(null);
|
|
282
351
|
const [companies, setCompanies] = useState([]);
|
|
283
352
|
const [selectedCompanyIndex, setSelectedCompanyIndex] = useState(0);
|
|
@@ -304,11 +373,52 @@ function App() {
|
|
|
304
373
|
const [tasksPanelSelectedIndex, setTasksPanelSelectedIndex] = useState(0);
|
|
305
374
|
const [activityPanelMode, setActivityPanelMode] = useState("browse");
|
|
306
375
|
const [activityPanelSelectedIndex, setActivityPanelSelectedIndex] = useState(0);
|
|
376
|
+
const [sessionPanelSelectedIndex, setSessionPanelSelectedIndex] = useState(0);
|
|
307
377
|
function focusPanel(panelId, focus = "sidebar") {
|
|
308
378
|
setActivePanel(panelId);
|
|
309
379
|
setSelectedPanelIndex(panelIndexFor(panelId));
|
|
310
380
|
setNavigationFocus(focus);
|
|
311
381
|
}
|
|
382
|
+
function restartSetupFlow() {
|
|
383
|
+
const currentConfig = configManager.config;
|
|
384
|
+
const nextServerUrl = currentConfig?.umbrellaUrl ?? currentConfig?.serverUrl ?? DEFAULT_UMBRELLA_SERVER_URL;
|
|
385
|
+
setSetupStep("server-choice");
|
|
386
|
+
setServerUrl(nextServerUrl);
|
|
387
|
+
setSelectedServerChoiceIndex(inferSetupServerChoiceIndex(nextServerUrl));
|
|
388
|
+
setSetupEmail("");
|
|
389
|
+
setSetupCookie(null);
|
|
390
|
+
setCompanies([]);
|
|
391
|
+
setSelectedCompanyIndex(0);
|
|
392
|
+
setSpaces([]);
|
|
393
|
+
setSelectedSpaceIndex(0);
|
|
394
|
+
setSelectedCompany(null);
|
|
395
|
+
setInputValue("");
|
|
396
|
+
setBusyLabel(null);
|
|
397
|
+
setMessage(currentConfig
|
|
398
|
+
? "Choose the Umbrella server you want to use for this device. This will repair the saved link."
|
|
399
|
+
: "Choose the Umbrella server you want to use for this device.");
|
|
400
|
+
focusPanel("setup", "panel");
|
|
401
|
+
}
|
|
402
|
+
async function signOutAndRestartSetup() {
|
|
403
|
+
configManager.clearUmbrellaSession();
|
|
404
|
+
configManager.clearAuthSnapshot();
|
|
405
|
+
setAuthSnapshot(createDefaultUmbrellaAuthSnapshot());
|
|
406
|
+
setRefreshTick((value) => value + 1);
|
|
407
|
+
restartSetupFlow();
|
|
408
|
+
setMessage("This device was signed out. Choose the Umbrella server you want to use and start over.");
|
|
409
|
+
}
|
|
410
|
+
async function runSessionAction(actionId) {
|
|
411
|
+
if (actionId === "repair-setup") {
|
|
412
|
+
restartSetupFlow();
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
if (actionId === "switch-space") {
|
|
416
|
+
focusPanel("spaces", "panel");
|
|
417
|
+
setMessage("Opened Spaces so you can choose a different space inside the current company.");
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
await signOutAndRestartSetup();
|
|
421
|
+
}
|
|
312
422
|
async function refreshAll() {
|
|
313
423
|
try {
|
|
314
424
|
if (configManager.config) {
|
|
@@ -318,7 +428,7 @@ function App() {
|
|
|
318
428
|
const vendorSnapshot = await buildVendorRuntimeBridgeSnapshot();
|
|
319
429
|
hydrateUmbrellaTransportTaskBridgeFromSnapshot(vendorSnapshot);
|
|
320
430
|
hydrateUmbrellaContextRuntimeBridgeFromSnapshot(vendorSnapshot);
|
|
321
|
-
const [transport, treeState, pending, pulled, fixes, connectors, hubEntries, connectorRuns, session, repoContext, tasks] = await Promise.all([
|
|
431
|
+
const [transport, treeState, pending, pulled, fixes, connectors, hubEntries, connectorRuns, session, repoContext, tasks, swarm, repoResolution, worktrees, sources, adaptive] = await Promise.all([
|
|
322
432
|
getTransportState(),
|
|
323
433
|
getContextTreeState(),
|
|
324
434
|
getPendingMemories(),
|
|
@@ -330,6 +440,11 @@ function App() {
|
|
|
330
440
|
ensureSessionState(),
|
|
331
441
|
getRepoContext(),
|
|
332
442
|
getTasks(),
|
|
443
|
+
getSwarmStatus(),
|
|
444
|
+
getRepoResolution(),
|
|
445
|
+
listRegisteredWorktrees(),
|
|
446
|
+
listKnowledgeSources(),
|
|
447
|
+
getAdaptiveKnowledgeSummary(),
|
|
333
448
|
]);
|
|
334
449
|
setRefreshState({
|
|
335
450
|
transport,
|
|
@@ -343,10 +458,17 @@ function App() {
|
|
|
343
458
|
session,
|
|
344
459
|
repoContext,
|
|
345
460
|
tasks,
|
|
461
|
+
swarm,
|
|
462
|
+
repoResolution,
|
|
463
|
+
worktrees,
|
|
464
|
+
sources,
|
|
465
|
+
adaptive,
|
|
346
466
|
activity: buildActivityItems(vendorSnapshot.stores.transport, session.events ?? []),
|
|
347
467
|
});
|
|
468
|
+
setRefreshError(null);
|
|
348
469
|
}
|
|
349
|
-
catch {
|
|
470
|
+
catch (error) {
|
|
471
|
+
setRefreshError(error instanceof Error ? error.message : "Unknown refresh error");
|
|
350
472
|
setRefreshState(null);
|
|
351
473
|
}
|
|
352
474
|
}
|
|
@@ -855,7 +977,12 @@ function App() {
|
|
|
855
977
|
const choice = UMBRELLA_PROVIDER_CHOICES[providerPanelConnectKindIndex];
|
|
856
978
|
if (!choice)
|
|
857
979
|
return;
|
|
858
|
-
setProviderPanelConnectDraft((value) => ({
|
|
980
|
+
setProviderPanelConnectDraft((value) => ({
|
|
981
|
+
...value,
|
|
982
|
+
kind: choice.kind,
|
|
983
|
+
label: choice.suggestedLabel,
|
|
984
|
+
baseUrl: choice.baseUrl ?? "",
|
|
985
|
+
}));
|
|
859
986
|
setProviderPanelMode("connect-label");
|
|
860
987
|
return;
|
|
861
988
|
}
|
|
@@ -891,7 +1018,7 @@ function App() {
|
|
|
891
1018
|
return;
|
|
892
1019
|
}
|
|
893
1020
|
setProviderPanelConnectDraft((value) => ({ ...value, apiKey: nextKey }));
|
|
894
|
-
if (providerPanelConnectDraft.kind
|
|
1021
|
+
if (getProviderChoice(providerPanelConnectDraft.kind)?.requiresBaseUrlInput) {
|
|
895
1022
|
setProviderPanelMode("connect-base-url");
|
|
896
1023
|
}
|
|
897
1024
|
else {
|
|
@@ -980,7 +1107,7 @@ function App() {
|
|
|
980
1107
|
setMessage(`Opened ${PANELS[selectedPanelIndex]?.title ?? "panel"}.`);
|
|
981
1108
|
return;
|
|
982
1109
|
}
|
|
983
|
-
const shortcutPanel = panelForShortcut(input);
|
|
1110
|
+
const shortcutPanel = navigationFocus === "sidebar" ? panelForShortcut(input) : null;
|
|
984
1111
|
if (shortcutPanel && activePanel !== "setup") {
|
|
985
1112
|
focusPanel(shortcutPanel, "panel");
|
|
986
1113
|
setMessage(`Jumped to ${PANELS[panelIndexFor(shortcutPanel)]?.title ?? shortcutPanel}.`);
|
|
@@ -1038,9 +1165,11 @@ function App() {
|
|
|
1038
1165
|
return;
|
|
1039
1166
|
}
|
|
1040
1167
|
if (input === "s") {
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1168
|
+
restartSetupFlow();
|
|
1169
|
+
return;
|
|
1170
|
+
}
|
|
1171
|
+
if (input === "x") {
|
|
1172
|
+
void signOutAndRestartSetup();
|
|
1044
1173
|
return;
|
|
1045
1174
|
}
|
|
1046
1175
|
if (activePanel === "providers") {
|
|
@@ -1177,6 +1306,31 @@ function App() {
|
|
|
1177
1306
|
return;
|
|
1178
1307
|
}
|
|
1179
1308
|
}
|
|
1309
|
+
if (activePanel === "session") {
|
|
1310
|
+
if (navigationFocus === "sidebar")
|
|
1311
|
+
return;
|
|
1312
|
+
if (key.upArrow || input === "k") {
|
|
1313
|
+
setSessionPanelSelectedIndex((value) => Math.max(0, value - 1));
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
if (key.downArrow || input === "j") {
|
|
1317
|
+
setSessionPanelSelectedIndex((value) => Math.min(SESSION_ACTIONS.length - 1, value + 1));
|
|
1318
|
+
return;
|
|
1319
|
+
}
|
|
1320
|
+
if (key.return || input === "o") {
|
|
1321
|
+
const action = SESSION_ACTIONS[sessionPanelSelectedIndex];
|
|
1322
|
+
if (!action)
|
|
1323
|
+
return;
|
|
1324
|
+
if (action.id === "sign-out") {
|
|
1325
|
+
void runPanelAction("Signing out this device...", async () => {
|
|
1326
|
+
await runSessionAction(action.id);
|
|
1327
|
+
}, "Signed out this device and restarted setup.");
|
|
1328
|
+
return;
|
|
1329
|
+
}
|
|
1330
|
+
void runSessionAction(action.id);
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1180
1334
|
if (activePanel === "tasks") {
|
|
1181
1335
|
if (key.escape) {
|
|
1182
1336
|
if (tasksPanelMode === "inspect") {
|
|
@@ -1436,45 +1590,58 @@ function App() {
|
|
|
1436
1590
|
? navigationFocus === "sidebar"
|
|
1437
1591
|
? "Sidebar focus: Up/Down choose panel | Enter, Right, or Tab opens it | [ ] cycle panels | 1-9 or h/t/a/v/m/w/b/c/u jumps panels | ? query | + curate | p push | l pull | s setup | q quit"
|
|
1438
1592
|
: "Spaces: Enter or w switch | n create | i refresh | Esc or Left returns to sidebar | ? query | + curate | q quit"
|
|
1439
|
-
: activePanel === "
|
|
1440
|
-
?
|
|
1441
|
-
?
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
: activePanel === "connectors"
|
|
1446
|
-
? connectorsPanelMode === "browse"
|
|
1593
|
+
: activePanel === "session"
|
|
1594
|
+
? navigationFocus === "sidebar"
|
|
1595
|
+
? "Sidebar focus: Up/Down choose panel | Enter, Right, or Tab opens it | [ ] cycle panels | 1-9 or h/t/a/v/m/w/b/c/u jumps panels | ? query | + curate | p push | l pull | s setup | x sign out/start over | q quit"
|
|
1596
|
+
: "Session: Up/Down choose action | Enter or o runs it | Use this panel to inspect server, company, and space info | Esc or Left returns to sidebar | q quit"
|
|
1597
|
+
: activePanel === "hub"
|
|
1598
|
+
? hubPanelMode === "browse"
|
|
1447
1599
|
? navigationFocus === "sidebar"
|
|
1448
1600
|
? "Sidebar focus: Up/Down choose panel | Enter, Right, or Tab opens it | [ ] cycle panels | 1-9 or h/t/a/v/m/w/b/c/u jumps panels | ? query | + curate | p push | l pull | s setup | q quit"
|
|
1449
|
-
: "
|
|
1450
|
-
: "
|
|
1451
|
-
: activePanel === "
|
|
1452
|
-
?
|
|
1601
|
+
: "Hub: Up/Down choose | Enter or n install | i inspect | b guided browse | l refresh | Esc or Left returns to sidebar | ? query | + curate | q quit"
|
|
1602
|
+
: "Hub live panel"
|
|
1603
|
+
: activePanel === "connectors"
|
|
1604
|
+
? connectorsPanelMode === "browse"
|
|
1453
1605
|
? navigationFocus === "sidebar"
|
|
1454
|
-
? "Sidebar focus: Up/Down choose panel | Enter, Right, or Tab opens
|
|
1455
|
-
: "
|
|
1456
|
-
: "
|
|
1457
|
-
: activePanel === "
|
|
1458
|
-
?
|
|
1606
|
+
? "Sidebar focus: Up/Down choose panel | Enter, Right, or Tab opens it | [ ] cycle panels | 1-9 or h/t/a/v/m/w/b/c/u jumps panels | ? query | + curate | p push | l pull | s setup | q quit"
|
|
1607
|
+
: "Connectors: Up/Down choose | Enter or i install | r run | o outputs | v inspect | Esc or Left returns to sidebar | ? query | + curate | q quit"
|
|
1608
|
+
: "Connectors live panel"
|
|
1609
|
+
: activePanel === "tasks"
|
|
1610
|
+
? tasksPanelMode === "browse"
|
|
1459
1611
|
? navigationFocus === "sidebar"
|
|
1460
|
-
? "Sidebar focus: Up/Down choose panel | Enter, Right, or Tab opens
|
|
1461
|
-
: "
|
|
1462
|
-
: "
|
|
1463
|
-
:
|
|
1612
|
+
? "Sidebar focus: Up/Down choose panel | Enter, Right, or Tab opens tasks | [ ] cycle panels | 1-9 or h/t/a/v/m/w/b/c/u jumps panels | ? query | + curate | p push | l pull | s setup | q quit"
|
|
1613
|
+
: "Tasks: Up/Down choose | Enter or i inspect | o open related panel | Esc or Left returns to sidebar | r refresh | ? query | + curate | q quit"
|
|
1614
|
+
: "Tasks inspect: Esc goes back to the task list | Enter or o opens related panel | Left returns to sidebar | r refresh | ? query | + curate | q quit"
|
|
1615
|
+
: activePanel === "activity"
|
|
1616
|
+
? activityPanelMode === "browse"
|
|
1617
|
+
? navigationFocus === "sidebar"
|
|
1618
|
+
? "Sidebar focus: Up/Down choose panel | Enter, Right, or Tab opens activity | [ ] cycle panels | 1-9 or h/t/a/v/m/w/b/c/u jumps panels | ? query | + curate | p push | l pull | s setup | q quit"
|
|
1619
|
+
: "Activity: Up/Down choose | Enter or i inspect | o open related panel | Esc or Left returns to sidebar | r refresh | ? query | + curate | q quit"
|
|
1620
|
+
: "Activity inspect: Esc goes back to the event list | Left returns to sidebar | Enter or o opens related panel | r refresh | ? query | + curate | q quit"
|
|
1621
|
+
: "Sidebar focus: Up/Down or j/k move panels | Enter, Right, or Tab opens a panel | [ ] cycle panels | 1-9 or h/t/a/v/m/w/b/c/u jumps panels | ? query | + curate | p push | l pull | r refresh | s setup | x sign out/start over | q quit";
|
|
1464
1622
|
const config = configManager.config;
|
|
1465
1623
|
let mainContent = null;
|
|
1466
1624
|
if (activePanel === "setup") {
|
|
1467
1625
|
mainContent = (_jsx(SetupView, { authSnapshot: authSnapshot, busyLabel: busyLabel, companies: companies, config: config, inputValue: inputValue, message: message, onInputChange: setInputValue, selectedCompanyIndex: selectedCompanyIndex, selectedServerChoiceIndex: selectedServerChoiceIndex, selectedSpaceIndex: selectedSpaceIndex, serverUrl: serverUrl, spaces: spaces, step: setupStep }));
|
|
1468
1626
|
}
|
|
1469
|
-
else if (!config
|
|
1627
|
+
else if (!config) {
|
|
1470
1628
|
mainContent = (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "yellow", children: "This terminal app can open before live sign-in is finished." }), _jsx(Text, { color: "gray", children: "Right now this repo is not fully linked to a company and space yet." }), _jsx(Text, { color: "gray", children: "Open Setup and finish the device link before you expect shared server context to work." })] }));
|
|
1471
1629
|
}
|
|
1630
|
+
else if (!refreshState) {
|
|
1631
|
+
mainContent = (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "yellow", children: "Refreshing the linked repo Context\u2026" }), _jsxs(Text, { color: "gray", children: ["Saved link: ", config.companyName, " / ", config.projectName] }), _jsxs(Text, { color: "gray", children: ["Server: ", config.umbrellaUrl ?? config.serverUrl] }), _jsx(Text, { color: "gray", children: "This device is linked. Press r to refresh if this takes more than a moment." }), refreshError ? _jsxs(Text, { color: "red", children: ["Refresh detail: ", refreshError] }) : null] }));
|
|
1632
|
+
}
|
|
1472
1633
|
else if (activePanel === "home") {
|
|
1473
|
-
mainContent = (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { bold: true, children: [config.companyName, " / ", config.projectName] }), _jsx(Text, { color: "gray", children: "This is the repo-level Context home for the current company space." }), _jsx(Text, { color: "gray", children: "The TUI is local-first: it reads this repo's .um folder even before the live server is queried." }), connectionPresentation ? (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: connectionPresentation.connectionMode === "verified_live_connection" ? "green" : "yellow", children: connectionPresentation.connectionMode === "verified_live_connection"
|
|
1634
|
+
mainContent = (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { bold: true, children: [config.companyName, " / ", config.projectName] }), _jsx(Text, { color: "gray", children: "This is the repo-level Context home for the current company space." }), refreshError ? _jsxs(Text, { color: "yellow", children: ["Last refresh had a hiccup: ", refreshError] }) : null, _jsx(Text, { color: "gray", children: "The TUI is local-first: it reads this repo's .um folder even before the live server is queried." }), connectionPresentation ? (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: connectionPresentation.connectionMode === "verified_live_connection" ? "green" : "yellow", children: connectionPresentation.connectionMode === "verified_live_connection"
|
|
1474
1635
|
? "Live connection verified"
|
|
1475
|
-
: "Saved local setup only" }), _jsx(Text, { color: "gray", children: connectionPresentation.connectionSummary }), connectionPresentation.warnings.map((warning) => (_jsxs(Text, { color: "yellow", children: ["- ", warning] }, warning)))] })) : null, _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Section, { title: "Connection", children: [_jsx(StatusLine, { label: "Umbrella
|
|
1636
|
+
: "Saved local setup only" }), _jsx(Text, { color: "gray", children: connectionPresentation.connectionSummary }), connectionPresentation.warnings.map((warning) => (_jsxs(Text, { color: "yellow", children: ["- ", warning] }, warning)))] })) : null, _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Section, { title: "Connection", children: [_jsx(StatusLine, { label: "Umbrella app URL", value: config.umbrellaUrl ?? "Not saved" }), _jsx(StatusLine, { label: "Context backend URL", value: config.serverUrl }), _jsx(StatusLine, { label: "Saved company link", value: `${config.companyName} / ${config.projectName}` }), _jsx(StatusLine, { label: "Auth state", value: formatUmbrellaAuthStatus(connectionPresentation?.authSnapshot.status ?? authSnapshot.status) }), _jsx(StatusLine, { label: "Shared API key", value: config.apiKey ? "Saved" : "Missing" }), _jsx(StatusLine, { label: "Connection mode", value: connectionPresentation?.connectionMode === "verified_live_connection"
|
|
1476
1637
|
? "Verified live connection"
|
|
1477
|
-
: "Saved local config only" })] }), _jsxs(Section, { title: "Sync", children: [_jsx(StatusLine, { label: "Pending drafts", value: String(refreshState.pending.length) }), _jsx(StatusLine, { label: "Pulled context", value: String(refreshState.pulled.length) }), _jsx(StatusLine, { label: "Known fixes", value: String(refreshState.fixes.length) }), _jsx(StatusLine, { label: "Last push", value: formatAgo(refreshState.repoContext.state?.lastPushAt) }), _jsx(StatusLine, { label: "Last pull", value: formatAgo(refreshState.repoContext.state?.lastPullAt) })] }), _jsxs(Section, { title: "Runtime", children: [_jsx(StatusLine, { label: "Provider", value: readiness.activeProvider?.name ?? "Not connected" }), _jsx(StatusLine, { label: "Model", value: readiness.activeModel ?? "Not selected" }), _jsx(StatusLine, { label: "Transport", value: vendorTransportStore?.status ?? refreshState.transport.status }), _jsx(StatusLine, { label: "Repo .um", value: refreshState.repoContext.umDir })] }), _jsxs(Section, { title: "
|
|
1638
|
+
: "Saved local config only" })] }), _jsxs(Section, { title: "Sync", children: [_jsx(StatusLine, { label: "Pending drafts", value: String(refreshState.pending.length) }), _jsx(StatusLine, { label: "Pulled context", value: String(refreshState.pulled.length) }), _jsx(StatusLine, { label: "Known fixes", value: String(refreshState.fixes.length) }), _jsx(StatusLine, { label: "Last push", value: formatAgo(refreshState.repoContext.state?.lastPushAt) }), _jsx(StatusLine, { label: "Last pull", value: formatAgo(refreshState.repoContext.state?.lastPullAt) })] }), _jsxs(Section, { title: "Runtime", children: [_jsx(StatusLine, { label: "Provider", value: readiness.activeProvider?.name ?? "Not connected" }), _jsx(StatusLine, { label: "Model", value: readiness.activeModel ?? "Not selected" }), _jsx(StatusLine, { label: "Transport", value: vendorTransportStore?.status ?? refreshState.transport.status }), _jsx(StatusLine, { label: "Repo .um", value: refreshState.repoContext.umDir }), _jsx(StatusLine, { label: "Repo mode", value: refreshState.repoResolution.mode === "linked" ? "Linked worktree" : "Direct project" })] }), _jsxs(Section, { title: "Workspace Links", children: [_jsx(StatusLine, { label: "Registered worktrees", value: String(refreshState.worktrees.length) }), _jsx(StatusLine, { label: "Knowledge sources", value: String(refreshState.sources.length) }), _jsx(StatusLine, { label: "Cross-repo search", value: getSwarmReadinessLabel(refreshState.swarm, refreshState.sources.length) }), _jsx(StatusLine, { label: "Worktree names", value: summarizeNames(refreshState.worktrees.map((entry) => entry.name), "None") }), _jsx(StatusLine, { label: "Source aliases", value: summarizeNames(refreshState.sources.map((entry) => entry.alias), "None") }), _jsx(Text, { color: "gray", children: "Worktrees are extra folders that point back to this main repo. Sources are read-only Umbrella repos that swarm can search beside this repo." }), _jsx(Text, { color: "gray", children: "Use: umbrella-context worktree add/list/remove and umbrella-context source add/list/remove." })] }), _jsxs(Section, { title: "Adaptive Knowledge", children: [_jsx(StatusLine, { label: "Entries with abstracts", value: String(refreshState.adaptive.entryCount) }), _jsx(StatusLine, { label: "Last refresh", value: formatAgo(refreshState.adaptive.generatedAt) }), _jsx(StatusLine, { label: "Hottest note", value: refreshState.adaptive.hottestEntries[0]?.title ?? "None yet" })] }), _jsxs(Section, { title: "Swarm", children: [_jsx(StatusLine, { label: "Configured", value: refreshState.swarm.configured ? "Yes" : "No" }), _jsx(StatusLine, { label: "Mode", value: !refreshState.swarm.configured
|
|
1639
|
+
? "Off"
|
|
1640
|
+
: isAutoBootstrappedSwarm(refreshState.swarm)
|
|
1641
|
+
? "Auto-ready from linked sources"
|
|
1642
|
+
: "Custom onboarded setup" }), _jsx(StatusLine, { label: "Healthy providers", value: `${getSwarmHealthyCount(refreshState.swarm)} / ${refreshState.swarm.providers.length}` }), _jsx(StatusLine, { label: "Writable providers", value: String(getSwarmWritableCount(refreshState.swarm)) }), _jsx(StatusLine, { label: "Config file", value: refreshState.swarm.configPath }), _jsx(StatusLine, { label: "Searching now", value: summarizeNames(refreshState.swarm.providers.map((provider) => provider.label), "Umbrella Context only") }), refreshState.sources.length > 0 ? (_jsx(Text, { color: hasLiveSourceProvider(refreshState.swarm) ? "green" : "yellow", children: hasLiveSourceProvider(refreshState.swarm)
|
|
1643
|
+
? "Linked source repos are already live in swarm search."
|
|
1644
|
+
: "This repo has linked sources, but swarm still needs one more setup step before they can be searched." })) : (_jsx(Text, { color: "gray", children: "Add a source repo when you want this repo to search another Umbrella repo too." })), refreshState.swarm.suggestions.slice(0, 2).map((suggestion) => (_jsx(Text, { color: "gray", children: suggestion }, suggestion)))] }), _jsxs(Section, { title: "Context Tree", children: [_jsx(StatusLine, { label: "Summary", value: vendorTreeStore?.summaryHandle ?? refreshState.treeState.summaryHandle }), _jsx(StatusLine, { label: "Nodes", value: String(vendorTreeStore?.nodes.length ?? refreshState.treeState.nodes.length) }), _jsx(StatusLine, { label: "Runtime provider", value: vendorTreeStore?.runtime.provider ?? "No provider" }), _jsx(StatusLine, { label: "Runtime model", value: vendorTreeStore?.runtime.model ?? "No model" })] }), queryResult ? (_jsxs(Section, { title: `Latest Query: ${queryResult.query}`, children: [_jsxs(Text, { children: ["Local matches: ", String(queryResult.localMatches.length)] }), _jsxs(Text, { children: ["Shared matches: ", String(queryResult.remoteMatches.length)] })] })) : null, connectionPresentation?.connectionMode === "saved_local_config" ? (_jsxs(Section, { title: "Next Step", children: [_jsx(Text, { color: "yellow", children: "Run setup again before you trust shared server actions for this repo." }), _jsx(Text, { color: "gray", children: "Press x if you want to sign out on this device and start over from the beginning." })] })) : null] })] }));
|
|
1478
1645
|
}
|
|
1479
1646
|
else if (activePanel === "tasks") {
|
|
1480
1647
|
mainContent = (_jsx(TasksPanelView, { mode: tasksPanelMode, selectedIndex: tasksPanelSelectedIndex, tasks: vendorTasks, transportStatus: vendorTransportStore?.status ?? vendorTransportSummary.transportStatus, queueLength: vendorTransportStore?.queue.length ?? vendorTransportSummary.queueDepth, activeTaskId: vendorTransportStore?.queue[0]?.id ??
|
|
@@ -1506,7 +1673,11 @@ function App() {
|
|
|
1506
1673
|
mainContent = (_jsx(ConnectorsPanelView, { installedSources: vendorConnectorsStore?.installedSources ?? [], recentSource: vendorConnectorsStore?.recentSource ?? null, recentRunSource: vendorConnectorsStore?.recentRunSource ?? null, registryEntries: registryEntries, selectedIndex: connectorsPanelSelectedIndex }));
|
|
1507
1674
|
}
|
|
1508
1675
|
else {
|
|
1509
|
-
mainContent = (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Session Memory" }), _jsx(Text, { color: "gray", children: "
|
|
1676
|
+
mainContent = (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Session Memory" }), _jsx(Text, { color: "gray", children: "Session is the control room for this device and this repo. It shows what is saved, what is active now, and what the local runtime has been doing." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Session ID", value: refreshState.session?.id ?? "None" }), _jsx(StatusLine, { label: "Current panel", value: refreshState.session?.currentPanel ?? "None" }), _jsx(StatusLine, { label: "Current focus", value: refreshState.session?.currentFocus ?? "None" }), _jsx(StatusLine, { label: "Commands", value: String(refreshState.session?.commandHistory.length ?? 0) }), _jsx(StatusLine, { label: "Events", value: String(refreshState.session?.events.length ?? 0) }), _jsx(StatusLine, { label: "Transport", value: vendorTransportStore?.status ?? refreshState.transport.status }), _jsx(StatusLine, { label: "Tree summary", value: vendorTreeStore?.summaryHandle ?? refreshState.treeState.summaryHandle })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Section, { title: "Swarm", children: [_jsx(StatusLine, { label: "Configured", value: refreshState.swarm.configured ? "Yes" : "No" }), _jsx(StatusLine, { label: "Mode", value: !refreshState.swarm.configured
|
|
1677
|
+
? "Off"
|
|
1678
|
+
: isAutoBootstrappedSwarm(refreshState.swarm)
|
|
1679
|
+
? "Auto-ready from linked sources"
|
|
1680
|
+
: "Custom onboarded setup" }), _jsx(StatusLine, { label: "Healthy providers", value: `${getSwarmHealthyCount(refreshState.swarm)} / ${refreshState.swarm.providers.length}` }), _jsx(StatusLine, { label: "Writable providers", value: String(getSwarmWritableCount(refreshState.swarm)) }), _jsx(StatusLine, { label: "Searching now", value: summarizeNames(refreshState.swarm.providers.map((provider) => provider.label), "Umbrella Context only") }), _jsx(Text, { color: "gray", children: "Use: umbrella-context swarm onboard, swarm status, swarm query, and swarm curate." }), refreshState.swarm.suggestions.slice(0, 2).map((suggestion) => (_jsx(Text, { color: "gray", children: suggestion }, suggestion)))] }), _jsxs(Section, { title: "Workspace Links", children: [_jsx(StatusLine, { label: "Repo mode", value: refreshState.repoResolution.mode === "linked" ? "Linked worktree" : "Direct project" }), _jsx(StatusLine, { label: "Registered worktrees", value: String(refreshState.worktrees.length) }), _jsx(StatusLine, { label: "Knowledge sources", value: String(refreshState.sources.length) }), _jsx(StatusLine, { label: "Cross-repo search", value: getSwarmReadinessLabel(refreshState.swarm, refreshState.sources.length) }), _jsx(StatusLine, { label: "Worktree names", value: summarizeNames(refreshState.worktrees.map((entry) => entry.name), "None") }), _jsx(StatusLine, { label: "Source aliases", value: summarizeNames(refreshState.sources.map((entry) => entry.alias), "None") }), _jsx(Text, { color: "gray", children: "Sources are read-only Umbrella repos that swarm can search beside this one." })] }), _jsxs(Section, { title: "Adaptive Knowledge", children: [_jsx(StatusLine, { label: "Entries with abstracts", value: String(refreshState.adaptive.entryCount) }), _jsx(StatusLine, { label: "Last refresh", value: formatAgo(refreshState.adaptive.generatedAt) }), _jsx(Text, { color: "gray", children: "Frequently used notes get a hotness boost so the most useful saved context rises first." })] }), _jsxs(Section, { title: "Saved Device Setup", children: [_jsx(StatusLine, { label: "Umbrella app URL", value: config?.umbrellaUrl ?? "Not saved" }), _jsx(StatusLine, { label: "Context backend URL", value: config?.serverUrl ?? "Not saved" }), _jsx(StatusLine, { label: "Saved company link", value: config ? `${config.companyName} / ${config.projectName}` : "Not saved" }), _jsx(StatusLine, { label: "Auth state", value: formatUmbrellaAuthStatus(connectionPresentation?.authSnapshot.status ?? authSnapshot.status) }), _jsx(Text, { color: "gray", children: "This is what this computer is signed into right now." })] }), _jsxs(Section, { title: "Connection Actions", children: [SESSION_ACTIONS.map((action, index) => (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { color: index === sessionPanelSelectedIndex ? "yellow" : "white", children: [index === sessionPanelSelectedIndex ? ">" : " ", " ", action.title] }), _jsx(Text, { color: "gray", children: action.description })] }, action.id))), _jsx(Text, { color: "gray", children: "Enter runs the selected action. \"Repair setup\" is how you switch server or company. \"Switch space\" stays inside the current company." }), _jsx(Text, { color: "gray", children: "You can still run: umbrella-context logout" })] }), _jsxs(Section, { title: "Transport and Tasks", children: [_jsx(StatusLine, { label: "Queue depth", value: String(vendorTransportStore?.queue.length ?? 0) }), _jsx(StatusLine, { label: "Recent tasks", value: String(vendorTasks.length) }), _jsx(StatusLine, { label: "Active task", value: vendorTransportSummary.activeTaskId ?? "None" }), _jsx(StatusLine, { label: "Started tasks", value: String(vendorTransportSummary.startedTasks) }), vendorRecentTransportEvents.length ? (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, color: "yellow", children: "Recent transport events" }), vendorRecentTransportEvents.map((event) => (_jsxs(Text, { color: "gray", children: [new Date(event.at).toLocaleString(), " | ", event.kind, " | ", event.title] }, `${event.kind}-${event.at}-${event.taskId ?? "no-task"}`)))] })) : (_jsx(Text, { color: "gray", children: "No transport events yet." }))] }), _jsxs(Section, { title: "Context Runtime Tree", children: [_jsx(StatusLine, { label: "Nodes", value: String(vendorTreeStore?.nodes.length ?? 0) }), _jsx(StatusLine, { label: "Pending drafts", value: String(vendorTreeStore?.stats.pendingDrafts ?? 0) }), _jsx(StatusLine, { label: "Pulled context", value: String(vendorTreeStore?.stats.pulledContext ?? 0) }), _jsx(StatusLine, { label: "Known fixes", value: String(vendorTreeStore?.stats.pulledFixes ?? 0) }), _jsx(StatusLine, { label: "Runtime transport", value: vendorTreeStore?.runtime.transportStatus ?? "idle" }), vendorRootTreeNodes.length ? (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, color: "yellow", children: "Top runtime nodes" }), vendorRootTreeNodes.map((node) => (_jsx(Text, { color: "gray", children: `${" ".repeat(node.depth)}- ${node.label}${node.detail ? ` | ${node.detail}` : ""}` }, node.id)))] })) : (_jsx(Text, { color: "gray", children: "The context tree has not been built yet." }))] }), _jsxs(Section, { title: "Session Continuity", children: [_jsx(StatusLine, { label: "Panel history", value: refreshState.session?.panelHistory.join(" -> ") || "None" }), _jsx(StatusLine, { label: "Recent providers", value: refreshState.session?.recentProviderIds.join(", ") || "None" }), _jsx(StatusLine, { label: "Recent models", value: refreshState.session?.recentModels.join(", ") || "None" }), _jsx(StatusLine, { label: "Recent hub items", value: refreshState.session?.recentHubSlugs.join(", ") || "None" }), _jsx(StatusLine, { label: "Recent connectors", value: refreshState.session?.recentConnectorSources.join(", ") || "None" })] }), _jsxs(Section, { title: "Runtime Bridge", children: [_jsx(StatusLine, { label: "Hydrated", value: vendorTransportSummary.isHydrated ? "Yes" : "No" }), _jsx(StatusLine, { label: "Generated", value: formatAgo(vendorTransportSummary.generatedAt) }), _jsx(StatusLine, { label: "Bridge queue", value: String(vendorTransportSummary.queueDepth) }), _jsx(StatusLine, { label: "Bridge tasks", value: String(vendorTransportSummary.recentTaskCount) }), _jsx(StatusLine, { label: "Bridge company", value: vendorContextSummary.companyName ?? "Unlinked company" }), _jsx(StatusLine, { label: "Bridge space", value: vendorContextSummary.spaceName ?? "Unlinked space" }), _jsx(StatusLine, { label: "Bridge provider", value: vendorContextSummary.providerName ?? "No provider" }), _jsx(StatusLine, { label: "Bridge model", value: vendorContextSummary.modelName ?? "No model" }), _jsx(StatusLine, { label: "Tree nodes", value: String(vendorContextSummary.treeNodes) }), _jsx(StatusLine, { label: "Runtime status", value: vendorContextSummary.runtimeStatus })] })] })] }));
|
|
1510
1681
|
}
|
|
1511
1682
|
return (_jsxs(PanelShell, { activePanel: activePanel, footer: footer, message: busyLabel ? `${busyLabel}` : message, navigationFocus: navigationFocus, selectedPanelIndex: selectedPanelIndex, children: [mainContent, inputMode ? (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "yellow", children: inputMode === "query" ? "Ask Context" : "Save a local Context note" }), _jsx(TextInput, { value: inputValue, onChange: setInputValue })] })) : null] }));
|
|
1512
1683
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare function worktreeAddCommandAction(targetPath?: string, opts?: {
|
|
2
|
+
force?: boolean;
|
|
3
|
+
format?: string;
|
|
4
|
+
name?: string;
|
|
5
|
+
}): Promise<void>;
|
|
6
|
+
export declare function worktreeListCommandAction(opts?: {
|
|
7
|
+
format?: string;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
export declare function worktreeRemoveCommandAction(targetPath?: string, opts?: {
|
|
10
|
+
format?: string;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
export declare function worktreeCommand(cli: any): void;
|