umbrella-context 0.1.2

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.
Files changed (40) hide show
  1. package/README.md +41 -0
  2. package/dist/commands/connect.d.ts +1 -0
  3. package/dist/commands/connect.js +69 -0
  4. package/dist/commands/curate.d.ts +5 -0
  5. package/dist/commands/curate.js +35 -0
  6. package/dist/commands/fix.d.ts +1 -0
  7. package/dist/commands/fix.js +40 -0
  8. package/dist/commands/interactive.d.ts +1 -0
  9. package/dist/commands/interactive.js +145 -0
  10. package/dist/commands/locations.d.ts +1 -0
  11. package/dist/commands/locations.js +17 -0
  12. package/dist/commands/login.d.ts +1 -0
  13. package/dist/commands/login.js +7 -0
  14. package/dist/commands/mcp.d.ts +1 -0
  15. package/dist/commands/mcp.js +73 -0
  16. package/dist/commands/pull.d.ts +2 -0
  17. package/dist/commands/pull.js +58 -0
  18. package/dist/commands/push.d.ts +2 -0
  19. package/dist/commands/push.js +65 -0
  20. package/dist/commands/record.d.ts +1 -0
  21. package/dist/commands/record.js +37 -0
  22. package/dist/commands/search.d.ts +2 -0
  23. package/dist/commands/search.js +57 -0
  24. package/dist/commands/seed.d.ts +1 -0
  25. package/dist/commands/seed.js +117 -0
  26. package/dist/commands/setup.d.ts +1 -0
  27. package/dist/commands/setup.js +171 -0
  28. package/dist/commands/space.d.ts +1 -0
  29. package/dist/commands/space.js +75 -0
  30. package/dist/commands/status.d.ts +2 -0
  31. package/dist/commands/status.js +32 -0
  32. package/dist/config.d.ts +30 -0
  33. package/dist/config.js +63 -0
  34. package/dist/index.d.ts +1 -0
  35. package/dist/index.js +42 -0
  36. package/dist/repo-state.d.ts +53 -0
  37. package/dist/repo-state.js +171 -0
  38. package/dist/umbrella.d.ts +45 -0
  39. package/dist/umbrella.js +108 -0
  40. package/package.json +41 -0
@@ -0,0 +1,57 @@
1
+ import chalk from "chalk";
2
+ import { configManager } from "../config.js";
3
+ import { getPendingMemories, getPulledMemories, summarizeLocalMemoryMatches } from "../repo-state.js";
4
+ export async function searchCommandAction(query) {
5
+ const config = configManager.config;
6
+ if (!config) {
7
+ console.log(chalk.red("Not configured. Run: umbrella-context setup"));
8
+ return;
9
+ }
10
+ try {
11
+ const localMatches = summarizeLocalMemoryMatches([...(await getPendingMemories()), ...(await getPulledMemories())], query);
12
+ const res = await fetch(`${config.serverUrl}/api/memories/search?query=${encodeURIComponent(query)}`, {
13
+ headers: { Authorization: `Bearer ${config.apiKey}` },
14
+ });
15
+ if (!res.ok) {
16
+ const err = await res.json();
17
+ console.log(chalk.red(`\n Failed: ${err.error}`));
18
+ return;
19
+ }
20
+ const data = await res.json();
21
+ if (data.results.length === 0 && localMatches.length === 0) {
22
+ console.log(chalk.yellow(`\n No context found for "${query}"`));
23
+ return;
24
+ }
25
+ console.log(chalk.bold(`\n Found context for ${config.companyName} / ${config.projectName}:\n`));
26
+ if (localMatches.length > 0) {
27
+ console.log(chalk.cyan(" Local .um matches:\n"));
28
+ localMatches.forEach((result, index) => {
29
+ console.log(chalk.cyan(` ${index + 1}. [local]`));
30
+ console.log(` ${result.content}`);
31
+ if (result.tags?.length)
32
+ console.log(chalk.gray(` Tags: ${result.tags.join(", ")}`));
33
+ console.log(chalk.gray(` Saved: ${new Date(result.createdAt).toLocaleString()}`));
34
+ console.log("");
35
+ });
36
+ }
37
+ if (data.results.length > 0) {
38
+ console.log(chalk.cyan(" Server matches:\n"));
39
+ }
40
+ data.results.forEach((result, index) => {
41
+ console.log(chalk.cyan(` ${index + 1}. [${result.systemType}]`));
42
+ console.log(` ${result.content}`);
43
+ if (result.tags?.length)
44
+ console.log(chalk.gray(` Tags: ${result.tags.join(", ")}`));
45
+ console.log(chalk.gray(` Source: ${result.source} | ${new Date(result.createdAt).toLocaleDateString()}`));
46
+ console.log("");
47
+ });
48
+ }
49
+ catch (err) {
50
+ console.log(chalk.red(`\n Error: ${err.message}`));
51
+ }
52
+ }
53
+ export function searchCommand(cli) {
54
+ cli.command("search <query>", "Search saved context by keyword").action(async (query) => {
55
+ await searchCommandAction(query);
56
+ });
57
+ }
@@ -0,0 +1 @@
1
+ export declare function seedCommand(cli: any): void;
@@ -0,0 +1,117 @@
1
+ import chalk from "chalk";
2
+ import prompts from "prompts";
3
+ import { configManager } from "../config.js";
4
+ export function seedCommand(cli) {
5
+ cli.command("seed", "Create first workspace, user, and project").action(async () => {
6
+ console.log(chalk.bold("\n Seed - Create your first workspace\n"));
7
+ const serverUrl = await prompts({
8
+ type: "text",
9
+ name: "value",
10
+ message: "Server URL",
11
+ initial: "http://localhost:3000",
12
+ });
13
+ if (!serverUrl.value)
14
+ return;
15
+ const workspaceName = await prompts({
16
+ type: "text",
17
+ name: "value",
18
+ message: "Workspace name",
19
+ initial: "Personal",
20
+ });
21
+ if (!workspaceName.value)
22
+ return;
23
+ const email = await prompts({
24
+ type: "text",
25
+ name: "value",
26
+ message: "Email",
27
+ });
28
+ if (!email.value)
29
+ return;
30
+ const password = await prompts({
31
+ type: "password",
32
+ name: "value",
33
+ message: "Password (min 6 chars)",
34
+ });
35
+ if (!password.value)
36
+ return;
37
+ const projectName = await prompts({
38
+ type: "text",
39
+ name: "value",
40
+ message: "First project name",
41
+ initial: "Default",
42
+ });
43
+ if (!projectName.value)
44
+ return;
45
+ try {
46
+ const seedRes = await fetch(`${serverUrl.value}/api/auth/seed-user`, {
47
+ method: "POST",
48
+ headers: { "Content-Type": "application/json" },
49
+ body: JSON.stringify({
50
+ email: email.value,
51
+ password: password.value,
52
+ workspaceName: workspaceName.value,
53
+ }),
54
+ });
55
+ if (!seedRes.ok && seedRes.status !== 409) {
56
+ const err = await seedRes.json();
57
+ console.log(chalk.red(`\n Failed to create user: ${err.error}`));
58
+ return;
59
+ }
60
+ if (seedRes.status === 409) {
61
+ console.log(chalk.yellow("\n User already exists, continuing..."));
62
+ }
63
+ else {
64
+ console.log(chalk.green("\n User created"));
65
+ }
66
+ const loginRes = await fetch(`${serverUrl.value}/api/auth/login`, {
67
+ method: "POST",
68
+ headers: { "Content-Type": "application/json" },
69
+ body: JSON.stringify({ email: email.value, password: password.value }),
70
+ });
71
+ const loginData = await loginRes.json();
72
+ if (loginData.projects?.length > 0) {
73
+ console.log(chalk.green(`\n Workspace "${loginData.workspace.name}" already has ${loginData.projects.length} project(s)`));
74
+ configManager.set({
75
+ serverUrl: serverUrl.value,
76
+ apiKey: loginData.projects[0].apiKey,
77
+ projectId: loginData.projects[0].id,
78
+ projectName: loginData.projects[0].name,
79
+ workspaceId: loginData.workspace.id,
80
+ workspaceName: loginData.workspace.name,
81
+ });
82
+ console.log(chalk.gray(`\n Connected to: ${loginData.workspace.name} / ${loginData.projects[0].name}`));
83
+ return;
84
+ }
85
+ const projectRes = await fetch(`${serverUrl.value}/api/auth/projects`, {
86
+ method: "POST",
87
+ headers: { "Content-Type": "application/json" },
88
+ body: JSON.stringify({
89
+ workspaceId: loginData.workspaceId || loginData.workspace.id,
90
+ name: projectName.value,
91
+ }),
92
+ });
93
+ if (!projectRes.ok) {
94
+ const err = await projectRes.json();
95
+ console.log(chalk.red(`\n Failed to create project: ${err.error}`));
96
+ return;
97
+ }
98
+ const project = await projectRes.json();
99
+ configManager.set({
100
+ serverUrl: serverUrl.value,
101
+ apiKey: project.apiKey,
102
+ projectId: project.id,
103
+ projectName: project.name,
104
+ workspaceId: loginData.workspaceId || loginData.workspace.id,
105
+ workspaceName: loginData.workspace.name,
106
+ });
107
+ console.log(chalk.green("\n All set!"));
108
+ console.log(chalk.green(` Workspace: ${loginData.workspace.name}`));
109
+ console.log(chalk.green(` Project: ${project.name}`));
110
+ console.log(chalk.green(` API Key: ${project.apiKey}`));
111
+ console.log(chalk.gray("\n Run umbrella-context to start."));
112
+ }
113
+ catch (err) {
114
+ console.log(chalk.red(`\n Error: ${err.message}`));
115
+ }
116
+ });
117
+ }
@@ -0,0 +1 @@
1
+ export declare function setupCommand(cli: any): void;
@@ -0,0 +1,171 @@
1
+ import chalk from "chalk";
2
+ import prompts from "prompts";
3
+ import { configManager } from "../config.js";
4
+ import { ensureRepoContext } from "../repo-state.js";
5
+ import { createContextSpace, createUmbrellaCompany, getCliSetup, getCompanyContextSummary, getUmbrellaHealth, listUmbrellaCompanies, signInToUmbrella, toContextSpaces, } from "../umbrella.js";
6
+ function normalizeServerUrl(value) {
7
+ return value.trim().replace(/\/+$/, "");
8
+ }
9
+ function printConnected(setup) {
10
+ console.log(chalk.green(`\n Connected to ${setup.companyName} / ${setup.activeSpaceName}`));
11
+ console.log(chalk.gray(` Context space: ${setup.activeSpaceName}`));
12
+ console.log(chalk.gray(` Saved config to ${configManager.configPath}`));
13
+ console.log(chalk.gray("\n Next commands:"));
14
+ console.log(chalk.gray(" umbrella-context query \"What do we already know?\""));
15
+ console.log(chalk.gray(" umbrella-context curate \"We learned that...\""));
16
+ console.log(chalk.gray(" umbrella-context mcp"));
17
+ }
18
+ async function chooseCompany(serverUrl, companies, cookie, initialCompanyId) {
19
+ if (initialCompanyId) {
20
+ const matched = companies.find((company) => company.id === initialCompanyId);
21
+ if (matched)
22
+ return matched;
23
+ }
24
+ const companyPrompt = await prompts({
25
+ type: "select",
26
+ name: "value",
27
+ message: "Choose a company from Umbrella",
28
+ choices: [
29
+ ...companies.map((company) => ({
30
+ title: `${company.name} (${company.issuePrefix})`,
31
+ value: company.id,
32
+ })),
33
+ { title: "+ Create new company", value: "__create__" },
34
+ ],
35
+ });
36
+ if (!companyPrompt.value)
37
+ return null;
38
+ if (companyPrompt.value !== "__create__") {
39
+ return companies.find((company) => company.id === companyPrompt.value) ?? null;
40
+ }
41
+ const createdPrompt = await prompts({
42
+ type: "text",
43
+ name: "value",
44
+ message: "New company name",
45
+ validate: (value) => (value.trim().length > 0 ? true : "Enter a company name"),
46
+ });
47
+ if (!createdPrompt.value)
48
+ return null;
49
+ return createUmbrellaCompany(serverUrl, createdPrompt.value.trim(), cookie);
50
+ }
51
+ async function chooseSpace(serverUrl, companyId, spaces, cookie, initialSpaceId) {
52
+ if (initialSpaceId) {
53
+ const matched = spaces.find((space) => space.id === initialSpaceId);
54
+ if (matched)
55
+ return matched.id;
56
+ }
57
+ const spacePrompt = await prompts({
58
+ type: "select",
59
+ name: "value",
60
+ message: "Choose a context space",
61
+ choices: [
62
+ ...spaces.map((space) => ({
63
+ title: space.isPrimary ? `${space.name} (core)` : space.name,
64
+ value: space.id,
65
+ })),
66
+ { title: "+ Create new space", value: "__create__" },
67
+ ],
68
+ });
69
+ if (!spacePrompt.value)
70
+ return null;
71
+ if (spacePrompt.value !== "__create__")
72
+ return spacePrompt.value;
73
+ const createdPrompt = await prompts({
74
+ type: "text",
75
+ name: "value",
76
+ message: "New context space name",
77
+ validate: (value) => (value.trim().length > 0 ? true : "Enter a space name"),
78
+ });
79
+ if (!createdPrompt.value)
80
+ return null;
81
+ const summary = await createContextSpace(serverUrl, companyId, createdPrompt.value.trim(), cookie);
82
+ return summary.activeProjectId;
83
+ }
84
+ function saveSetup(setup, umbrellaUrl) {
85
+ configManager.set({
86
+ umbrellaUrl,
87
+ serverUrl: setup.baseUrl,
88
+ companyId: setup.companyId,
89
+ companyName: setup.companyName,
90
+ workspaceId: setup.workspaceId,
91
+ workspaceName: setup.workspaceName,
92
+ projectId: setup.activeSpaceId,
93
+ projectName: setup.activeSpaceName,
94
+ apiKey: setup.apiKey,
95
+ });
96
+ configManager.upsertLocation({
97
+ repoRoot: process.cwd(),
98
+ companyId: setup.companyId,
99
+ companyName: setup.companyName,
100
+ projectId: setup.activeSpaceId,
101
+ projectName: setup.activeSpaceName,
102
+ updatedAt: new Date().toISOString(),
103
+ });
104
+ }
105
+ export function setupCommand(cli) {
106
+ cli
107
+ .command("setup", "Sign into Umbrella, choose a company, and connect this device to a context space")
108
+ .option("--server-url <url>", "Umbrella server URL")
109
+ .option("--email <email>", "Umbrella email for authenticated mode")
110
+ .option("--password <password>", "Umbrella password for authenticated mode")
111
+ .option("--company-id <id>", "Existing Umbrella company ID")
112
+ .option("--space-id <id>", "Existing context space ID")
113
+ .action(async (options) => {
114
+ console.log(chalk.bold("\n Umbrella Context Setup\n"));
115
+ const existing = configManager.config;
116
+ const serverUrlPrompt = await prompts({
117
+ type: options.serverUrl ? null : "text",
118
+ name: "value",
119
+ message: "Umbrella server URL",
120
+ initial: existing?.serverUrl || "http://127.0.0.1:3100",
121
+ });
122
+ const serverUrl = normalizeServerUrl(options.serverUrl?.trim() || serverUrlPrompt.value || existing?.serverUrl || "http://127.0.0.1:3100");
123
+ try {
124
+ const health = await getUmbrellaHealth(serverUrl);
125
+ let cookie = null;
126
+ if (health.deploymentMode === "authenticated") {
127
+ const emailPrompt = await prompts({
128
+ type: options.email ? null : "text",
129
+ name: "value",
130
+ message: "Umbrella email",
131
+ });
132
+ const passwordPrompt = await prompts({
133
+ type: options.password ? null : "password",
134
+ name: "value",
135
+ message: "Umbrella password",
136
+ });
137
+ const email = options.email?.trim() || emailPrompt.value;
138
+ const password = options.password?.trim() || passwordPrompt.value;
139
+ if (!email || !password) {
140
+ console.log(chalk.red("\n Sign-in cancelled."));
141
+ return;
142
+ }
143
+ const session = await signInToUmbrella(serverUrl, email, password);
144
+ cookie = session.cookie;
145
+ }
146
+ else {
147
+ console.log(chalk.gray(" Local trusted mode detected. Using the local board access path."));
148
+ }
149
+ const companies = await listUmbrellaCompanies(serverUrl, cookie);
150
+ const company = await chooseCompany(serverUrl, companies, cookie, options.companyId?.trim());
151
+ if (!company) {
152
+ console.log(chalk.yellow("\n No company selected."));
153
+ return;
154
+ }
155
+ const summary = await getCompanyContextSummary(serverUrl, company.id, cookie);
156
+ const spaces = toContextSpaces(summary);
157
+ const selectedSpaceId = await chooseSpace(serverUrl, company.id, spaces, cookie, options.spaceId?.trim());
158
+ if (!selectedSpaceId) {
159
+ console.log(chalk.yellow("\n No context space selected."));
160
+ return;
161
+ }
162
+ const setup = await getCliSetup(serverUrl, company.id, selectedSpaceId, cookie);
163
+ saveSetup(setup, serverUrl);
164
+ await ensureRepoContext(configManager.config);
165
+ printConnected(setup);
166
+ }
167
+ catch (err) {
168
+ console.log(chalk.red(`\n Error: ${err.message}`));
169
+ }
170
+ });
171
+ }
@@ -0,0 +1 @@
1
+ export declare function spaceCommand(cli: any): void;
@@ -0,0 +1,75 @@
1
+ import chalk from "chalk";
2
+ import prompts from "prompts";
3
+ import { configManager } from "../config.js";
4
+ import { ensureRepoContext } from "../repo-state.js";
5
+ import { getCliSetup, getCompanyContextSummary, toContextSpaces } from "../umbrella.js";
6
+ export function spaceCommand(cli) {
7
+ cli
8
+ .command("space <action> [space]", "List or switch context spaces for the current company")
9
+ .action(async (action, spaceArg) => {
10
+ const config = configManager.config;
11
+ if (!config) {
12
+ console.log(chalk.red("Not configured. Run: umbrella-context setup"));
13
+ return;
14
+ }
15
+ if (!config.umbrellaUrl) {
16
+ console.log(chalk.red("No Umbrella URL saved for this device. Run umbrella-context setup to enable space commands."));
17
+ return;
18
+ }
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
+ });
75
+ }
@@ -0,0 +1,2 @@
1
+ export declare function statusCommandAction(): Promise<void>;
2
+ export declare function statusCommand(cli: any): void;
@@ -0,0 +1,32 @@
1
+ import chalk from "chalk";
2
+ import { configManager } from "../config.js";
3
+ import { getPendingMemories, getPulledFixes, getPulledMemories, getRepoContext } from "../repo-state.js";
4
+ export async function statusCommandAction() {
5
+ const config = configManager.config;
6
+ if (!config) {
7
+ console.log(chalk.red("Not configured. Run: umbrella-context setup"));
8
+ return;
9
+ }
10
+ const { repoRoot, state, umDir } = await getRepoContext();
11
+ const pending = await getPendingMemories();
12
+ const pulledMemories = await getPulledMemories();
13
+ const pulledFixes = await getPulledFixes();
14
+ console.log(chalk.bold("\n Umbrella Context Status\n"));
15
+ console.log(` Company: ${config.companyName}`);
16
+ console.log(` Space: ${config.projectName}`);
17
+ console.log(` Umbrella: ${config.umbrellaUrl ?? "Not saved"}`);
18
+ console.log(` Server: ${config.serverUrl}`);
19
+ console.log(` Current Directory: ${process.cwd()}`);
20
+ console.log(` Repo Root: ${repoRoot}`);
21
+ console.log(` Local Context Folder: ${umDir}`);
22
+ console.log(` Pending Local Context: ${pending.length}`);
23
+ console.log(` Pulled Context Snapshot: ${pulledMemories.length}`);
24
+ console.log(` Pulled Known Fixes: ${pulledFixes.length}`);
25
+ console.log(` Last Push: ${state?.lastPushAt ?? "Never"}`);
26
+ console.log(` Last Pull: ${state?.lastPullAt ?? "Never"}`);
27
+ }
28
+ export function statusCommand(cli) {
29
+ cli.command("status", "Show the current repo, company, space, and local sync state").action(async () => {
30
+ await statusCommandAction();
31
+ });
32
+ }
@@ -0,0 +1,30 @@
1
+ export interface AgentMemoryConfig {
2
+ umbrellaUrl?: string;
3
+ serverUrl: string;
4
+ apiKey: string;
5
+ companyId: string;
6
+ companyName: string;
7
+ projectId: string;
8
+ projectName: string;
9
+ workspaceId: string;
10
+ workspaceName: string;
11
+ }
12
+ export interface SavedLocation {
13
+ repoRoot: string;
14
+ companyId: string;
15
+ companyName: string;
16
+ projectId: string;
17
+ projectName: string;
18
+ updatedAt: string;
19
+ }
20
+ export declare class ConfigManager {
21
+ private conf;
22
+ constructor();
23
+ get config(): AgentMemoryConfig | null;
24
+ set(config: Partial<AgentMemoryConfig>): void;
25
+ clear(): void;
26
+ get locations(): SavedLocation[];
27
+ upsertLocation(location: SavedLocation): void;
28
+ get configPath(): string;
29
+ }
30
+ export declare const configManager: ConfigManager;
package/dist/config.js ADDED
@@ -0,0 +1,63 @@
1
+ import Conf from "conf";
2
+ import path from "path";
3
+ import os from "os";
4
+ export class ConfigManager {
5
+ conf;
6
+ constructor() {
7
+ this.conf = new Conf({
8
+ projectName: "umbrella-context",
9
+ configName: "config",
10
+ });
11
+ }
12
+ get config() {
13
+ return this.conf.get("serverUrl")
14
+ ? {
15
+ umbrellaUrl: this.conf.get("umbrellaUrl"),
16
+ serverUrl: this.conf.get("serverUrl"),
17
+ apiKey: this.conf.get("apiKey"),
18
+ companyId: this.conf.get("companyId"),
19
+ companyName: this.conf.get("companyName"),
20
+ projectId: this.conf.get("projectId"),
21
+ projectName: this.conf.get("projectName"),
22
+ workspaceId: this.conf.get("workspaceId"),
23
+ workspaceName: this.conf.get("workspaceName"),
24
+ }
25
+ : null;
26
+ }
27
+ set(config) {
28
+ if (config.umbrellaUrl)
29
+ this.conf.set("umbrellaUrl", config.umbrellaUrl);
30
+ if (config.serverUrl)
31
+ this.conf.set("serverUrl", config.serverUrl);
32
+ if (config.apiKey)
33
+ this.conf.set("apiKey", config.apiKey);
34
+ if (config.companyId)
35
+ this.conf.set("companyId", config.companyId);
36
+ if (config.companyName)
37
+ this.conf.set("companyName", config.companyName);
38
+ if (config.projectId)
39
+ this.conf.set("projectId", config.projectId);
40
+ if (config.projectName)
41
+ this.conf.set("projectName", config.projectName);
42
+ if (config.workspaceId)
43
+ this.conf.set("workspaceId", config.workspaceId);
44
+ if (config.workspaceName)
45
+ this.conf.set("workspaceName", config.workspaceName);
46
+ }
47
+ clear() {
48
+ this.conf.clear();
49
+ }
50
+ get locations() {
51
+ return this.conf.get("locations") ?? [];
52
+ }
53
+ upsertLocation(location) {
54
+ const locations = this.locations.filter((entry) => entry.repoRoot !== location.repoRoot);
55
+ locations.push(location);
56
+ this.conf.set("locations", locations.sort((a, b) => a.repoRoot.localeCompare(b.repoRoot)));
57
+ }
58
+ get configPath() {
59
+ return this.conf.path
60
+ ?? path.join(os.homedir(), ".config", "umbrella-context", "config.json");
61
+ }
62
+ }
63
+ export const configManager = new ConfigManager();
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,42 @@
1
+ import { cac } from "cac";
2
+ import { setupCommand } from "./commands/setup.js";
3
+ import { loginCommand } from "./commands/login.js";
4
+ import { connectCommand } from "./commands/connect.js";
5
+ import { pushCommand } from "./commands/push.js";
6
+ import { pullCommand } from "./commands/pull.js";
7
+ import { searchCommand } from "./commands/search.js";
8
+ import { fixCommand } from "./commands/fix.js";
9
+ import { recordCommand } from "./commands/record.js";
10
+ import { mcpCommand } from "./commands/mcp.js";
11
+ import { interactiveCommand } from "./commands/interactive.js";
12
+ import { curateCommand } from "./commands/curate.js";
13
+ import { statusCommand } from "./commands/status.js";
14
+ import { locationsCommand } from "./commands/locations.js";
15
+ import { spaceCommand } from "./commands/space.js";
16
+ const cli = cac("umbrella-context");
17
+ cli.option("--config <path>", "Path to config file");
18
+ import { seedCommand } from "./commands/seed.js";
19
+ setupCommand(cli);
20
+ loginCommand(cli);
21
+ connectCommand(cli);
22
+ pushCommand(cli);
23
+ pullCommand(cli);
24
+ searchCommand(cli);
25
+ fixCommand(cli);
26
+ recordCommand(cli);
27
+ mcpCommand(cli);
28
+ seedCommand(cli);
29
+ curateCommand(cli);
30
+ statusCommand(cli);
31
+ locationsCommand(cli);
32
+ spaceCommand(cli);
33
+ cli.command("query [...args]", "Alias for search").action(async (args) => {
34
+ const { searchCommandAction } = await import("./commands/search.js");
35
+ await searchCommandAction(args.join(" "));
36
+ });
37
+ cli.command("", "Interactive mode").action(async () => {
38
+ await interactiveCommand([]);
39
+ });
40
+ cli.help();
41
+ cli.version("0.1.2");
42
+ cli.parse();
@@ -0,0 +1,53 @@
1
+ import type { AgentMemoryConfig } from "./config.js";
2
+ export type LocalMemoryEntry = {
3
+ id: string;
4
+ content: string;
5
+ tags: string[];
6
+ systemType: string;
7
+ source: string;
8
+ createdAt: string;
9
+ };
10
+ export type LocalFixEntry = {
11
+ id: string;
12
+ errorSignal: string;
13
+ solution: string;
14
+ confidence: number;
15
+ timesApplied: number;
16
+ timesSucceeded: number;
17
+ createdAt: string;
18
+ lastApplied: string | null;
19
+ };
20
+ export type RepoContextState = {
21
+ version: 1;
22
+ repoRoot: string;
23
+ umDir: string;
24
+ companyId: string;
25
+ companyName: string;
26
+ workspaceId: string;
27
+ workspaceName: string;
28
+ projectId: string;
29
+ projectName: string;
30
+ umbrellaUrl: string | null;
31
+ serverUrl: string;
32
+ initializedAt: string;
33
+ updatedAt: string;
34
+ lastPushAt: null | string;
35
+ lastPullAt: null | string;
36
+ };
37
+ export declare function findRepoRoot(startDir?: string): Promise<string>;
38
+ export declare function ensureRepoContext(config: AgentMemoryConfig, cwd?: string): Promise<string>;
39
+ export declare function getRepoContext(cwd?: string): Promise<{
40
+ repoRoot: string;
41
+ state: RepoContextState | null;
42
+ umDir: string;
43
+ }>;
44
+ export declare function updateRepoContext(updater: (current: RepoContextState) => RepoContextState | Promise<RepoContextState>, cwd?: string): Promise<RepoContextState>;
45
+ export declare function addPendingMemory(input: Omit<LocalMemoryEntry, "createdAt" | "id">, cwd?: string): Promise<LocalMemoryEntry>;
46
+ export declare function getPendingMemories(cwd?: string): Promise<LocalMemoryEntry[]>;
47
+ export declare function clearPendingMemories(cwd?: string): Promise<void>;
48
+ export declare function setPulledMemories(memories: LocalMemoryEntry[], cwd?: string): Promise<void>;
49
+ export declare function getPulledMemories(cwd?: string): Promise<LocalMemoryEntry[]>;
50
+ export declare function setPulledFixes(fixes: LocalFixEntry[], cwd?: string): Promise<void>;
51
+ export declare function getPulledFixes(cwd?: string): Promise<LocalFixEntry[]>;
52
+ export declare function markPushCompleted(cwd?: string): Promise<RepoContextState>;
53
+ export declare function summarizeLocalMemoryMatches(entries: LocalMemoryEntry[], query: string): LocalMemoryEntry[];