umbrella-context 0.1.2 → 0.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/catalog.d.ts +33 -0
- package/dist/commands/catalog.js +211 -0
- package/dist/commands/connect.js +14 -14
- package/dist/commands/connectors.d.ts +15 -0
- package/dist/commands/connectors.js +620 -0
- package/dist/commands/curate.d.ts +1 -0
- package/dist/commands/curate.js +39 -3
- package/dist/commands/debug.d.ts +2 -0
- package/dist/commands/debug.js +55 -0
- package/dist/commands/hub.d.ts +20 -0
- package/dist/commands/hub.js +429 -0
- package/dist/commands/interactive.d.ts +2 -0
- package/dist/commands/interactive.js +918 -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 +211 -0
- package/dist/commands/providers.d.ts +17 -0
- package/dist/commands/providers.js +344 -0
- package/dist/commands/pull.js +10 -1
- package/dist/commands/push.js +18 -1
- package/dist/commands/restart.d.ts +2 -0
- package/dist/commands/restart.js +21 -0
- package/dist/commands/search.js +19 -1
- package/dist/commands/session.d.ts +2 -0
- package/dist/commands/session.js +128 -0
- package/dist/commands/space.d.ts +1 -0
- package/dist/commands/space.js +81 -63
- package/dist/commands/status.d.ts +25 -0
- package/dist/commands/status.js +104 -16
- package/dist/config.d.ts +23 -0
- package/dist/config.js +69 -0
- package/dist/index.js +26 -4
- package/dist/repo-state.d.ts +84 -0
- package/dist/repo-state.js +419 -3
- package/package.json +1 -1
package/dist/commands/pull.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { configManager } from "../config.js";
|
|
3
|
-
import { ensureRepoContext, setPulledFixes, setPulledMemories } from "../repo-state.js";
|
|
3
|
+
import { ensureRepoContext, recordSessionEvent, setPulledFixes, setPulledMemories, setSessionPanel } from "../repo-state.js";
|
|
4
4
|
export async function pullCommandAction() {
|
|
5
5
|
const config = configManager.config;
|
|
6
6
|
if (!config) {
|
|
@@ -9,6 +9,7 @@ export async function pullCommandAction() {
|
|
|
9
9
|
}
|
|
10
10
|
try {
|
|
11
11
|
await ensureRepoContext(config);
|
|
12
|
+
await setSessionPanel("pull", config.projectName);
|
|
12
13
|
const [memoriesRes, fixesRes] = await Promise.all([
|
|
13
14
|
fetch(`${config.serverUrl}/api/memories?limit=50`, {
|
|
14
15
|
headers: { Authorization: `Bearer ${config.apiKey}` },
|
|
@@ -42,6 +43,14 @@ export async function pullCommandAction() {
|
|
|
42
43
|
createdAt: entry.createdAt ?? new Date().toISOString(),
|
|
43
44
|
lastApplied: entry.lastApplied ?? null,
|
|
44
45
|
})));
|
|
46
|
+
await recordSessionEvent({
|
|
47
|
+
kind: "pull",
|
|
48
|
+
title: `Pulled ${memoriesJson.results?.length ?? 0} Context entr${(memoriesJson.results?.length ?? 0) === 1 ? "y" : "ies"}`,
|
|
49
|
+
detail: `Cached ${fixesJson.results?.length ?? 0} known fix${(fixesJson.results?.length ?? 0) === 1 ? "" : "es"} for ${config.companyName} / ${config.projectName}.`,
|
|
50
|
+
panel: "pull",
|
|
51
|
+
focus: config.projectName,
|
|
52
|
+
status: "success",
|
|
53
|
+
});
|
|
45
54
|
console.log(chalk.green(`\n Pulled ${memoriesJson.results?.length ?? 0} context entries from the server.`));
|
|
46
55
|
console.log(chalk.gray(` Company: ${config.companyName}`));
|
|
47
56
|
console.log(chalk.gray(` Space: ${config.projectName}`));
|
package/dist/commands/push.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { configManager } from "../config.js";
|
|
3
|
-
import { clearPendingMemories, ensureRepoContext, getPendingMemories, getPulledMemories, markPushCompleted, setPulledMemories, } from "../repo-state.js";
|
|
3
|
+
import { clearPendingMemories, ensureRepoContext, getPendingMemories, getPulledMemories, markPushCompleted, recordSessionEvent, setSessionPanel, setPulledMemories, } from "../repo-state.js";
|
|
4
4
|
export async function pushCommandAction() {
|
|
5
5
|
const config = configManager.config;
|
|
6
6
|
if (!config) {
|
|
@@ -9,8 +9,17 @@ export async function pushCommandAction() {
|
|
|
9
9
|
}
|
|
10
10
|
try {
|
|
11
11
|
await ensureRepoContext(config);
|
|
12
|
+
await setSessionPanel("push", config.projectName);
|
|
12
13
|
const pending = await getPendingMemories();
|
|
13
14
|
if (pending.length === 0) {
|
|
15
|
+
await recordSessionEvent({
|
|
16
|
+
kind: "push",
|
|
17
|
+
title: "Push skipped because nothing was pending",
|
|
18
|
+
detail: `This repo had no local drafts waiting to sync for ${config.companyName} / ${config.projectName}.`,
|
|
19
|
+
panel: "push",
|
|
20
|
+
focus: config.projectName,
|
|
21
|
+
status: "info",
|
|
22
|
+
});
|
|
14
23
|
console.log(chalk.yellow("\n Nothing to push. Your local .um folder is already in sync."));
|
|
15
24
|
return;
|
|
16
25
|
}
|
|
@@ -50,6 +59,14 @@ export async function pushCommandAction() {
|
|
|
50
59
|
]);
|
|
51
60
|
await clearPendingMemories();
|
|
52
61
|
await markPushCompleted();
|
|
62
|
+
await recordSessionEvent({
|
|
63
|
+
kind: "push",
|
|
64
|
+
title: `Pushed ${synced.length} Context entr${synced.length === 1 ? "y" : "ies"}`,
|
|
65
|
+
detail: `Shared local drafts from ${config.companyName} / ${config.projectName} with the server.`,
|
|
66
|
+
panel: "push",
|
|
67
|
+
focus: config.projectName,
|
|
68
|
+
status: "success",
|
|
69
|
+
});
|
|
53
70
|
console.log(chalk.green(`\n Pushed ${synced.length} local context entr${synced.length === 1 ? "y" : "ies"}.`));
|
|
54
71
|
console.log(chalk.gray(` Company: ${config.companyName}`));
|
|
55
72
|
console.log(chalk.gray(` Space: ${config.projectName}`));
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { configManager } from "../config.js";
|
|
3
|
+
import { ensureRepoContext, ensureSessionState, resetSessionState } from "../repo-state.js";
|
|
4
|
+
export async function restartCommandAction() {
|
|
5
|
+
const config = configManager.config;
|
|
6
|
+
if (!config) {
|
|
7
|
+
console.log(chalk.red("Not configured. Run: umbrella-context setup"));
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
await ensureRepoContext(config);
|
|
11
|
+
const session = await resetSessionState();
|
|
12
|
+
await ensureSessionState();
|
|
13
|
+
console.log(chalk.green("\n Context terminal restarted for this repo."));
|
|
14
|
+
console.log(chalk.gray(` New session: ${session.id}`));
|
|
15
|
+
console.log(chalk.gray(" Local .um context files were kept. Only the live shell session was refreshed."));
|
|
16
|
+
}
|
|
17
|
+
export function restartCommand(cli) {
|
|
18
|
+
cli.command("restart", "Refresh the local repo session without deleting .um data").action(async () => {
|
|
19
|
+
await restartCommandAction();
|
|
20
|
+
});
|
|
21
|
+
}
|
package/dist/commands/search.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { configManager } from "../config.js";
|
|
3
|
-
import { getPendingMemories, getPulledMemories, summarizeLocalMemoryMatches } from "../repo-state.js";
|
|
3
|
+
import { getPendingMemories, getPulledMemories, recordSessionEvent, recordSessionQuery, setSessionPanel, summarizeLocalMemoryMatches } from "../repo-state.js";
|
|
4
4
|
export async function searchCommandAction(query) {
|
|
5
5
|
const config = configManager.config;
|
|
6
6
|
if (!config) {
|
|
@@ -8,6 +8,8 @@ export async function searchCommandAction(query) {
|
|
|
8
8
|
return;
|
|
9
9
|
}
|
|
10
10
|
try {
|
|
11
|
+
await setSessionPanel("query", query);
|
|
12
|
+
await recordSessionQuery(query);
|
|
11
13
|
const localMatches = summarizeLocalMemoryMatches([...(await getPendingMemories()), ...(await getPulledMemories())], query);
|
|
12
14
|
const res = await fetch(`${config.serverUrl}/api/memories/search?query=${encodeURIComponent(query)}`, {
|
|
13
15
|
headers: { Authorization: `Bearer ${config.apiKey}` },
|
|
@@ -19,9 +21,25 @@ export async function searchCommandAction(query) {
|
|
|
19
21
|
}
|
|
20
22
|
const data = await res.json();
|
|
21
23
|
if (data.results.length === 0 && localMatches.length === 0) {
|
|
24
|
+
await recordSessionEvent({
|
|
25
|
+
kind: "query",
|
|
26
|
+
title: `No context found for "${query}"`,
|
|
27
|
+
detail: "The query did not match local drafts or server context.",
|
|
28
|
+
panel: "query",
|
|
29
|
+
focus: query,
|
|
30
|
+
status: "warning",
|
|
31
|
+
});
|
|
22
32
|
console.log(chalk.yellow(`\n No context found for "${query}"`));
|
|
23
33
|
return;
|
|
24
34
|
}
|
|
35
|
+
await recordSessionEvent({
|
|
36
|
+
kind: "query",
|
|
37
|
+
title: `Searched Context for "${query}"`,
|
|
38
|
+
detail: `Found ${localMatches.length} local match${localMatches.length === 1 ? "" : "es"} and ${data.results.length} server match${data.results.length === 1 ? "" : "es"}.`,
|
|
39
|
+
panel: "query",
|
|
40
|
+
focus: query,
|
|
41
|
+
status: "success",
|
|
42
|
+
});
|
|
25
43
|
console.log(chalk.bold(`\n Found context for ${config.companyName} / ${config.projectName}:\n`));
|
|
26
44
|
if (localMatches.length > 0) {
|
|
27
45
|
console.log(chalk.cyan(" Local .um matches:\n"));
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { ensureSessionState, getConnectorRuns, getInstalledConnectors, getInstalledHubEntries, getPendingMemories, getPulledFixes, getPulledMemories, } from "../repo-state.js";
|
|
3
|
+
import { getStatusSnapshot } from "./status.js";
|
|
4
|
+
function divider() {
|
|
5
|
+
return chalk.gray("------------------------------------------------------------");
|
|
6
|
+
}
|
|
7
|
+
function line(label, value) {
|
|
8
|
+
return ` ${chalk.cyan(label.padEnd(18))} ${value}`;
|
|
9
|
+
}
|
|
10
|
+
async function printSessionSummary() {
|
|
11
|
+
const snapshot = await getStatusSnapshot();
|
|
12
|
+
const session = await ensureSessionState();
|
|
13
|
+
console.log(chalk.bold("\n Session Summary\n"));
|
|
14
|
+
console.log(line("Company", snapshot.companyName));
|
|
15
|
+
console.log(line("Space", snapshot.spaceName));
|
|
16
|
+
console.log(line("Current panel", snapshot.currentPanel));
|
|
17
|
+
console.log(line("Current focus", snapshot.currentFocus));
|
|
18
|
+
console.log(line("Latest event", snapshot.latestEvent));
|
|
19
|
+
console.log(line("Commands", String(session.commandHistory.length)));
|
|
20
|
+
console.log(line("Queries", String(session.recentQueries.length)));
|
|
21
|
+
console.log(line("Curations", String(session.recentCurations.length)));
|
|
22
|
+
console.log("");
|
|
23
|
+
}
|
|
24
|
+
async function printSessionTimeline() {
|
|
25
|
+
const session = await ensureSessionState();
|
|
26
|
+
console.log(chalk.bold("\n Session Timeline\n"));
|
|
27
|
+
console.log(divider());
|
|
28
|
+
if ((session.events?.length ?? 0) === 0) {
|
|
29
|
+
console.log(chalk.gray(" No session events yet."));
|
|
30
|
+
console.log("");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
session.events.slice(0, 12).forEach((entry, index) => {
|
|
34
|
+
const badge = entry.status === "success" ? chalk.green(`[${entry.kind}]`)
|
|
35
|
+
: entry.status === "warning" ? chalk.yellow(`[${entry.kind}]`)
|
|
36
|
+
: entry.status === "failure" ? chalk.red(`[${entry.kind}]`)
|
|
37
|
+
: chalk.cyan(`[${entry.kind}]`);
|
|
38
|
+
console.log(` ${index + 1}. ${badge} ${entry.title}`);
|
|
39
|
+
console.log(chalk.gray(` ${new Date(entry.at).toLocaleString()}`));
|
|
40
|
+
if (entry.detail) {
|
|
41
|
+
console.log(chalk.gray(` ${entry.detail}`));
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
console.log("");
|
|
45
|
+
}
|
|
46
|
+
async function printSessionPanel() {
|
|
47
|
+
const session = await ensureSessionState();
|
|
48
|
+
const latestPanelEvent = (session.events ?? []).find((entry) => entry.panel === session.currentPanel);
|
|
49
|
+
console.log(chalk.bold("\n Live Panel\n"));
|
|
50
|
+
console.log(divider());
|
|
51
|
+
console.log(line("Panel", session.currentPanel ?? "None"));
|
|
52
|
+
console.log(line("Focus", session.currentFocus ?? "None"));
|
|
53
|
+
console.log(line("Last panel event", latestPanelEvent?.title ?? "Nothing panel-specific yet"));
|
|
54
|
+
if (session.panelHistory.length > 0) {
|
|
55
|
+
console.log("");
|
|
56
|
+
console.log(chalk.bold(" Recent panels"));
|
|
57
|
+
session.panelHistory.slice(0, 5).forEach((entry, index) => {
|
|
58
|
+
console.log(` ${index + 1}. ${entry}`);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
console.log("");
|
|
62
|
+
}
|
|
63
|
+
async function printSessionRecent() {
|
|
64
|
+
const pending = await getPendingMemories();
|
|
65
|
+
const pulled = await getPulledMemories();
|
|
66
|
+
const fixes = await getPulledFixes();
|
|
67
|
+
const connectors = await getConnectorRuns();
|
|
68
|
+
const hub = await getInstalledHubEntries();
|
|
69
|
+
const installedConnectors = await getInstalledConnectors();
|
|
70
|
+
console.log(chalk.bold("\n Recent Repo Activity\n"));
|
|
71
|
+
console.log(divider());
|
|
72
|
+
console.log(line("Pending drafts", String(pending.length)));
|
|
73
|
+
console.log(line("Pulled context", String(pulled.length)));
|
|
74
|
+
console.log(line("Known fixes", String(fixes.length)));
|
|
75
|
+
console.log(line("Hub installs", String(hub.length)));
|
|
76
|
+
console.log(line("Connectors", String(installedConnectors.length)));
|
|
77
|
+
console.log(line("Connector runs", String(connectors.length)));
|
|
78
|
+
if (connectors[0]) {
|
|
79
|
+
console.log("");
|
|
80
|
+
console.log(chalk.bold(" Latest connector run"));
|
|
81
|
+
console.log(` ${connectors[0].connectorName} (${connectors[0].status})`);
|
|
82
|
+
console.log(chalk.gray(` ${connectors[0].summary}`));
|
|
83
|
+
}
|
|
84
|
+
console.log("");
|
|
85
|
+
}
|
|
86
|
+
async function printSessionHistory() {
|
|
87
|
+
const session = await ensureSessionState();
|
|
88
|
+
console.log(chalk.bold("\n Session History\n"));
|
|
89
|
+
console.log(divider());
|
|
90
|
+
if (session.commandHistory.length === 0) {
|
|
91
|
+
console.log(chalk.gray(" No commands recorded yet."));
|
|
92
|
+
console.log("");
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
session.commandHistory.slice(0, 20).forEach((entry, index) => {
|
|
96
|
+
console.log(` ${index + 1}. ${entry}`);
|
|
97
|
+
});
|
|
98
|
+
console.log("");
|
|
99
|
+
}
|
|
100
|
+
export async function sessionCommandAction(action = "summary") {
|
|
101
|
+
const normalized = action.toLowerCase();
|
|
102
|
+
if (normalized === "summary") {
|
|
103
|
+
await printSessionSummary();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (normalized === "timeline") {
|
|
107
|
+
await printSessionTimeline();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (normalized === "panel") {
|
|
111
|
+
await printSessionPanel();
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (normalized === "recent") {
|
|
115
|
+
await printSessionRecent();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
if (normalized === "history") {
|
|
119
|
+
await printSessionHistory();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
console.log(chalk.red("Use: session summary | session timeline | session panel | session recent | session history"));
|
|
123
|
+
}
|
|
124
|
+
export function sessionCommand(cli) {
|
|
125
|
+
cli.command("session [action]", "Show persistent terminal session views for this repo").action(async (action) => {
|
|
126
|
+
await sessionCommandAction(action ?? "summary");
|
|
127
|
+
});
|
|
128
|
+
}
|
package/dist/commands/space.d.ts
CHANGED
package/dist/commands/space.js
CHANGED
|
@@ -1,75 +1,93 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import prompts from "prompts";
|
|
3
3
|
import { configManager } from "../config.js";
|
|
4
|
-
import { ensureRepoContext } from "../repo-state.js";
|
|
4
|
+
import { ensureRepoContext, recordSessionEvent, setSessionPanel } from "../repo-state.js";
|
|
5
5
|
import { getCliSetup, getCompanyContextSummary, toContextSpaces } from "../umbrella.js";
|
|
6
|
+
export async function spaceCommandAction(action, spaceArg) {
|
|
7
|
+
const config = configManager.config;
|
|
8
|
+
if (!config) {
|
|
9
|
+
console.log(chalk.red("Not configured. Run: umbrella-context setup"));
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
if (!config.umbrellaUrl) {
|
|
13
|
+
console.log(chalk.red("No Umbrella URL saved for this device. Run umbrella-context setup to enable space commands."));
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const normalizedAction = action.toLowerCase();
|
|
17
|
+
const summary = await getCompanyContextSummary(config.umbrellaUrl, config.companyId);
|
|
18
|
+
const spaces = toContextSpaces(summary);
|
|
19
|
+
if (normalizedAction === "list") {
|
|
20
|
+
await setSessionPanel("space", "list");
|
|
21
|
+
console.log(chalk.bold(`\n Spaces for ${config.companyName}\n`));
|
|
22
|
+
spaces.forEach((entry, index) => {
|
|
23
|
+
const active = entry.id === config.projectId ? " (active)" : "";
|
|
24
|
+
const primary = entry.isPrimary ? " [core]" : "";
|
|
25
|
+
console.log(` ${index + 1}. ${entry.name}${primary}${active}`);
|
|
26
|
+
});
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (normalizedAction !== "switch") {
|
|
30
|
+
console.log(chalk.red("Use either 'umbrella-context space list' or 'umbrella-context space switch'."));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
let chosen = spaces.find((entry) => entry.id === spaceArg || entry.name.toLowerCase() === (spaceArg ?? "").toLowerCase()) ?? null;
|
|
34
|
+
if (!chosen) {
|
|
35
|
+
const answer = await prompts({
|
|
36
|
+
type: "select",
|
|
37
|
+
name: "value",
|
|
38
|
+
message: "Choose a context space",
|
|
39
|
+
choices: spaces.map((entry) => ({
|
|
40
|
+
title: entry.isPrimary ? `${entry.name} (core)` : entry.name,
|
|
41
|
+
value: entry.id,
|
|
42
|
+
})),
|
|
43
|
+
});
|
|
44
|
+
chosen = spaces.find((entry) => entry.id === answer.value) ?? null;
|
|
45
|
+
}
|
|
46
|
+
if (!chosen) {
|
|
47
|
+
console.log(chalk.yellow("\n No space selected."));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const setup = await getCliSetup(config.umbrellaUrl, config.companyId, chosen.id);
|
|
51
|
+
configManager.set({
|
|
52
|
+
umbrellaUrl: config.umbrellaUrl,
|
|
53
|
+
serverUrl: setup.baseUrl,
|
|
54
|
+
apiKey: setup.apiKey,
|
|
55
|
+
companyId: setup.companyId,
|
|
56
|
+
companyName: setup.companyName,
|
|
57
|
+
workspaceId: setup.workspaceId,
|
|
58
|
+
workspaceName: setup.workspaceName,
|
|
59
|
+
projectId: setup.activeSpaceId,
|
|
60
|
+
projectName: setup.activeSpaceName,
|
|
61
|
+
});
|
|
62
|
+
configManager.upsertLocation({
|
|
63
|
+
repoRoot: process.cwd(),
|
|
64
|
+
companyId: setup.companyId,
|
|
65
|
+
companyName: setup.companyName,
|
|
66
|
+
projectId: setup.activeSpaceId,
|
|
67
|
+
projectName: setup.activeSpaceName,
|
|
68
|
+
updatedAt: new Date().toISOString(),
|
|
69
|
+
});
|
|
70
|
+
await ensureRepoContext(configManager.config);
|
|
71
|
+
await setSessionPanel("space", setup.activeSpaceName);
|
|
72
|
+
await recordSessionEvent({
|
|
73
|
+
kind: "space",
|
|
74
|
+
title: `Switched repo to ${setup.activeSpaceName}`,
|
|
75
|
+
detail: `The active Context space for ${setup.companyName} is now ${setup.activeSpaceName}.`,
|
|
76
|
+
panel: "space",
|
|
77
|
+
focus: setup.activeSpaceName,
|
|
78
|
+
status: "success",
|
|
79
|
+
});
|
|
80
|
+
console.log(chalk.green(`\n Switched to ${setup.companyName} / ${setup.activeSpaceName}`));
|
|
81
|
+
}
|
|
6
82
|
export function spaceCommand(cli) {
|
|
7
83
|
cli
|
|
8
84
|
.command("space <action> [space]", "List or switch context spaces for the current company")
|
|
9
85
|
.action(async (action, spaceArg) => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
console.log(chalk.red("Not configured. Run: umbrella-context setup"));
|
|
13
|
-
return;
|
|
86
|
+
try {
|
|
87
|
+
await spaceCommandAction(action, spaceArg);
|
|
14
88
|
}
|
|
15
|
-
|
|
16
|
-
console.log(chalk.red(
|
|
17
|
-
return;
|
|
89
|
+
catch (err) {
|
|
90
|
+
console.log(chalk.red(`Could not load spaces: ${err.message}`));
|
|
18
91
|
}
|
|
19
|
-
const normalizedAction = action.toLowerCase();
|
|
20
|
-
const summary = await getCompanyContextSummary(config.umbrellaUrl, config.companyId);
|
|
21
|
-
const spaces = toContextSpaces(summary);
|
|
22
|
-
if (normalizedAction === "list") {
|
|
23
|
-
console.log(chalk.bold(`\n Spaces for ${config.companyName}\n`));
|
|
24
|
-
spaces.forEach((entry, index) => {
|
|
25
|
-
const active = entry.id === config.projectId ? " (active)" : "";
|
|
26
|
-
const primary = entry.isPrimary ? " [core]" : "";
|
|
27
|
-
console.log(` ${index + 1}. ${entry.name}${primary}${active}`);
|
|
28
|
-
});
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
if (normalizedAction !== "switch") {
|
|
32
|
-
console.log(chalk.red("Use either 'umbrella-context space list' or 'umbrella-context space switch'."));
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
let chosen = spaces.find((entry) => entry.id === spaceArg || entry.name.toLowerCase() === (spaceArg ?? "").toLowerCase()) ?? null;
|
|
36
|
-
if (!chosen) {
|
|
37
|
-
const answer = await prompts({
|
|
38
|
-
type: "select",
|
|
39
|
-
name: "value",
|
|
40
|
-
message: "Choose a context space",
|
|
41
|
-
choices: spaces.map((entry) => ({
|
|
42
|
-
title: entry.isPrimary ? `${entry.name} (core)` : entry.name,
|
|
43
|
-
value: entry.id,
|
|
44
|
-
})),
|
|
45
|
-
});
|
|
46
|
-
chosen = spaces.find((entry) => entry.id === answer.value) ?? null;
|
|
47
|
-
}
|
|
48
|
-
if (!chosen) {
|
|
49
|
-
console.log(chalk.yellow("\n No space selected."));
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
const setup = await getCliSetup(config.umbrellaUrl, config.companyId, chosen.id);
|
|
53
|
-
configManager.set({
|
|
54
|
-
umbrellaUrl: config.umbrellaUrl,
|
|
55
|
-
serverUrl: setup.baseUrl,
|
|
56
|
-
apiKey: setup.apiKey,
|
|
57
|
-
companyId: setup.companyId,
|
|
58
|
-
companyName: setup.companyName,
|
|
59
|
-
workspaceId: setup.workspaceId,
|
|
60
|
-
workspaceName: setup.workspaceName,
|
|
61
|
-
projectId: setup.activeSpaceId,
|
|
62
|
-
projectName: setup.activeSpaceName,
|
|
63
|
-
});
|
|
64
|
-
configManager.upsertLocation({
|
|
65
|
-
repoRoot: process.cwd(),
|
|
66
|
-
companyId: setup.companyId,
|
|
67
|
-
companyName: setup.companyName,
|
|
68
|
-
projectId: setup.activeSpaceId,
|
|
69
|
-
projectName: setup.activeSpaceName,
|
|
70
|
-
updatedAt: new Date().toISOString(),
|
|
71
|
-
});
|
|
72
|
-
await ensureRepoContext(configManager.config);
|
|
73
|
-
console.log(chalk.green(`\n Switched to ${setup.companyName} / ${setup.activeSpaceName}`));
|
|
74
92
|
});
|
|
75
93
|
}
|
|
@@ -1,2 +1,27 @@
|
|
|
1
|
+
export type StatusSnapshot = {
|
|
2
|
+
companyName: string;
|
|
3
|
+
spaceName: string;
|
|
4
|
+
umbrellaUrl: string | null;
|
|
5
|
+
serverUrl: string;
|
|
6
|
+
currentDirectory: string;
|
|
7
|
+
repoRoot: string;
|
|
8
|
+
umDir: string;
|
|
9
|
+
pendingCount: number;
|
|
10
|
+
pulledContextCount: number;
|
|
11
|
+
pulledFixCount: number;
|
|
12
|
+
lastPushAt: string;
|
|
13
|
+
lastPullAt: string;
|
|
14
|
+
hubEntriesCount: number;
|
|
15
|
+
connectorsCount: number;
|
|
16
|
+
mcpConfigured: boolean;
|
|
17
|
+
latestConnectorRun: string;
|
|
18
|
+
providerLabel: string;
|
|
19
|
+
modelLabel: string;
|
|
20
|
+
currentPanel: string;
|
|
21
|
+
currentFocus: string;
|
|
22
|
+
latestEvent: string;
|
|
23
|
+
nextSteps: string[];
|
|
24
|
+
};
|
|
25
|
+
export declare function getStatusSnapshot(): Promise<StatusSnapshot>;
|
|
1
26
|
export declare function statusCommandAction(): Promise<void>;
|
|
2
27
|
export declare function statusCommand(cli: any): void;
|
package/dist/commands/status.js
CHANGED
|
@@ -1,29 +1,117 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import path from "path";
|
|
2
4
|
import { configManager } from "../config.js";
|
|
3
|
-
import { getPendingMemories, getPulledFixes, getPulledMemories, getRepoContext } from "../repo-state.js";
|
|
4
|
-
export async function
|
|
5
|
+
import { getConnectorRuns, getInstalledConnectors, getInstalledHubEntries, getPendingMemories, getPulledFixes, getPulledMemories, getRepoContext, ensureSessionState, } from "../repo-state.js";
|
|
6
|
+
export async function getStatusSnapshot() {
|
|
5
7
|
const config = configManager.config;
|
|
6
8
|
if (!config) {
|
|
7
|
-
|
|
8
|
-
return;
|
|
9
|
+
throw new Error("Not configured. Run: umbrella-context setup");
|
|
9
10
|
}
|
|
10
11
|
const { repoRoot, state, umDir } = await getRepoContext();
|
|
12
|
+
const session = await ensureSessionState();
|
|
13
|
+
const latestEvent = session.events?.[0] ?? null;
|
|
11
14
|
const pending = await getPendingMemories();
|
|
12
15
|
const pulledMemories = await getPulledMemories();
|
|
13
16
|
const pulledFixes = await getPulledFixes();
|
|
17
|
+
const connectors = await getInstalledConnectors();
|
|
18
|
+
const hubEntries = await getInstalledHubEntries();
|
|
19
|
+
const connectorRuns = await getConnectorRuns();
|
|
20
|
+
const activeProvider = configManager.providers.find((entry) => entry.id === config.activeProvider) ?? null;
|
|
21
|
+
const latestConnectorRun = connectorRuns[0] ?? null;
|
|
22
|
+
let mcpConfigured = false;
|
|
23
|
+
try {
|
|
24
|
+
const repoMcp = JSON.parse(await fs.readFile(path.join(repoRoot, ".mcp.json"), "utf8"));
|
|
25
|
+
mcpConfigured = Boolean(repoMcp?.mcpServers?.["umbrella-context"]);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
mcpConfigured = false;
|
|
29
|
+
}
|
|
30
|
+
const nextSteps = [];
|
|
31
|
+
if (pending.length > 0)
|
|
32
|
+
nextSteps.push(`Run "umbrella-context push" to share ${pending.length} local draft${pending.length === 1 ? "" : "s"}.`);
|
|
33
|
+
if (!activeProvider)
|
|
34
|
+
nextSteps.push('Connect a model provider with "umbrella-context providers connect".');
|
|
35
|
+
else if (!config.activeModel)
|
|
36
|
+
nextSteps.push('Pick a model with "umbrella-context model switch".');
|
|
37
|
+
if (!mcpConfigured)
|
|
38
|
+
nextSteps.push('Install the MCP bridge with "umbrella-context connectors install codex-mcp".');
|
|
39
|
+
if (connectors.length === 0)
|
|
40
|
+
nextSteps.push('Add a first repo connector with "umbrella-context connectors install".');
|
|
41
|
+
if (hubEntries.length === 0)
|
|
42
|
+
nextSteps.push('Browse reusable bundles with "umbrella-context hub list".');
|
|
43
|
+
return {
|
|
44
|
+
companyName: config.companyName,
|
|
45
|
+
spaceName: config.projectName,
|
|
46
|
+
umbrellaUrl: config.umbrellaUrl ?? null,
|
|
47
|
+
serverUrl: config.serverUrl,
|
|
48
|
+
currentDirectory: process.cwd(),
|
|
49
|
+
repoRoot,
|
|
50
|
+
umDir,
|
|
51
|
+
pendingCount: pending.length,
|
|
52
|
+
pulledContextCount: pulledMemories.length,
|
|
53
|
+
pulledFixCount: pulledFixes.length,
|
|
54
|
+
lastPushAt: state?.lastPushAt ?? "Never",
|
|
55
|
+
lastPullAt: state?.lastPullAt ?? "Never",
|
|
56
|
+
hubEntriesCount: hubEntries.length,
|
|
57
|
+
connectorsCount: connectors.length,
|
|
58
|
+
mcpConfigured,
|
|
59
|
+
latestConnectorRun: latestConnectorRun
|
|
60
|
+
? `${latestConnectorRun.connectorName} (${latestConnectorRun.status}) at ${latestConnectorRun.ranAt}`
|
|
61
|
+
: "Never",
|
|
62
|
+
providerLabel: activeProvider ? `${activeProvider.name} (${activeProvider.kind})` : "Not connected",
|
|
63
|
+
modelLabel: config.activeModel ?? "Not selected",
|
|
64
|
+
currentPanel: session.currentPanel ?? "Home",
|
|
65
|
+
currentFocus: session.currentFocus ?? "None",
|
|
66
|
+
latestEvent: latestEvent ? `${latestEvent.title} (${latestEvent.status})` : "No session events yet",
|
|
67
|
+
nextSteps,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export async function statusCommandAction() {
|
|
71
|
+
let snapshot;
|
|
72
|
+
try {
|
|
73
|
+
snapshot = await getStatusSnapshot();
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
console.log(chalk.red(err.message));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
14
79
|
console.log(chalk.bold("\n Umbrella Context Status\n"));
|
|
15
|
-
console.log(
|
|
16
|
-
console.log(`
|
|
17
|
-
console.log(`
|
|
18
|
-
console.log(`
|
|
19
|
-
console.log(`
|
|
20
|
-
console.log(
|
|
21
|
-
console.log(
|
|
22
|
-
console.log(`
|
|
23
|
-
console.log(`
|
|
24
|
-
console.log(`
|
|
25
|
-
console.log(`
|
|
26
|
-
console.log(`
|
|
80
|
+
console.log(chalk.cyan(" Connection"));
|
|
81
|
+
console.log(` Company: ${snapshot.companyName}`);
|
|
82
|
+
console.log(` Space: ${snapshot.spaceName}`);
|
|
83
|
+
console.log(` Umbrella: ${snapshot.umbrellaUrl ?? "Not saved"}`);
|
|
84
|
+
console.log(` Context Backend: ${snapshot.serverUrl}`);
|
|
85
|
+
console.log("");
|
|
86
|
+
console.log(chalk.cyan(" Local Repo"));
|
|
87
|
+
console.log(` Current Directory: ${snapshot.currentDirectory}`);
|
|
88
|
+
console.log(` Repo Root: ${snapshot.repoRoot}`);
|
|
89
|
+
console.log(` Local Context Folder: ${snapshot.umDir}`);
|
|
90
|
+
console.log(` Pending Local Context: ${snapshot.pendingCount}`);
|
|
91
|
+
console.log(` Pulled Context Snapshot: ${snapshot.pulledContextCount}`);
|
|
92
|
+
console.log(` Pulled Known Fixes: ${snapshot.pulledFixCount}`);
|
|
93
|
+
console.log(` Last Push: ${snapshot.lastPushAt}`);
|
|
94
|
+
console.log(` Last Pull: ${snapshot.lastPullAt}`);
|
|
95
|
+
console.log("");
|
|
96
|
+
console.log(chalk.cyan(" Repo Ecosystem"));
|
|
97
|
+
console.log(` Hub Entries Installed: ${snapshot.hubEntriesCount}`);
|
|
98
|
+
console.log(` Connectors Installed: ${snapshot.connectorsCount}`);
|
|
99
|
+
console.log(` Repo MCP Wired: ${snapshot.mcpConfigured ? "Yes" : "No"}`);
|
|
100
|
+
console.log(` Last Connector Run: ${snapshot.latestConnectorRun}`);
|
|
101
|
+
console.log("");
|
|
102
|
+
console.log(chalk.cyan(" Model Runtime"));
|
|
103
|
+
console.log(` Provider: ${snapshot.providerLabel}`);
|
|
104
|
+
console.log(` Model: ${snapshot.modelLabel}`);
|
|
105
|
+
console.log(` Session Panel: ${snapshot.currentPanel}`);
|
|
106
|
+
console.log(` Session Focus: ${snapshot.currentFocus}`);
|
|
107
|
+
console.log(` Latest Session Event: ${snapshot.latestEvent}`);
|
|
108
|
+
if (snapshot.nextSteps.length > 0) {
|
|
109
|
+
console.log("");
|
|
110
|
+
console.log(chalk.cyan(" Suggested Next Steps"));
|
|
111
|
+
snapshot.nextSteps.forEach((step) => {
|
|
112
|
+
console.log(` - ${step}`);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
27
115
|
}
|
|
28
116
|
export function statusCommand(cli) {
|
|
29
117
|
cli.command("status", "Show the current repo, company, space, and local sync state").action(async () => {
|
package/dist/config.d.ts
CHANGED
|
@@ -8,6 +8,22 @@ export interface AgentMemoryConfig {
|
|
|
8
8
|
projectName: string;
|
|
9
9
|
workspaceId: string;
|
|
10
10
|
workspaceName: string;
|
|
11
|
+
activeProvider?: string;
|
|
12
|
+
activeModel?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface SavedProvider {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
kind: string;
|
|
18
|
+
apiKey?: string;
|
|
19
|
+
baseUrl?: string;
|
|
20
|
+
updatedAt: string;
|
|
21
|
+
}
|
|
22
|
+
export interface HubRegistry {
|
|
23
|
+
id: string;
|
|
24
|
+
name: string;
|
|
25
|
+
url: string;
|
|
26
|
+
updatedAt: string;
|
|
11
27
|
}
|
|
12
28
|
export interface SavedLocation {
|
|
13
29
|
repoRoot: string;
|
|
@@ -23,8 +39,15 @@ export declare class ConfigManager {
|
|
|
23
39
|
get config(): AgentMemoryConfig | null;
|
|
24
40
|
set(config: Partial<AgentMemoryConfig>): void;
|
|
25
41
|
clear(): void;
|
|
42
|
+
clearUmbrellaSession(): void;
|
|
26
43
|
get locations(): SavedLocation[];
|
|
44
|
+
get providers(): SavedProvider[];
|
|
27
45
|
upsertLocation(location: SavedLocation): void;
|
|
46
|
+
upsertProvider(provider: SavedProvider): void;
|
|
47
|
+
removeProvider(id: string): void;
|
|
28
48
|
get configPath(): string;
|
|
49
|
+
get hubRegistries(): HubRegistry[];
|
|
50
|
+
upsertHubRegistry(registry: HubRegistry): void;
|
|
51
|
+
removeHubRegistry(id: string): void;
|
|
29
52
|
}
|
|
30
53
|
export declare const configManager: ConfigManager;
|