umbrella-context 0.1.2 → 0.1.32
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/bin/um.js +2 -0
- package/dist/adapters/byterover-context-runtime-store.d.ts +15 -0
- package/dist/adapters/byterover-context-runtime-store.js +57 -0
- package/dist/adapters/byterover-runtime-bridge.d.ts +218 -0
- package/dist/adapters/byterover-runtime-bridge.js +343 -0
- package/dist/adapters/byterover-transport-task-store.d.ts +13 -0
- package/dist/adapters/byterover-transport-task-store.js +50 -0
- package/dist/adapters/umbrella-onboarding.d.ts +27 -0
- package/dist/adapters/umbrella-onboarding.js +79 -0
- package/dist/adapters/umbrella-provider-runtime.d.ts +38 -0
- package/dist/adapters/umbrella-provider-runtime.js +199 -0
- package/dist/adapters/vendor-byterover.d.ts +4 -0
- package/dist/adapters/vendor-byterover.js +19 -0
- package/dist/commands/activity.d.ts +2 -0
- package/dist/commands/activity.js +82 -0
- package/dist/commands/bridge.d.ts +2 -0
- package/dist/commands/bridge.js +40 -0
- package/dist/commands/catalog.d.ts +34 -0
- package/dist/commands/catalog.js +234 -0
- package/dist/commands/connect.js +14 -14
- package/dist/commands/connectors.d.ts +24 -0
- package/dist/commands/connectors.js +626 -0
- package/dist/commands/curate.d.ts +1 -0
- package/dist/commands/curate.js +48 -3
- package/dist/commands/debug.d.ts +2 -0
- package/dist/commands/debug.js +55 -0
- package/dist/commands/fix.js +54 -0
- package/dist/commands/hub.d.ts +22 -0
- package/dist/commands/hub.js +487 -0
- package/dist/commands/interactive.d.ts +2 -0
- package/dist/commands/interactive.js +970 -62
- package/dist/commands/locations.d.ts +1 -0
- package/dist/commands/locations.js +15 -12
- package/dist/commands/logout.d.ts +2 -0
- package/dist/commands/logout.js +34 -0
- package/dist/commands/model.d.ts +11 -0
- package/dist/commands/model.js +225 -0
- package/dist/commands/providers.d.ts +17 -0
- package/dist/commands/providers.js +379 -0
- package/dist/commands/pull.js +60 -1
- package/dist/commands/push.js +62 -2
- package/dist/commands/reset.d.ts +2 -0
- package/dist/commands/reset.js +35 -0
- package/dist/commands/restart.d.ts +2 -0
- package/dist/commands/restart.js +21 -0
- package/dist/commands/search.js +65 -1
- package/dist/commands/session.d.ts +2 -0
- package/dist/commands/session.js +241 -0
- package/dist/commands/setup.js +58 -56
- package/dist/commands/space.d.ts +12 -0
- package/dist/commands/space.js +138 -42
- package/dist/commands/status.d.ts +29 -0
- package/dist/commands/status.js +120 -19
- package/dist/commands/tasks.d.ts +2 -0
- package/dist/commands/tasks.js +95 -0
- package/dist/commands/transport.d.ts +2 -0
- package/dist/commands/transport.js +88 -0
- package/dist/commands/tree.d.ts +2 -0
- package/dist/commands/tree.js +98 -0
- package/dist/commands/tui.d.ts +2 -0
- package/dist/commands/tui.js +1273 -0
- package/dist/config.d.ts +23 -0
- package/dist/config.js +69 -0
- package/dist/index.js +41 -5
- package/dist/repo-state.d.ts +227 -1
- package/dist/repo-state.js +920 -4
- package/dist/umbrella.js +29 -5
- package/package.json +11 -3
|
@@ -1,96 +1,997 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import prompts from "prompts";
|
|
3
3
|
import { configManager } from "../config.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { pullCommandAction } from "./pull.js";
|
|
4
|
+
import { ensureSessionState, getConnectorRuns, getInstalledConnectors, getInstalledHubEntries, getPendingMemories, getPulledFixes, getPulledMemories, recordSessionEvent, recordSessionCommand, recordSessionCuration, recordSessionQuery, setSessionPanel, resetSessionState, setSessionSummary, } from "../repo-state.js";
|
|
5
|
+
import { createContextSpace, getCompanyContextSummary, toContextSpaces } from "../umbrella.js";
|
|
6
|
+
import { parseInteractiveInput, renderCommandList, resolveCommand } from "./catalog.js";
|
|
8
7
|
import { searchCommandAction } from "./search.js";
|
|
9
|
-
import {
|
|
10
|
-
|
|
8
|
+
import { curateCommandAction } from "./curate.js";
|
|
9
|
+
import { spaceCommandAction } from "./space.js";
|
|
10
|
+
import { getProviderReadinessSummary, providersCommandAction } from "./providers.js";
|
|
11
|
+
import { getModelsForActiveProvider, modelCommandAction } from "./model.js";
|
|
12
|
+
import { hubCommandAction } from "./hub.js";
|
|
13
|
+
import { connectorsCommandAction } from "./connectors.js";
|
|
14
|
+
import { getStatusSnapshot } from "./status.js";
|
|
15
|
+
import { debugCommandAction } from "./debug.js";
|
|
16
|
+
import { logoutCommandAction } from "./logout.js";
|
|
17
|
+
import { restartCommandAction } from "./restart.js";
|
|
18
|
+
import { activityCommandAction } from "./activity.js";
|
|
19
|
+
function divider() {
|
|
20
|
+
return chalk.gray("----------------------------------------------------------------");
|
|
21
|
+
}
|
|
22
|
+
function labelValue(label, value) {
|
|
23
|
+
return ` ${chalk.cyan(label.padEnd(18))} ${value}`;
|
|
24
|
+
}
|
|
25
|
+
function printWelcomeHeader(providerLabel, modelLabel) {
|
|
26
|
+
const timeLabel = new Date().toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });
|
|
27
|
+
console.log(chalk.cyan("UMBRELLA CONTEXT") + chalk.gray(` ${timeLabel}`));
|
|
28
|
+
console.log(divider());
|
|
29
|
+
console.log(chalk.bold(" Command-first local Context for this repo"));
|
|
30
|
+
console.log(chalk.gray(` Runtime: ${providerLabel}${modelLabel ? ` (${modelLabel})` : ""}`));
|
|
31
|
+
console.log(chalk.gray(" Save to .um first. Push only when you want the team to share it."));
|
|
32
|
+
console.log(divider());
|
|
33
|
+
console.log(` ${chalk.yellow("/home")} Current repo and sync overview`);
|
|
34
|
+
console.log(` ${chalk.yellow("/query")} Ask Context a question`);
|
|
35
|
+
console.log(` ${chalk.yellow("/curate")} Save a reusable note locally`);
|
|
36
|
+
console.log(` ${chalk.yellow("/recent")} Show recent local activity`);
|
|
37
|
+
console.log(` ${chalk.yellow("/activity")} Show the richer repo activity feed`);
|
|
38
|
+
console.log(` ${chalk.yellow("/timeline")} Show the recent session event timeline`);
|
|
39
|
+
console.log(` ${chalk.yellow("/session")} Current terminal session summary`);
|
|
40
|
+
console.log(` ${chalk.yellow("/panel")} Show the active panel and focus`);
|
|
41
|
+
console.log(` ${chalk.yellow("/continue")} Re-open the last active panel`);
|
|
42
|
+
console.log(` ${chalk.yellow("/status")} Inspect sync, provider, and MCP state`);
|
|
43
|
+
console.log(` ${chalk.yellow("/restart")} Refresh this live terminal session`);
|
|
44
|
+
console.log(` ${chalk.yellow("/debug")} Show config paths and local runtime details`);
|
|
45
|
+
console.log(` ${chalk.yellow("/logout")} Disconnect this device from Umbrella Context`);
|
|
46
|
+
console.log(` ${chalk.yellow("/reset")} Reset this repo's local Context state`);
|
|
47
|
+
console.log(` ${chalk.yellow("/")} Full command list`);
|
|
48
|
+
console.log(divider());
|
|
49
|
+
console.log(` ${chalk.gray("Shortcuts:")} type plain text to query, or start with ${chalk.yellow("+")} to curate quickly.`);
|
|
50
|
+
console.log("");
|
|
51
|
+
}
|
|
52
|
+
async function printRuntimeSnapshot() {
|
|
11
53
|
const config = configManager.config;
|
|
12
|
-
if (!config)
|
|
13
|
-
|
|
54
|
+
if (!config)
|
|
55
|
+
return;
|
|
56
|
+
const activeProvider = configManager.providers.find((entry) => entry.id === config.activeProvider) ?? null;
|
|
57
|
+
const providerLabel = activeProvider ? activeProvider.name : "No provider connected";
|
|
58
|
+
const modelLabel = config.activeModel ?? "";
|
|
59
|
+
printWelcomeHeader(providerLabel, modelLabel);
|
|
60
|
+
}
|
|
61
|
+
async function printHomeView(config) {
|
|
62
|
+
await setSessionPanel("home", config.projectName);
|
|
63
|
+
const snapshot = await getStatusSnapshot();
|
|
64
|
+
const pending = await getPendingMemories();
|
|
65
|
+
const hubEntries = await getInstalledHubEntries();
|
|
66
|
+
const connectors = await getInstalledConnectors();
|
|
67
|
+
const connectorRuns = await getConnectorRuns();
|
|
68
|
+
const session = await ensureSessionState();
|
|
69
|
+
const latestConnectorRun = connectorRuns[0] ?? null;
|
|
70
|
+
console.log(chalk.bold(` ${config.companyName} / ${config.projectName}`));
|
|
71
|
+
console.log(divider());
|
|
72
|
+
console.log(chalk.bold(" Sync"));
|
|
73
|
+
console.log(labelValue("Pending drafts", String(snapshot.pendingCount)));
|
|
74
|
+
console.log(labelValue("Pulled context", String(snapshot.pulledContextCount)));
|
|
75
|
+
console.log(labelValue("Known fixes", String(snapshot.pulledFixCount)));
|
|
76
|
+
console.log("");
|
|
77
|
+
console.log(chalk.bold(" Repo"));
|
|
78
|
+
console.log(labelValue("Hub installs", String(hubEntries.length)));
|
|
79
|
+
console.log(labelValue("Connectors", String(connectors.length)));
|
|
80
|
+
console.log(labelValue("Last connector run", latestConnectorRun ? `${latestConnectorRun.connectorName} (${latestConnectorRun.status})` : "Never"));
|
|
81
|
+
console.log("");
|
|
82
|
+
console.log(chalk.bold(" Runtime"));
|
|
83
|
+
console.log(labelValue("Provider", snapshot.providerLabel));
|
|
84
|
+
console.log(labelValue("Model", snapshot.modelLabel));
|
|
85
|
+
console.log(labelValue("Repo MCP", snapshot.mcpConfigured ? "Ready" : "Needs setup"));
|
|
86
|
+
console.log(labelValue("Current panel", session.currentPanel ?? "Home"));
|
|
87
|
+
console.log(labelValue("Current focus", session.currentFocus ?? "None"));
|
|
88
|
+
console.log(labelValue("Latest event", session.events?.[0]?.title ?? "Nothing yet"));
|
|
89
|
+
console.log("");
|
|
90
|
+
console.log(chalk.bold(" Suggested next steps"));
|
|
91
|
+
if (snapshot.nextSteps.length > 0) {
|
|
92
|
+
snapshot.nextSteps.forEach((step) => console.log(` - ${step}`));
|
|
93
|
+
}
|
|
94
|
+
else if (pending.length > 0) {
|
|
95
|
+
console.log(` - ${chalk.yellow("/push")} to share ${pending.length} local draft${pending.length === 1 ? "" : "s"}`);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
console.log(` - ${chalk.yellow('/curate "What you learned"')} to stage a new local note`);
|
|
99
|
+
console.log(` - ${chalk.yellow("/query What do we already know about this?")} to search local and server memory`);
|
|
100
|
+
}
|
|
101
|
+
console.log(` - ${chalk.yellow("/recent")} to inspect the latest repo activity`);
|
|
102
|
+
console.log(` - ${chalk.yellow("/activity")} to inspect the richer repo activity feed`);
|
|
103
|
+
console.log("");
|
|
104
|
+
}
|
|
105
|
+
function printSessionHint(title, lines) {
|
|
106
|
+
console.log("");
|
|
107
|
+
console.log(chalk.bold(` ${title}`));
|
|
108
|
+
lines.forEach((line) => console.log(` - ${line}`));
|
|
109
|
+
console.log("");
|
|
110
|
+
}
|
|
111
|
+
function printRecentSection(title, items, render) {
|
|
112
|
+
console.log(chalk.bold(` ${title}`));
|
|
113
|
+
if (items.length === 0) {
|
|
114
|
+
console.log(chalk.gray(" Nothing recent yet."));
|
|
115
|
+
console.log("");
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
items.forEach((item, index) => {
|
|
119
|
+
console.log(render(item, index));
|
|
120
|
+
});
|
|
121
|
+
console.log("");
|
|
122
|
+
}
|
|
123
|
+
async function printSessionView() {
|
|
124
|
+
await setSessionPanel("session", "summary");
|
|
125
|
+
const session = await ensureSessionState();
|
|
126
|
+
console.log("");
|
|
127
|
+
console.log(chalk.bold(" Current Session"));
|
|
128
|
+
console.log(divider());
|
|
129
|
+
console.log(labelValue("Session ID", session.id));
|
|
130
|
+
console.log(labelValue("Started", session.startedAt));
|
|
131
|
+
console.log(labelValue("Updated", session.updatedAt));
|
|
132
|
+
console.log(labelValue("Commands", String(session.commandHistory.length)));
|
|
133
|
+
console.log(labelValue("Queries", String(session.recentQueries.length)));
|
|
134
|
+
console.log(labelValue("Curations", String(session.recentCurations.length)));
|
|
135
|
+
console.log(labelValue("Last summary", session.lastSummary ?? "Nothing recorded yet"));
|
|
136
|
+
console.log(labelValue("Current panel", session.currentPanel ?? "None"));
|
|
137
|
+
console.log(labelValue("Current focus", session.currentFocus ?? "None"));
|
|
138
|
+
console.log(labelValue("Events", String(session.events?.length ?? 0)));
|
|
139
|
+
console.log("");
|
|
140
|
+
if (session.panelHistory.length > 0) {
|
|
141
|
+
console.log(chalk.bold(" Panel history"));
|
|
142
|
+
session.panelHistory.slice(0, 5).forEach((entry, index) => console.log(` ${index + 1}. ${entry}`));
|
|
143
|
+
console.log("");
|
|
144
|
+
}
|
|
145
|
+
if (session.recentQueries.length > 0) {
|
|
146
|
+
console.log(chalk.bold(" Recent Queries"));
|
|
147
|
+
session.recentQueries.slice(0, 3).forEach((entry, index) => console.log(` ${index + 1}. ${entry}`));
|
|
148
|
+
console.log("");
|
|
149
|
+
}
|
|
150
|
+
if (session.recentCurations.length > 0) {
|
|
151
|
+
console.log(chalk.bold(" Recent Curations"));
|
|
152
|
+
session.recentCurations.slice(0, 3).forEach((entry, index) => console.log(` ${index + 1}. ${entry}`));
|
|
153
|
+
console.log("");
|
|
154
|
+
}
|
|
155
|
+
if (session.recentProviderIds.length > 0 || session.recentModels.length > 0) {
|
|
156
|
+
console.log(chalk.bold(" Runtime recents"));
|
|
157
|
+
if (session.recentProviderIds.length > 0) {
|
|
158
|
+
const names = session.recentProviderIds
|
|
159
|
+
.map((id) => configManager.providers.find((entry) => entry.id === id)?.name ?? id)
|
|
160
|
+
.join(", ");
|
|
161
|
+
console.log(` Providers: ${names}`);
|
|
162
|
+
}
|
|
163
|
+
if (session.recentModels.length > 0) {
|
|
164
|
+
console.log(` Models: ${session.recentModels.join(", ")}`);
|
|
165
|
+
}
|
|
166
|
+
console.log("");
|
|
167
|
+
}
|
|
168
|
+
if (session.recentHubSlugs.length > 0 || session.recentConnectorSources.length > 0) {
|
|
169
|
+
console.log(chalk.bold(" Ecosystem recents"));
|
|
170
|
+
if (session.recentHubSlugs.length > 0) {
|
|
171
|
+
console.log(` Hub: ${session.recentHubSlugs.join(", ")}`);
|
|
172
|
+
}
|
|
173
|
+
if (session.recentConnectorSources.length > 0) {
|
|
174
|
+
console.log(` Connectors: ${session.recentConnectorSources.join(", ")}`);
|
|
175
|
+
}
|
|
176
|
+
console.log("");
|
|
177
|
+
}
|
|
178
|
+
if ((session.events?.length ?? 0) > 0) {
|
|
179
|
+
console.log(chalk.bold(" Recent timeline"));
|
|
180
|
+
session.events.slice(0, 5).forEach((entry, index) => {
|
|
181
|
+
console.log(` ${index + 1}. [${entry.kind}] ${entry.title}`);
|
|
182
|
+
if (entry.detail) {
|
|
183
|
+
console.log(chalk.gray(` ${entry.detail}`));
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
console.log("");
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async function printProviderOverview() {
|
|
190
|
+
const readiness = getProviderReadinessSummary();
|
|
191
|
+
const providerCount = configManager.providers.length;
|
|
192
|
+
console.log("");
|
|
193
|
+
console.log(chalk.bold(" Provider Runtime"));
|
|
194
|
+
console.log(divider());
|
|
195
|
+
console.log(labelValue("Connected", String(providerCount)));
|
|
196
|
+
console.log(labelValue("Active provider", readiness.activeProvider?.name ?? "Not connected"));
|
|
197
|
+
console.log(labelValue("Active model", readiness.activeModel ?? "Not selected"));
|
|
198
|
+
console.log(labelValue("Runtime state", !readiness.providerReady
|
|
199
|
+
? "Needs provider"
|
|
200
|
+
: !readiness.modelReady
|
|
201
|
+
? "Needs model"
|
|
202
|
+
: "Ready"));
|
|
203
|
+
console.log("");
|
|
204
|
+
}
|
|
205
|
+
async function printModelOverview() {
|
|
206
|
+
const readiness = getProviderReadinessSummary();
|
|
207
|
+
const models = getModelsForActiveProvider();
|
|
208
|
+
console.log("");
|
|
209
|
+
console.log(chalk.bold(" Model Runtime"));
|
|
210
|
+
console.log(divider());
|
|
211
|
+
console.log(labelValue("Provider", readiness.activeProvider?.name ?? "Not connected"));
|
|
212
|
+
console.log(labelValue("Active model", readiness.activeModel ?? "Not selected"));
|
|
213
|
+
console.log(labelValue("Available models", String(models.length)));
|
|
214
|
+
if (models.length > 0) {
|
|
215
|
+
console.log("");
|
|
216
|
+
console.log(chalk.bold(" Available Models"));
|
|
217
|
+
models.forEach((model, index) => {
|
|
218
|
+
const active = readiness.activeModel === model ? " (active)" : "";
|
|
219
|
+
console.log(` ${index + 1}. ${model}${active}`);
|
|
220
|
+
});
|
|
221
|
+
console.log("");
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
async function printHubOverview() {
|
|
225
|
+
const installed = await getInstalledHubEntries();
|
|
226
|
+
console.log("");
|
|
227
|
+
console.log(chalk.bold(" Hub Overview"));
|
|
228
|
+
console.log(divider());
|
|
229
|
+
console.log(labelValue("Catalog entries", "3"));
|
|
230
|
+
console.log(labelValue("Installed", String(installed.length)));
|
|
231
|
+
if (installed.length > 0) {
|
|
232
|
+
console.log("");
|
|
233
|
+
console.log(chalk.bold(" Installed Bundles"));
|
|
234
|
+
installed.slice(0, 5).forEach((entry, index) => {
|
|
235
|
+
console.log(` ${index + 1}. ${entry.name} [${entry.type}]`);
|
|
236
|
+
});
|
|
237
|
+
console.log("");
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
async function printConnectorOverview() {
|
|
241
|
+
const connectors = await getInstalledConnectors();
|
|
242
|
+
const connectorRuns = await getConnectorRuns();
|
|
243
|
+
const latest = connectorRuns[0] ?? null;
|
|
244
|
+
console.log("");
|
|
245
|
+
console.log(chalk.bold(" Connector Overview"));
|
|
246
|
+
console.log(divider());
|
|
247
|
+
console.log(labelValue("Installed", String(connectors.length)));
|
|
248
|
+
console.log(labelValue("Last run", latest ? `${latest.connectorName} (${latest.status})` : "Never"));
|
|
249
|
+
if (connectors.length > 0) {
|
|
250
|
+
console.log("");
|
|
251
|
+
console.log(chalk.bold(" Installed Connectors"));
|
|
252
|
+
connectors.forEach((entry, index) => {
|
|
253
|
+
console.log(` ${index + 1}. ${entry.name} [${entry.type}]`);
|
|
254
|
+
});
|
|
255
|
+
console.log("");
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
async function printCurrentPanelView() {
|
|
259
|
+
const session = await ensureSessionState();
|
|
260
|
+
const latestPanelEvent = (session.events ?? []).find((entry) => entry.panel === session.currentPanel);
|
|
261
|
+
console.log("");
|
|
262
|
+
console.log(chalk.bold(" Live Panel"));
|
|
263
|
+
console.log(divider());
|
|
264
|
+
console.log(labelValue("Panel", session.currentPanel ?? "None"));
|
|
265
|
+
console.log(labelValue("Focus", session.currentFocus ?? "None"));
|
|
266
|
+
console.log(labelValue("Last panel event", latestPanelEvent?.title ?? "Nothing panel-specific yet"));
|
|
267
|
+
if (session.panelHistory.length > 0) {
|
|
268
|
+
console.log("");
|
|
269
|
+
console.log(chalk.bold(" Recent panels"));
|
|
270
|
+
session.panelHistory.slice(0, 5).forEach((entry, index) => console.log(` ${index + 1}. ${entry}`));
|
|
271
|
+
}
|
|
272
|
+
console.log("");
|
|
273
|
+
}
|
|
274
|
+
async function printTimelineView() {
|
|
275
|
+
await setSessionPanel("timeline", "events");
|
|
276
|
+
const session = await ensureSessionState();
|
|
277
|
+
console.log("");
|
|
278
|
+
console.log(chalk.bold(" Session Timeline"));
|
|
279
|
+
console.log(divider());
|
|
280
|
+
if ((session.events?.length ?? 0) === 0) {
|
|
281
|
+
console.log(chalk.gray(" No session events yet."));
|
|
282
|
+
console.log("");
|
|
14
283
|
return;
|
|
15
284
|
}
|
|
16
|
-
|
|
17
|
-
|
|
285
|
+
session.events.slice(0, 12).forEach((entry, index) => {
|
|
286
|
+
const badge = entry.status === "success" ? chalk.green(`[${entry.kind}]`)
|
|
287
|
+
: entry.status === "warning" ? chalk.yellow(`[${entry.kind}]`)
|
|
288
|
+
: entry.status === "failure" ? chalk.red(`[${entry.kind}]`)
|
|
289
|
+
: chalk.cyan(`[${entry.kind}]`);
|
|
290
|
+
const focusSuffix = entry.focus ? ` -> ${entry.focus}` : "";
|
|
291
|
+
console.log(` ${index + 1}. ${badge} ${entry.title}${focusSuffix}`);
|
|
292
|
+
console.log(chalk.gray(` ${new Date(entry.at).toLocaleString()}`));
|
|
293
|
+
if (entry.detail) {
|
|
294
|
+
console.log(chalk.gray(` ${entry.detail}`));
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
console.log("");
|
|
298
|
+
}
|
|
299
|
+
async function printActivityView() {
|
|
300
|
+
await activityCommandAction();
|
|
301
|
+
}
|
|
302
|
+
async function continueLastPanel(config) {
|
|
303
|
+
const session = await ensureSessionState();
|
|
304
|
+
const panel = session.currentPanel;
|
|
305
|
+
const focus = session.currentFocus ?? undefined;
|
|
306
|
+
if (!panel) {
|
|
307
|
+
console.log(chalk.yellow("\n No current panel to continue yet."));
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
if (panel === "home") {
|
|
311
|
+
await printHomeView(config);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (panel === "providers") {
|
|
315
|
+
if (focus) {
|
|
316
|
+
await providersCommandAction("inspect", focus);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
await openProvidersMenu();
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
if (panel === "model") {
|
|
323
|
+
if (focus) {
|
|
324
|
+
await modelCommandAction("inspect", focus);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
await openModelMenu();
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if (panel === "hub") {
|
|
331
|
+
if (focus && !focus.startsWith("registry:") && focus !== "list" && focus !== "installed") {
|
|
332
|
+
await hubCommandAction("inspect", focus);
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
if (focus?.startsWith("registry:")) {
|
|
336
|
+
await hubCommandAction("registry", "list");
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
await openHubMenu();
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
if (panel === "connectors") {
|
|
343
|
+
if (focus && focus !== "list") {
|
|
344
|
+
await connectorsCommandAction("inspect", focus);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
await openConnectorsMenu();
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (panel === "space" || panel === "spaces" || panel === "projects") {
|
|
351
|
+
await openSpaceMenu(config);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
if (panel === "session") {
|
|
355
|
+
await printSessionView();
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
if (panel === "recent") {
|
|
359
|
+
await handleRecent(config);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
if (panel === "activity") {
|
|
363
|
+
await printActivityView();
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
if (panel === "timeline") {
|
|
367
|
+
await printTimelineView();
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
if (panel === "reset") {
|
|
371
|
+
console.log(chalk.yellow("\n The last panel was a local reset. Run /status to see the clean repo state or /home to start fresh."));
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (panel === "status") {
|
|
375
|
+
await import("./status.js").then((mod) => mod.statusCommandAction());
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
console.log(chalk.yellow(`\n No resume handler yet for panel "${panel}".`));
|
|
379
|
+
}
|
|
380
|
+
async function openSpaceMenu(config) {
|
|
18
381
|
while (true) {
|
|
19
|
-
|
|
20
|
-
|
|
382
|
+
await setSessionPanel("space", config.projectName);
|
|
383
|
+
const summary = await getCompanyContextSummary(config.umbrellaUrl, config.companyId);
|
|
384
|
+
const spaces = toContextSpaces(summary);
|
|
385
|
+
const answer = await prompts({
|
|
386
|
+
type: "select",
|
|
21
387
|
name: "value",
|
|
22
|
-
message:
|
|
388
|
+
message: `Context spaces for ${config.companyName}`,
|
|
389
|
+
choices: [
|
|
390
|
+
{ title: "Overview", description: "See the current company and space summary", value: "overview" },
|
|
391
|
+
{ title: "List spaces", description: "Show all spaces for this company", value: "list" },
|
|
392
|
+
{ title: "Switch space", description: "Move this repo to another space", value: "switch" },
|
|
393
|
+
{ title: "Create space", description: "Add a new team lane like Growth or Engineering", value: "create" },
|
|
394
|
+
{ title: "Back", value: "back" },
|
|
395
|
+
],
|
|
23
396
|
});
|
|
24
|
-
if (!
|
|
397
|
+
if (!answer.value || answer.value === "back")
|
|
398
|
+
return;
|
|
399
|
+
if (answer.value === "overview") {
|
|
400
|
+
await handleSpaces(config);
|
|
25
401
|
continue;
|
|
26
|
-
const parts = input.value.trim().split(/\s+/);
|
|
27
|
-
const cmd = parts[0].toLowerCase();
|
|
28
|
-
const rest = parts.slice(1).join(" ");
|
|
29
|
-
if (cmd === "exit" || cmd === "quit")
|
|
30
|
-
break;
|
|
31
|
-
if (cmd === "curate") {
|
|
32
|
-
await curateCommandAction(rest);
|
|
33
402
|
}
|
|
34
|
-
|
|
35
|
-
await
|
|
403
|
+
if (answer.value === "list") {
|
|
404
|
+
await spaceCommandAction("list");
|
|
405
|
+
continue;
|
|
36
406
|
}
|
|
37
|
-
|
|
38
|
-
|
|
407
|
+
if (answer.value === "switch") {
|
|
408
|
+
if (spaces.length === 0) {
|
|
409
|
+
console.log(chalk.yellow("\n No spaces found for this company."));
|
|
410
|
+
continue;
|
|
411
|
+
}
|
|
412
|
+
await spaceCommandAction("switch");
|
|
413
|
+
continue;
|
|
39
414
|
}
|
|
40
|
-
|
|
41
|
-
await
|
|
415
|
+
if (answer.value === "create") {
|
|
416
|
+
const createAnswer = await prompts({
|
|
417
|
+
type: "text",
|
|
418
|
+
name: "name",
|
|
419
|
+
message: "Name the new context space",
|
|
420
|
+
validate: (value) => (value.trim().length > 1 ? true : "Use at least 2 characters."),
|
|
421
|
+
});
|
|
422
|
+
const nextName = String(createAnswer.name ?? "").trim();
|
|
423
|
+
if (!nextName) {
|
|
424
|
+
console.log(chalk.yellow("\n No space name provided."));
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
await createContextSpace(config.umbrellaUrl, config.companyId, nextName);
|
|
428
|
+
await recordSessionEvent({
|
|
429
|
+
kind: "space",
|
|
430
|
+
title: `Created space ${nextName}`,
|
|
431
|
+
detail: `A new Context space was created inside ${config.companyName}.`,
|
|
432
|
+
panel: "space",
|
|
433
|
+
focus: nextName,
|
|
434
|
+
status: "success",
|
|
435
|
+
});
|
|
436
|
+
console.log(chalk.green(`\n Created ${nextName}.`));
|
|
437
|
+
const switchNow = await prompts({
|
|
438
|
+
type: "confirm",
|
|
439
|
+
name: "value",
|
|
440
|
+
message: `Switch this repo to ${nextName} now?`,
|
|
441
|
+
initial: true,
|
|
442
|
+
});
|
|
443
|
+
if (switchNow.value) {
|
|
444
|
+
await spaceCommandAction("switch", nextName);
|
|
445
|
+
}
|
|
446
|
+
continue;
|
|
42
447
|
}
|
|
43
|
-
|
|
44
|
-
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
async function openProvidersMenu() {
|
|
451
|
+
while (true) {
|
|
452
|
+
const readiness = getProviderReadinessSummary();
|
|
453
|
+
const activeProvider = readiness.activeProvider;
|
|
454
|
+
await setSessionPanel("providers", activeProvider?.id ?? null);
|
|
455
|
+
const answer = await prompts({
|
|
456
|
+
type: "select",
|
|
457
|
+
name: "value",
|
|
458
|
+
message: activeProvider ? `Provider flow (active: ${activeProvider.name})` : "Provider flow",
|
|
459
|
+
choices: [
|
|
460
|
+
{ title: "Setup runtime", description: "Carry this device from provider choice into model readiness", value: "setup" },
|
|
461
|
+
{ title: "Overview", description: "See provider runtime readiness for this device", value: "overview" },
|
|
462
|
+
{ title: "List providers", description: "See providers already saved on this device", value: "list" },
|
|
463
|
+
{ title: "Inspect provider", description: "Read the details and next steps for one provider", value: "inspect" },
|
|
464
|
+
{ title: "Inspect recent provider", description: "Open the provider you touched most recently", value: "recent" },
|
|
465
|
+
{ title: "Test runtime", description: "Check whether the active provider is actually ready to run", value: "test" },
|
|
466
|
+
{ title: "Connect provider", description: "Add a new provider API key on this device", value: "connect" },
|
|
467
|
+
{ title: "Switch provider", description: "Choose the active provider", value: "switch" },
|
|
468
|
+
{ title: "Disconnect provider", description: "Remove a saved provider from this device", value: "disconnect" },
|
|
469
|
+
{ title: "Choose model", description: "Pick the active model for the current provider", value: "model" },
|
|
470
|
+
{ title: "Back", value: "back" },
|
|
471
|
+
],
|
|
472
|
+
});
|
|
473
|
+
if (!answer.value || answer.value === "back")
|
|
474
|
+
return;
|
|
475
|
+
if (answer.value === "overview") {
|
|
476
|
+
await printProviderOverview();
|
|
477
|
+
continue;
|
|
45
478
|
}
|
|
46
|
-
|
|
47
|
-
await
|
|
479
|
+
if (answer.value === "model") {
|
|
480
|
+
await openModelMenu();
|
|
481
|
+
continue;
|
|
48
482
|
}
|
|
49
|
-
|
|
50
|
-
|
|
483
|
+
const result = await providersCommandAction(answer.value);
|
|
484
|
+
if (result?.activeProvider) {
|
|
485
|
+
const lines = [`Active provider: ${result.activeProvider.name}`];
|
|
486
|
+
if (result.activeProvider.baseUrl) {
|
|
487
|
+
lines.push(`Base URL: ${result.activeProvider.baseUrl}`);
|
|
488
|
+
}
|
|
489
|
+
lines.push(result.needsModelSelection
|
|
490
|
+
? "No model is selected yet, so the runtime is only partially ready."
|
|
491
|
+
: "Provider and model are both ready for terminal work.");
|
|
492
|
+
printSessionHint("Provider Session Summary", lines);
|
|
51
493
|
}
|
|
52
|
-
|
|
53
|
-
await
|
|
494
|
+
if ((answer.value === "connect" || answer.value === "switch" || answer.value === "setup") && result?.needsModelSelection) {
|
|
495
|
+
const chooseModel = await prompts({
|
|
496
|
+
type: "confirm",
|
|
497
|
+
name: "value",
|
|
498
|
+
message: "Choose a model now?",
|
|
499
|
+
initial: true,
|
|
500
|
+
});
|
|
501
|
+
if (chooseModel.value) {
|
|
502
|
+
const modelResult = await modelCommandAction("switch");
|
|
503
|
+
if (modelResult?.activeModel) {
|
|
504
|
+
printSessionHint("Runtime Ready", [
|
|
505
|
+
`Provider: ${modelResult.providerName ?? "Unknown"}`,
|
|
506
|
+
`Model: ${modelResult.activeModel}`,
|
|
507
|
+
'You can now type a plain question or use "/query ..." directly.',
|
|
508
|
+
]);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
54
511
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
`)
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
async function openModelMenu() {
|
|
515
|
+
while (true) {
|
|
516
|
+
const currentConfig = configManager.config;
|
|
517
|
+
const provider = configManager.providers.find((entry) => entry.id === currentConfig?.activeProvider) ?? null;
|
|
518
|
+
const models = getModelsForActiveProvider();
|
|
519
|
+
await setSessionPanel("model", currentConfig?.activeModel ?? provider?.id ?? null);
|
|
520
|
+
const answer = await prompts({
|
|
521
|
+
type: "select",
|
|
522
|
+
name: "value",
|
|
523
|
+
message: provider ? `Model flow (${provider.name})` : "Model flow",
|
|
524
|
+
choices: [
|
|
525
|
+
{ title: "Overview", description: "See active provider, model, and available choices", value: "overview" },
|
|
526
|
+
{ title: "List models", description: `See models for the active provider (${models.length})`, value: "list" },
|
|
527
|
+
{ title: "Inspect model", description: "Read details and the next step for a specific model", value: "inspect" },
|
|
528
|
+
{ title: "Inspect recent model", description: "Open the model you touched most recently", value: "recent" },
|
|
529
|
+
{ title: "Show readiness", description: "Check whether the model runtime is fully ready", value: "ready" },
|
|
530
|
+
{ title: "Switch model", description: "Choose the active model", value: "switch" },
|
|
531
|
+
{ title: "Back", value: "back" },
|
|
532
|
+
],
|
|
533
|
+
});
|
|
534
|
+
if (!answer.value || answer.value === "back")
|
|
535
|
+
return;
|
|
536
|
+
if (answer.value === "overview") {
|
|
537
|
+
await printModelOverview();
|
|
538
|
+
continue;
|
|
67
539
|
}
|
|
68
|
-
|
|
69
|
-
|
|
540
|
+
const result = await modelCommandAction(answer.value);
|
|
541
|
+
if (result?.action === "switch" && result.activeModel) {
|
|
542
|
+
printSessionHint("Model Session Summary", [
|
|
543
|
+
`Provider: ${result.providerName ?? "Unknown"}`,
|
|
544
|
+
`Active model: ${result.activeModel}`,
|
|
545
|
+
'The runtime is ready. Try a plain question or run "/query ...".',
|
|
546
|
+
]);
|
|
70
547
|
}
|
|
71
548
|
}
|
|
72
549
|
}
|
|
550
|
+
async function openHubMenu() {
|
|
551
|
+
while (true) {
|
|
552
|
+
const session = await ensureSessionState();
|
|
553
|
+
await setSessionPanel("hub", session.currentFocus);
|
|
554
|
+
const answer = await prompts({
|
|
555
|
+
type: "select",
|
|
556
|
+
name: "value",
|
|
557
|
+
message: "Hub flow",
|
|
558
|
+
choices: [
|
|
559
|
+
{ title: "Browse and act", description: "Inspect a bundle, install it, and keep moving in one flow", value: "browse" },
|
|
560
|
+
{ title: "Overview", description: "See installed bundles and the local hub state", value: "overview" },
|
|
561
|
+
{ title: "Browse catalog", description: "See available bundles, skills, and connector packs", value: "list" },
|
|
562
|
+
{ title: "Install hub entry", description: "Install a bundle into this repo", value: "install" },
|
|
563
|
+
{ title: "Inspect bundle", description: "Pick a hub entry and read what it includes", value: "inspect" },
|
|
564
|
+
{ title: "Inspect recent bundle", description: "Open the last hub entry you touched in this session", value: "recent" },
|
|
565
|
+
{ title: "Installed hub entries", description: "See what this repo already has", value: "installed" },
|
|
566
|
+
{ title: "Registries", description: "See configured hub registries", value: "registry" },
|
|
567
|
+
{ title: "Back", value: "back" },
|
|
568
|
+
],
|
|
569
|
+
});
|
|
570
|
+
if (!answer.value || answer.value === "back")
|
|
571
|
+
return;
|
|
572
|
+
if (answer.value === "overview") {
|
|
573
|
+
await printHubOverview();
|
|
574
|
+
continue;
|
|
575
|
+
}
|
|
576
|
+
if (answer.value === "browse") {
|
|
577
|
+
const browseResult = await hubCommandAction("browse");
|
|
578
|
+
if (browseResult?.installedEntry) {
|
|
579
|
+
const lines = [`Hub entry: ${browseResult.installedEntry.name}`];
|
|
580
|
+
if (browseResult.assetPath)
|
|
581
|
+
lines.push(`Asset file: ${browseResult.assetPath}`);
|
|
582
|
+
if (browseResult.filePaths && browseResult.filePaths.length > 0) {
|
|
583
|
+
lines.push(`${browseResult.filePaths.length} repo file${browseResult.filePaths.length === 1 ? "" : "s"} updated`);
|
|
584
|
+
}
|
|
585
|
+
if (browseResult.recommendedConnector) {
|
|
586
|
+
lines.push(`Recommended connector: ${browseResult.recommendedConnector}`);
|
|
587
|
+
}
|
|
588
|
+
printSessionHint("Hub Browse Summary", lines);
|
|
589
|
+
}
|
|
590
|
+
continue;
|
|
591
|
+
}
|
|
592
|
+
if (answer.value === "registry") {
|
|
593
|
+
await hubCommandAction("registry", "list");
|
|
594
|
+
continue;
|
|
595
|
+
}
|
|
596
|
+
if (answer.value === "recent") {
|
|
597
|
+
const recent = session.recentHubSlugs[0];
|
|
598
|
+
if (!recent) {
|
|
599
|
+
console.log(chalk.yellow("\n No recent hub entry in this session yet."));
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
await hubCommandAction("inspect", recent);
|
|
603
|
+
continue;
|
|
604
|
+
}
|
|
605
|
+
if (answer.value === "inspect") {
|
|
606
|
+
const inspectAnswer = await prompts({
|
|
607
|
+
type: "select",
|
|
608
|
+
name: "value",
|
|
609
|
+
message: "Choose a hub entry to inspect",
|
|
610
|
+
choices: [
|
|
611
|
+
{ title: "Quick Ping Growth Bundle", value: "quick-ping-growth-bundle" },
|
|
612
|
+
{ title: "Engineering Debug Skill Pack", value: "engineering-debug-skill-pack" },
|
|
613
|
+
{ title: "Umbrella Context MCP Connector", value: "umbrella-context-mcp-connector" },
|
|
614
|
+
],
|
|
615
|
+
});
|
|
616
|
+
if (!inspectAnswer.value) {
|
|
617
|
+
console.log(chalk.yellow("\n No hub entry selected."));
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
620
|
+
await hubCommandAction("inspect", inspectAnswer.value);
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
const result = await hubCommandAction(answer.value);
|
|
624
|
+
if (result?.action === "install" && result.installedEntry) {
|
|
625
|
+
const lines = [`Installed: ${result.installedEntry.name}`];
|
|
626
|
+
if (result.assetPath)
|
|
627
|
+
lines.push(`Asset file: ${result.assetPath}`);
|
|
628
|
+
if (result.filePaths && result.filePaths.length > 0) {
|
|
629
|
+
lines.push(`${result.filePaths.length} repo file${result.filePaths.length === 1 ? "" : "s"} added or refreshed`);
|
|
630
|
+
}
|
|
631
|
+
if (result.recommendedConnector) {
|
|
632
|
+
lines.push(`Recommended connector: ${result.recommendedConnector}`);
|
|
633
|
+
}
|
|
634
|
+
printSessionHint("Hub Install Summary", lines);
|
|
635
|
+
const next = await prompts({
|
|
636
|
+
type: "confirm",
|
|
637
|
+
name: "value",
|
|
638
|
+
message: "Open connectors now to run anything that bundle installed?",
|
|
639
|
+
initial: true,
|
|
640
|
+
});
|
|
641
|
+
if (next.value) {
|
|
642
|
+
await openConnectorsMenu();
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
async function openConnectorsMenu() {
|
|
648
|
+
while (true) {
|
|
649
|
+
const session = await ensureSessionState();
|
|
650
|
+
await setSessionPanel("connectors", session.currentFocus);
|
|
651
|
+
const answer = await prompts({
|
|
652
|
+
type: "select",
|
|
653
|
+
name: "value",
|
|
654
|
+
message: "Connector flow",
|
|
655
|
+
choices: [
|
|
656
|
+
{ title: "Overview", description: "See installed connectors and the latest run state", value: "overview" },
|
|
657
|
+
{ title: "List connectors", description: "See repo connectors already installed", value: "list" },
|
|
658
|
+
{ title: "Inspect connector", description: "Read connector details and recommended next steps", value: "inspect" },
|
|
659
|
+
{ title: "Inspect recent connector", description: "Open the connector you touched most recently", value: "recent" },
|
|
660
|
+
{ title: "View outputs", description: "See connector-written files and the latest run summary", value: "outputs" },
|
|
661
|
+
{ title: "Install connector", description: "Add a connector into this repo", value: "install" },
|
|
662
|
+
{ title: "Run connector", description: "Execute a connector inside this repo", value: "run" },
|
|
663
|
+
{ title: "Back", value: "back" },
|
|
664
|
+
],
|
|
665
|
+
});
|
|
666
|
+
if (!answer.value || answer.value === "back")
|
|
667
|
+
return;
|
|
668
|
+
if (answer.value === "overview") {
|
|
669
|
+
await printConnectorOverview();
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
let target;
|
|
673
|
+
if (answer.value === "run" || answer.value === "inspect" || answer.value === "outputs") {
|
|
674
|
+
const installed = await getInstalledConnectors();
|
|
675
|
+
if (installed.length === 0) {
|
|
676
|
+
console.log(chalk.yellow("\n No connectors installed in this repo yet."));
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
const runAnswer = await prompts({
|
|
680
|
+
type: "select",
|
|
681
|
+
name: "value",
|
|
682
|
+
message: answer.value === "outputs" ? "Choose a connector to inspect outputs for" : "Choose a connector to run",
|
|
683
|
+
choices: installed.map((entry) => ({
|
|
684
|
+
title: `${entry.name} (${entry.type})`,
|
|
685
|
+
value: entry.source,
|
|
686
|
+
})),
|
|
687
|
+
});
|
|
688
|
+
target = runAnswer.value;
|
|
689
|
+
if (!target) {
|
|
690
|
+
console.log(chalk.yellow("\n No connector selected."));
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
const result = await connectorsCommandAction(answer.value, target);
|
|
695
|
+
if (result?.action === "install" && result.connectorName) {
|
|
696
|
+
const lines = [`Connector: ${result.connectorName}`];
|
|
697
|
+
if (result.repoConfigPath)
|
|
698
|
+
lines.push(`Repo MCP wiring: ${result.repoConfigPath}`);
|
|
699
|
+
if (result.filePaths && result.filePaths.length > 0) {
|
|
700
|
+
lines.push(`${result.filePaths.length} connector file${result.filePaths.length === 1 ? "" : "s"} added or refreshed`);
|
|
701
|
+
}
|
|
702
|
+
lines.push('Running the connector will verify repo wiring and save a local run report in ".um".');
|
|
703
|
+
printSessionHint("Connector Install Summary", lines);
|
|
704
|
+
const runNow = await prompts({
|
|
705
|
+
type: "confirm",
|
|
706
|
+
name: "value",
|
|
707
|
+
message: "Run a connector now?",
|
|
708
|
+
initial: true,
|
|
709
|
+
});
|
|
710
|
+
if (runNow.value) {
|
|
711
|
+
const runResult = await connectorsCommandAction("run");
|
|
712
|
+
if (runResult?.connectorName) {
|
|
713
|
+
const lines = [
|
|
714
|
+
`Connector: ${runResult.connectorName}`,
|
|
715
|
+
`Status: ${runResult.status ?? "unknown"}`,
|
|
716
|
+
];
|
|
717
|
+
if (runResult.summary)
|
|
718
|
+
lines.push(runResult.summary);
|
|
719
|
+
if (runResult.stagedMemoryId)
|
|
720
|
+
lines.push(`Staged local draft: ${runResult.stagedMemoryId}`);
|
|
721
|
+
if (runResult.reportPath)
|
|
722
|
+
lines.push(`Run report: ${runResult.reportPath}`);
|
|
723
|
+
if (runResult.status === "success")
|
|
724
|
+
lines.push('Next move: run "/status" to review the updated repo state.');
|
|
725
|
+
printSessionHint("Connector Run Summary", lines);
|
|
726
|
+
const inspectOutputs = await prompts({
|
|
727
|
+
type: "confirm",
|
|
728
|
+
name: "value",
|
|
729
|
+
message: "Inspect this connector's outputs now?",
|
|
730
|
+
initial: true,
|
|
731
|
+
});
|
|
732
|
+
if (inspectOutputs.value && runResult.inspectedConnector) {
|
|
733
|
+
await connectorsCommandAction("outputs", runResult.inspectedConnector);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
else if (result?.action === "run" && result.connectorName) {
|
|
739
|
+
const lines = [
|
|
740
|
+
`Connector: ${result.connectorName}`,
|
|
741
|
+
`Status: ${result.status ?? "unknown"}`,
|
|
742
|
+
];
|
|
743
|
+
if (result.summary)
|
|
744
|
+
lines.push(result.summary);
|
|
745
|
+
if (result.stagedMemoryId)
|
|
746
|
+
lines.push(`Staged local draft: ${result.stagedMemoryId}`);
|
|
747
|
+
if (result.reportPath)
|
|
748
|
+
lines.push(`Run report: ${result.reportPath}`);
|
|
749
|
+
printSessionHint("Connector Run Summary", lines);
|
|
750
|
+
const inspectOutputs = await prompts({
|
|
751
|
+
type: "confirm",
|
|
752
|
+
name: "value",
|
|
753
|
+
message: "Inspect this connector's outputs now?",
|
|
754
|
+
initial: true,
|
|
755
|
+
});
|
|
756
|
+
if (inspectOutputs.value && target) {
|
|
757
|
+
await connectorsCommandAction("outputs", target);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
async function maybeHandleNativeMenu(command, args, config) {
|
|
763
|
+
if (args.length > 0)
|
|
764
|
+
return false;
|
|
765
|
+
if (command === "space" || command === "spaces" || command === "projects") {
|
|
766
|
+
await openSpaceMenu(config);
|
|
767
|
+
return true;
|
|
768
|
+
}
|
|
769
|
+
if (command === "providers") {
|
|
770
|
+
await openProvidersMenu();
|
|
771
|
+
return true;
|
|
772
|
+
}
|
|
773
|
+
if (command === "model") {
|
|
774
|
+
await openModelMenu();
|
|
775
|
+
return true;
|
|
776
|
+
}
|
|
777
|
+
if (command === "hub") {
|
|
778
|
+
await openHubMenu();
|
|
779
|
+
return true;
|
|
780
|
+
}
|
|
781
|
+
if (command === "connectors") {
|
|
782
|
+
await openConnectorsMenu();
|
|
783
|
+
return true;
|
|
784
|
+
}
|
|
785
|
+
return false;
|
|
786
|
+
}
|
|
787
|
+
export async function interactiveCommand(_args) {
|
|
788
|
+
if (!configManager.config) {
|
|
789
|
+
console.log(chalk.red("Not configured. Run: umbrella-context setup"));
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
const commandHistory = [];
|
|
793
|
+
await ensureSessionState();
|
|
794
|
+
await setSessionPanel("home", configManager.config.projectName);
|
|
795
|
+
await printRuntimeSnapshot();
|
|
796
|
+
await printHomeView(configManager.config);
|
|
797
|
+
console.log(chalk.gray(" Type / to see commands. Use plain text to query or start with + to curate.\n"));
|
|
798
|
+
while (true) {
|
|
799
|
+
const currentConfig = configManager.config;
|
|
800
|
+
if (!currentConfig) {
|
|
801
|
+
console.log(chalk.red("Config was cleared. Run umbrella-context setup again."));
|
|
802
|
+
break;
|
|
803
|
+
}
|
|
804
|
+
const input = await prompts({
|
|
805
|
+
type: "text",
|
|
806
|
+
name: "value",
|
|
807
|
+
message: chalk.cyan(`${currentConfig.companyName.toLowerCase().replace(/\s+/g, "-")}:${currentConfig.projectName.toLowerCase()}`),
|
|
808
|
+
initial: "/",
|
|
809
|
+
});
|
|
810
|
+
if (typeof input.value !== "string")
|
|
811
|
+
break;
|
|
812
|
+
const raw = input.value.trim();
|
|
813
|
+
if (!raw)
|
|
814
|
+
continue;
|
|
815
|
+
if (raw === "/" || raw === "help" || raw === "/help") {
|
|
816
|
+
console.log(chalk.gray(`\n${renderCommandList()}\n`));
|
|
817
|
+
continue;
|
|
818
|
+
}
|
|
819
|
+
if (raw === "exit" || raw === "/exit" || raw === "quit" || raw === "/quit") {
|
|
820
|
+
break;
|
|
821
|
+
}
|
|
822
|
+
if (raw.startsWith("+")) {
|
|
823
|
+
const content = raw.slice(1).trim();
|
|
824
|
+
if (!content) {
|
|
825
|
+
console.log(chalk.yellow("Use + followed by what you learned, for example +We learned the CTA must name the next step."));
|
|
826
|
+
continue;
|
|
827
|
+
}
|
|
828
|
+
commandHistory.push(`/curate ${content}`);
|
|
829
|
+
await recordSessionCommand(`/curate ${content}`);
|
|
830
|
+
await recordSessionCuration(content);
|
|
831
|
+
await setSessionSummary(`Curated a new local note: ${content.length > 48 ? `${content.slice(0, 48)}...` : content}`);
|
|
832
|
+
try {
|
|
833
|
+
await curateCommandAction(content);
|
|
834
|
+
}
|
|
835
|
+
catch (err) {
|
|
836
|
+
console.log(chalk.red(`Command failed: ${err.message}`));
|
|
837
|
+
}
|
|
838
|
+
continue;
|
|
839
|
+
}
|
|
840
|
+
const { command, args } = parseInteractiveInput(raw);
|
|
841
|
+
const spec = resolveCommand(command);
|
|
842
|
+
if (!raw.startsWith("/") && !spec) {
|
|
843
|
+
commandHistory.push(`/query ${raw}`);
|
|
844
|
+
await recordSessionCommand(`/query ${raw}`);
|
|
845
|
+
await recordSessionQuery(raw);
|
|
846
|
+
await setSessionSummary(`Queried Context: ${raw.length > 48 ? `${raw.slice(0, 48)}...` : raw}`);
|
|
847
|
+
try {
|
|
848
|
+
await searchCommandAction(raw);
|
|
849
|
+
}
|
|
850
|
+
catch (err) {
|
|
851
|
+
console.log(chalk.red(`Command failed: ${err.message}`));
|
|
852
|
+
}
|
|
853
|
+
continue;
|
|
854
|
+
}
|
|
855
|
+
if (!spec) {
|
|
856
|
+
console.log(chalk.yellow(`Unknown command: ${raw}. Type / to see available commands.`));
|
|
857
|
+
continue;
|
|
858
|
+
}
|
|
859
|
+
commandHistory.push(raw.startsWith("/") ? raw : `/${command} ${args.join(" ")}`.trim());
|
|
860
|
+
await recordSessionCommand(raw.startsWith("/") ? raw : `/${command} ${args.join(" ")}`.trim());
|
|
861
|
+
try {
|
|
862
|
+
const handledByMenu = await maybeHandleNativeMenu(command, args, currentConfig);
|
|
863
|
+
if (handledByMenu) {
|
|
864
|
+
continue;
|
|
865
|
+
}
|
|
866
|
+
await spec.action(args, {
|
|
867
|
+
config: currentConfig,
|
|
868
|
+
handleFix,
|
|
869
|
+
handleRecord,
|
|
870
|
+
handleSpaces,
|
|
871
|
+
handleHome: async (config) => printHomeView(config),
|
|
872
|
+
handleRecent,
|
|
873
|
+
handleActivity: async () => printActivityView(),
|
|
874
|
+
handleTimeline: async () => printTimelineView(),
|
|
875
|
+
handleHistory: async () => printHistory(commandHistory),
|
|
876
|
+
handleSession: async () => printSessionView(),
|
|
877
|
+
handleNewSession: async () => {
|
|
878
|
+
const next = await resetSessionState();
|
|
879
|
+
commandHistory.length = 0;
|
|
880
|
+
await recordSessionEvent({
|
|
881
|
+
kind: "session",
|
|
882
|
+
title: "Started a fresh shell session",
|
|
883
|
+
detail: `Session ID: ${next.id}`,
|
|
884
|
+
panel: "session",
|
|
885
|
+
focus: next.id,
|
|
886
|
+
status: "info",
|
|
887
|
+
});
|
|
888
|
+
printSessionHint("Fresh Session Started", [
|
|
889
|
+
`Session ID: ${next.id}`,
|
|
890
|
+
"Your repo context and .um data were kept.",
|
|
891
|
+
"Your command history for this shell was reset.",
|
|
892
|
+
]);
|
|
893
|
+
},
|
|
894
|
+
handleRestart: async () => {
|
|
895
|
+
await restartCommandAction();
|
|
896
|
+
commandHistory.length = 0;
|
|
897
|
+
},
|
|
898
|
+
handleDebug: async () => {
|
|
899
|
+
await debugCommandAction();
|
|
900
|
+
},
|
|
901
|
+
handleLogout: async () => {
|
|
902
|
+
await logoutCommandAction();
|
|
903
|
+
commandHistory.length = 0;
|
|
904
|
+
},
|
|
905
|
+
handlePanel: async () => {
|
|
906
|
+
await printCurrentPanelView();
|
|
907
|
+
},
|
|
908
|
+
handleContinue: async () => {
|
|
909
|
+
await continueLastPanel(currentConfig);
|
|
910
|
+
},
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
catch (err) {
|
|
914
|
+
console.log(chalk.red(`Command failed: ${err.message}`));
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
async function handleRecent(_config) {
|
|
919
|
+
await setSessionPanel("recent", "activity");
|
|
920
|
+
const pending = await getPendingMemories();
|
|
921
|
+
const pulled = await getPulledMemories();
|
|
922
|
+
const runs = await getConnectorRuns();
|
|
923
|
+
const session = await ensureSessionState();
|
|
924
|
+
console.log("");
|
|
925
|
+
printRecentSection("Recent session queries", session.recentQueries.slice(0, 3), (item, index) => {
|
|
926
|
+
return ` ${index + 1}. ${item}`;
|
|
927
|
+
});
|
|
928
|
+
printRecentSection("Recent session curations", session.recentCurations.slice(0, 3), (item, index) => {
|
|
929
|
+
return ` ${index + 1}. ${item}`;
|
|
930
|
+
});
|
|
931
|
+
printRecentSection("Recent local drafts", pending.slice(-3).reverse(), (item, index) => {
|
|
932
|
+
const preview = item.content.length > 72 ? `${item.content.slice(0, 72)}...` : item.content;
|
|
933
|
+
return ` ${index + 1}. ${preview} ${chalk.gray(`[${item.source}]`)}`;
|
|
934
|
+
});
|
|
935
|
+
printRecentSection("Recent pulled context", pulled.slice(-3).reverse(), (item, index) => {
|
|
936
|
+
const preview = item.content.length > 72 ? `${item.content.slice(0, 72)}...` : item.content;
|
|
937
|
+
return ` ${index + 1}. ${preview}`;
|
|
938
|
+
});
|
|
939
|
+
printRecentSection("Recent connector runs", runs.slice(0, 3), (item, index) => {
|
|
940
|
+
return ` ${index + 1}. ${item.connectorName} ${chalk.gray(`(${item.status})`)} - ${item.summary}`;
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
async function printHistory(commandHistory) {
|
|
944
|
+
const session = await ensureSessionState();
|
|
945
|
+
console.log("");
|
|
946
|
+
console.log(chalk.bold(" Session command history"));
|
|
947
|
+
const history = session.commandHistory.length > 0 ? session.commandHistory : commandHistory;
|
|
948
|
+
if (history.length === 0) {
|
|
949
|
+
console.log(chalk.gray(" No commands yet."));
|
|
950
|
+
console.log("");
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
history.slice(-10).forEach((entry, index) => {
|
|
954
|
+
console.log(` ${index + 1}. ${entry}`);
|
|
955
|
+
});
|
|
956
|
+
console.log("");
|
|
957
|
+
}
|
|
73
958
|
async function handleFix(error, config) {
|
|
74
959
|
if (!error) {
|
|
75
|
-
console.log(chalk.red("Usage: fix <error>"));
|
|
960
|
+
console.log(chalk.red("Usage: /fix <error>"));
|
|
76
961
|
return;
|
|
77
962
|
}
|
|
78
963
|
try {
|
|
964
|
+
const localFixes = await getPulledFixes();
|
|
965
|
+
const localMatches = localFixes.filter((entry) => [entry.errorSignal, entry.solution].join(" ").toLowerCase().includes(error.toLowerCase()));
|
|
966
|
+
if (localMatches.length > 0) {
|
|
967
|
+
console.log(chalk.cyan("\n Local cached fixes\n"));
|
|
968
|
+
localMatches.forEach((result, index) => {
|
|
969
|
+
const pct = Math.round(result.confidence * 100);
|
|
970
|
+
console.log(chalk.cyan(` ${index + 1}. [${pct}%] ${result.errorSignal}`));
|
|
971
|
+
console.log(` ${result.solution}`);
|
|
972
|
+
});
|
|
973
|
+
console.log("");
|
|
974
|
+
}
|
|
79
975
|
const res = await fetch(`${config.serverUrl}/api/evolutions/search?error=${encodeURIComponent(error)}`, { headers: { Authorization: `Bearer ${config.apiKey}` } });
|
|
80
|
-
if (!res.ok)
|
|
976
|
+
if (!res.ok) {
|
|
977
|
+
console.log(chalk.red("Server search failed."));
|
|
81
978
|
return;
|
|
979
|
+
}
|
|
82
980
|
const data = await res.json();
|
|
83
|
-
if (data.results.length === 0) {
|
|
981
|
+
if (data.results.length === 0 && localMatches.length === 0) {
|
|
84
982
|
console.log(chalk.yellow("No known fixes"));
|
|
85
983
|
return;
|
|
86
984
|
}
|
|
87
|
-
data.results.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
985
|
+
if (data.results.length > 0) {
|
|
986
|
+
console.log(chalk.cyan(" Server results\n"));
|
|
987
|
+
data.results.forEach((result, index) => {
|
|
988
|
+
const pct = Math.round(result.confidence * 100);
|
|
989
|
+
console.log(chalk.cyan(` ${index + 1}. [${pct}%]`));
|
|
990
|
+
console.log(` ${result.solution}`);
|
|
991
|
+
console.log(chalk.gray(` ${result.timesSucceeded}/${result.timesApplied} successes | ID: ${result.id}`));
|
|
992
|
+
console.log("");
|
|
993
|
+
});
|
|
994
|
+
}
|
|
94
995
|
}
|
|
95
996
|
catch (err) {
|
|
96
997
|
console.log(chalk.red(`Error: ${err.message}`));
|
|
@@ -99,7 +1000,7 @@ async function handleFix(error, config) {
|
|
|
99
1000
|
async function handleRecord(parts, config) {
|
|
100
1001
|
const [id, outcome] = parts;
|
|
101
1002
|
if (!id || !["success", "failure"].includes(outcome)) {
|
|
102
|
-
console.log(chalk.red("Usage: record <id> <success|failure>"));
|
|
1003
|
+
console.log(chalk.red("Usage: /record <id> <success|failure>"));
|
|
103
1004
|
return;
|
|
104
1005
|
}
|
|
105
1006
|
try {
|
|
@@ -111,8 +1012,10 @@ async function handleRecord(parts, config) {
|
|
|
111
1012
|
},
|
|
112
1013
|
body: JSON.stringify({ outcome }),
|
|
113
1014
|
});
|
|
114
|
-
if (!res.ok)
|
|
1015
|
+
if (!res.ok) {
|
|
1016
|
+
console.log(chalk.red("Could not record the fix outcome."));
|
|
115
1017
|
return;
|
|
1018
|
+
}
|
|
116
1019
|
const data = await res.json();
|
|
117
1020
|
const pct = Math.round(data.confidence * 100);
|
|
118
1021
|
console.log(chalk.green(`Recorded ${outcome} - confidence: ${pct}%`));
|
|
@@ -122,8 +1025,12 @@ async function handleRecord(parts, config) {
|
|
|
122
1025
|
}
|
|
123
1026
|
}
|
|
124
1027
|
async function handleSpaces(config) {
|
|
1028
|
+
const pending = await getPendingMemories();
|
|
1029
|
+
const pulled = await getPulledMemories();
|
|
125
1030
|
console.log(chalk.cyan(` Current company: ${config.companyName}`));
|
|
126
1031
|
console.log(chalk.cyan(` Current space: ${config.projectName}`));
|
|
1032
|
+
console.log(chalk.gray(` Local context notes waiting to push: ${pending.length}`));
|
|
1033
|
+
console.log(chalk.gray(` Local pulled snapshot size: ${pulled.length}`));
|
|
127
1034
|
if (!config.umbrellaUrl) {
|
|
128
1035
|
console.log(chalk.gray(" Run setup again if you want this terminal to list all company spaces."));
|
|
129
1036
|
return;
|
|
@@ -137,9 +1044,10 @@ async function handleSpaces(config) {
|
|
|
137
1044
|
const core = space.isPrimary ? " [core]" : "";
|
|
138
1045
|
console.log(chalk.gray(` ${index + 1}. ${space.name}${core}${active}`));
|
|
139
1046
|
});
|
|
140
|
-
console.log(chalk.gray('\n
|
|
1047
|
+
console.log(chalk.gray('\n Run "/space switch" to move this repo to another space.'));
|
|
141
1048
|
}
|
|
142
1049
|
catch (err) {
|
|
143
1050
|
console.log(chalk.red(` Could not load spaces: ${err.message}`));
|
|
144
1051
|
}
|
|
145
1052
|
}
|
|
1053
|
+
export { renderCommandList };
|