umbrella-context 0.1.37 → 0.1.39

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/config.d.ts CHANGED
@@ -24,6 +24,9 @@ export interface HubRegistry {
24
24
  id: string;
25
25
  name: string;
26
26
  url: string;
27
+ authScheme?: "none" | "bearer" | "token" | "basic" | "custom-header";
28
+ token?: string;
29
+ headerName?: string;
27
30
  updatedAt: string;
28
31
  }
29
32
  export interface StoredCliState {
@@ -47,6 +50,7 @@ export declare class ConfigManager {
47
50
  get locations(): SavedLocation[];
48
51
  get providers(): SavedProvider[];
49
52
  upsertLocation(location: SavedLocation): void;
53
+ replaceLocations(locations: SavedLocation[]): void;
50
54
  upsertProvider(provider: SavedProvider): void;
51
55
  removeProvider(id: string): void;
52
56
  get configPath(): string;
package/dist/config.js CHANGED
@@ -87,6 +87,11 @@ export class ConfigManager {
87
87
  locations.push(location);
88
88
  this.conf.set("locations", locations.sort((a, b) => a.repoRoot.localeCompare(b.repoRoot)));
89
89
  }
90
+ replaceLocations(locations) {
91
+ this.conf.set("locations", locations
92
+ .slice()
93
+ .sort((a, b) => a.repoRoot.localeCompare(b.repoRoot)));
94
+ }
90
95
  upsertProvider(provider) {
91
96
  const providers = this.providers.filter((entry) => entry.id !== provider.id && entry.name.toLowerCase() !== provider.name.toLowerCase());
92
97
  providers.push(provider);
@@ -115,6 +120,7 @@ export class ConfigManager {
115
120
  id: "umbrella-default",
116
121
  name: "Umbrella Hub",
117
122
  url: "https://hub.umbrella.local/default",
123
+ authScheme: "none",
118
124
  updatedAt: new Date(0).toISOString(),
119
125
  },
120
126
  ];
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { cac } from "cac";
3
+ import { readFileSync } from "node:fs";
3
4
  import { setupCommand } from "./commands/setup.js";
4
5
  import { loginCommand } from "./commands/login.js";
5
6
  import { connectCommand } from "./commands/connect.js";
@@ -29,6 +30,16 @@ import { treeCommand } from "./commands/tree.js";
29
30
  import { transportCommand } from "./commands/transport.js";
30
31
  import { bridgeCommand } from "./commands/bridge.js";
31
32
  import { curateViewCommandAction } from "./commands/curate.js";
33
+ function readCliVersion() {
34
+ try {
35
+ const packageJsonUrl = new URL("../package.json", import.meta.url);
36
+ const packageJson = JSON.parse(readFileSync(packageJsonUrl, "utf8"));
37
+ return packageJson.version ?? "0.0.0";
38
+ }
39
+ catch {
40
+ return "0.0.0";
41
+ }
42
+ }
32
43
  const cli = cac("umbrella-context");
33
44
  cli.option("--config <path>", "Path to config file");
34
45
  import { seedCommand } from "./commands/seed.js";
@@ -61,12 +72,19 @@ tasksCommand(cli);
61
72
  treeCommand(cli);
62
73
  transportCommand(cli);
63
74
  bridgeCommand(cli);
64
- cli.command("query [...args]", "Alias for search").action(async (args) => {
75
+ cli
76
+ .command("query [...args]", `Alias for search
77
+
78
+ Ask a natural-language question about your codebase or saved team context.`)
79
+ .option("--format <format>", "Output format (text or json)")
80
+ .example('query "How does authentication work?"')
81
+ .example('query "How does auth work?" --format json')
82
+ .action(async (args, opts) => {
65
83
  const { searchCommandAction } = await import("./commands/search.js");
66
- await searchCommandAction(args.join(" "));
84
+ await searchCommandAction(args.join(" "), opts);
67
85
  });
68
86
  cli.help();
69
- cli.version("0.1.37");
87
+ cli.version(readCliVersion());
70
88
  const argv = process.argv.slice(2);
71
89
  if (argv[0] === "curate" && argv[1] === "view" && argv.length === 2) {
72
90
  await curateViewCommandAction();
@@ -3,10 +3,49 @@ export type LocalMemoryEntry = {
3
3
  id: string;
4
4
  content: string;
5
5
  tags: string[];
6
+ keywords: string[];
7
+ category: string | null;
8
+ accessLevel: "space" | "company";
6
9
  systemType: string;
7
10
  source: string;
8
11
  createdAt: string;
9
12
  };
13
+ export type LocalQueryCacheEntry = {
14
+ id: string;
15
+ query: string;
16
+ normalizedQuery: string;
17
+ fingerprint: string;
18
+ payload: {
19
+ companyName: string;
20
+ spaceName: string;
21
+ query: string;
22
+ localMatches: LocalMemoryEntry[];
23
+ serverMatches: Array<Record<string, unknown>>;
24
+ total: number;
25
+ suggestions: string[];
26
+ providerReady?: boolean;
27
+ providerRequiredForSynthesis?: boolean;
28
+ directAnswer?: {
29
+ summary: string;
30
+ details: string;
31
+ sources: string[];
32
+ confidence: "high" | "medium";
33
+ gaps?: string;
34
+ } | null;
35
+ synthesizedAnswer?: {
36
+ summary: string;
37
+ details: string;
38
+ sources: string[];
39
+ confidence: "high" | "medium";
40
+ gaps?: string;
41
+ provider?: string;
42
+ model?: string;
43
+ } | null;
44
+ };
45
+ createdAt: string;
46
+ updatedAt: string;
47
+ hits: number;
48
+ };
10
49
  export type LocalFixEntry = {
11
50
  id: string;
12
51
  errorSignal: string;
@@ -219,6 +258,81 @@ export declare function getRepoContext(cwd?: string): Promise<{
219
258
  export declare function updateRepoContext(updater: (current: RepoContextState) => RepoContextState | Promise<RepoContextState>, cwd?: string): Promise<RepoContextState>;
220
259
  export declare function addPendingMemory(input: Omit<LocalMemoryEntry, "createdAt" | "id">, cwd?: string): Promise<LocalMemoryEntry>;
221
260
  export declare function getPendingMemories(cwd?: string): Promise<LocalMemoryEntry[]>;
261
+ export declare function getQueryCacheEntries(cwd?: string): Promise<{
262
+ payload: {
263
+ localMatches: LocalMemoryEntry[];
264
+ serverMatches: Record<string, unknown>[];
265
+ suggestions: string[];
266
+ providerReady: boolean;
267
+ providerRequiredForSynthesis: boolean;
268
+ directAnswer: {
269
+ summary: string;
270
+ details: string;
271
+ sources: string[];
272
+ confidence: "high" | "medium";
273
+ gaps?: string;
274
+ } | null;
275
+ synthesizedAnswer: {
276
+ summary: string;
277
+ details: string;
278
+ sources: string[];
279
+ confidence: "high" | "medium";
280
+ gaps?: string;
281
+ provider?: string;
282
+ model?: string;
283
+ } | null;
284
+ total: number;
285
+ companyName: string;
286
+ spaceName: string;
287
+ query: string;
288
+ };
289
+ hits: number;
290
+ createdAt: string;
291
+ updatedAt: string;
292
+ id: string;
293
+ query: string;
294
+ normalizedQuery: string;
295
+ fingerprint: string;
296
+ }[]>;
297
+ export declare function getQueryCacheEntry(query: string, fingerprint: string, cwd?: string): Promise<{
298
+ payload: {
299
+ localMatches: LocalMemoryEntry[];
300
+ serverMatches: Record<string, unknown>[];
301
+ suggestions: string[];
302
+ providerReady: boolean;
303
+ providerRequiredForSynthesis: boolean;
304
+ directAnswer: {
305
+ summary: string;
306
+ details: string;
307
+ sources: string[];
308
+ confidence: "high" | "medium";
309
+ gaps?: string;
310
+ } | null;
311
+ synthesizedAnswer: {
312
+ summary: string;
313
+ details: string;
314
+ sources: string[];
315
+ confidence: "high" | "medium";
316
+ gaps?: string;
317
+ provider?: string;
318
+ model?: string;
319
+ } | null;
320
+ total: number;
321
+ companyName: string;
322
+ spaceName: string;
323
+ query: string;
324
+ };
325
+ hits: number;
326
+ createdAt: string;
327
+ updatedAt: string;
328
+ id: string;
329
+ query: string;
330
+ normalizedQuery: string;
331
+ fingerprint: string;
332
+ } | null>;
333
+ export declare function buildLocalQueryFingerprint(cwd?: string): Promise<string>;
334
+ export declare function storeQueryCacheEntry(input: Omit<LocalQueryCacheEntry, "createdAt" | "hits" | "id" | "updatedAt">, cwd?: string): Promise<void>;
335
+ export declare function markQueryCacheHit(entryId: string, cwd?: string): Promise<void>;
222
336
  export declare function clearPendingMemories(cwd?: string): Promise<void>;
223
337
  export declare function resetRepoState(cwd?: string): Promise<{
224
338
  repoRoot: string;
@@ -260,6 +374,7 @@ export declare function appendTaskStreamingContent(taskId: string, content: stri
260
374
  export declare function addTaskReasoningContent(taskId: string, content: string, isThinking?: boolean, cwd?: string): Promise<LocalTask | null>;
261
375
  export declare function addTaskToolCall(taskId: string, toolCall: TaskToolCallPatch, cwd?: string): Promise<LocalTask | null>;
262
376
  export declare function completeTask(taskId: string, status: "completed" | "failed", detail?: string | null, cwd?: string): Promise<LocalTask | null>;
377
+ export declare function removeTask(taskId: string, cwd?: string): Promise<void>;
263
378
  export declare function addConnectorRun(input: Omit<LocalConnectorRun, "id" | "ranAt">, cwd?: string): Promise<LocalConnectorRun>;
264
379
  export declare function writeConnectorRunReport(run: LocalConnectorRun, cwd?: string): Promise<string>;
265
380
  export declare function getSessionState(cwd?: string): Promise<RepoSessionState | null>;
@@ -1,6 +1,6 @@
1
1
  import { promises as fs } from "fs";
2
2
  import path from "path";
3
- import { randomUUID } from "crypto";
3
+ import { createHash, randomUUID } from "crypto";
4
4
  import { execFileSync } from "child_process";
5
5
  import { configManager } from "./config.js";
6
6
  const UM_DIR = ".um";
@@ -15,9 +15,42 @@ const SESSION_FILE = "session.json";
15
15
  const TASKS_FILE = "tasks.json";
16
16
  const TRANSPORT_FILE = "transport.json";
17
17
  const CONTEXT_TREE_STATE_FILE = "context-tree.json";
18
+ const QUERY_CACHE_FILE = "query-cache.json";
18
19
  const HUB_ASSETS_DIR = "hub";
19
20
  const CONNECTOR_ASSETS_DIR = "connectors";
20
21
  const CONNECTOR_RUN_REPORTS_DIR = "connector-runs";
22
+ const SESSION_PANEL_ALIASES = {
23
+ connect: "setup",
24
+ fix: "activity",
25
+ login: "setup",
26
+ projects: "spaces",
27
+ pull: "home",
28
+ push: "home",
29
+ query: "home",
30
+ record: "activity",
31
+ search: "home",
32
+ space: "spaces",
33
+ };
34
+ function normalizeSessionPanel(panel) {
35
+ if (!panel)
36
+ return null;
37
+ return SESSION_PANEL_ALIASES[panel] ?? panel;
38
+ }
39
+ function normalizeLocalMemoryEntry(entry) {
40
+ return {
41
+ ...entry,
42
+ tags: entry.tags ?? [],
43
+ keywords: entry.keywords ?? [],
44
+ category: entry.category ?? null,
45
+ accessLevel: entry.accessLevel ?? "space",
46
+ systemType: entry.systemType ?? "system1_knowledge",
47
+ source: entry.source ?? "cli",
48
+ createdAt: entry.createdAt ?? new Date().toISOString(),
49
+ };
50
+ }
51
+ function normalizeLocalMemoryEntries(entries) {
52
+ return entries.map((entry) => normalizeLocalMemoryEntry(entry));
53
+ }
21
54
  function normalizeSessionState(state) {
22
55
  if (!state)
23
56
  return null;
@@ -27,14 +60,19 @@ function normalizeSessionState(state) {
27
60
  recentQueries: state.recentQueries ?? [],
28
61
  recentCurations: state.recentCurations ?? [],
29
62
  lastSummary: state.lastSummary ?? null,
30
- currentPanel: state.currentPanel ?? null,
63
+ currentPanel: normalizeSessionPanel(state.currentPanel ?? null),
31
64
  currentFocus: state.currentFocus ?? null,
32
- panelHistory: state.panelHistory ?? [],
65
+ panelHistory: (state.panelHistory ?? [])
66
+ .map((panel) => normalizeSessionPanel(panel))
67
+ .filter((panel) => Boolean(panel)),
33
68
  recentProviderIds: state.recentProviderIds ?? [],
34
69
  recentModels: state.recentModels ?? [],
35
70
  recentHubSlugs: state.recentHubSlugs ?? [],
36
71
  recentConnectorSources: state.recentConnectorSources ?? [],
37
- events: state.events ?? [],
72
+ events: (state.events ?? []).map((event) => ({
73
+ ...event,
74
+ panel: normalizeSessionPanel(event.panel ?? null),
75
+ })),
38
76
  };
39
77
  }
40
78
  function normalizeTransportState(state) {
@@ -191,6 +229,9 @@ function getTransportFile(repoRoot) {
191
229
  function getContextTreeStateFile(repoRoot) {
192
230
  return path.join(getUmDir(repoRoot), CONTEXT_TREE_STATE_FILE);
193
231
  }
232
+ function getQueryCacheFile(repoRoot) {
233
+ return path.join(getUmDir(repoRoot), QUERY_CACHE_FILE);
234
+ }
194
235
  async function ensureUmDir(repoRoot) {
195
236
  await fs.mkdir(getUmDir(repoRoot), { recursive: true });
196
237
  }
@@ -303,6 +344,9 @@ export async function addPendingMemory(input, cwd = process.cwd()) {
303
344
  id: randomUUID(),
304
345
  createdAt: new Date().toISOString(),
305
346
  ...input,
347
+ keywords: input.keywords ?? [],
348
+ category: input.category ?? null,
349
+ accessLevel: input.accessLevel ?? "space",
306
350
  };
307
351
  current.push(entry);
308
352
  await writeJsonFile(getPendingMemoriesFile(repoRoot), current);
@@ -315,7 +359,95 @@ export async function addPendingMemory(input, cwd = process.cwd()) {
315
359
  }
316
360
  export async function getPendingMemories(cwd = process.cwd()) {
317
361
  const { repoRoot } = await getRepoContext(cwd);
318
- return readJsonFile(getPendingMemoriesFile(repoRoot), []);
362
+ const entries = await readJsonFile(getPendingMemoriesFile(repoRoot), []);
363
+ return normalizeLocalMemoryEntries(entries);
364
+ }
365
+ function normalizeQueryCacheEntries(entries) {
366
+ return entries.map((entry) => ({
367
+ ...entry,
368
+ payload: {
369
+ ...entry.payload,
370
+ localMatches: normalizeLocalMemoryEntries(entry.payload.localMatches ?? []),
371
+ serverMatches: entry.payload.serverMatches ?? [],
372
+ suggestions: entry.payload.suggestions ?? [],
373
+ providerReady: entry.payload.providerReady ?? false,
374
+ providerRequiredForSynthesis: entry.payload.providerRequiredForSynthesis ?? false,
375
+ directAnswer: entry.payload.directAnswer ?? null,
376
+ synthesizedAnswer: entry.payload.synthesizedAnswer ?? null,
377
+ total: entry.payload.total ??
378
+ (entry.payload.localMatches?.length ?? 0) + (entry.payload.serverMatches?.length ?? 0),
379
+ },
380
+ hits: entry.hits ?? 0,
381
+ createdAt: entry.createdAt ?? new Date().toISOString(),
382
+ updatedAt: entry.updatedAt ?? new Date().toISOString(),
383
+ }));
384
+ }
385
+ export async function getQueryCacheEntries(cwd = process.cwd()) {
386
+ const { repoRoot } = await getRepoContext(cwd);
387
+ const entries = await readJsonFile(getQueryCacheFile(repoRoot), []);
388
+ return normalizeQueryCacheEntries(entries);
389
+ }
390
+ export async function getQueryCacheEntry(query, fingerprint, cwd = process.cwd()) {
391
+ const normalizedQuery = query.trim().toLowerCase();
392
+ const entries = await getQueryCacheEntries(cwd);
393
+ return (entries.find((entry) => entry.normalizedQuery === normalizedQuery && entry.fingerprint === fingerprint) ?? null);
394
+ }
395
+ export async function buildLocalQueryFingerprint(cwd = process.cwd()) {
396
+ const [pending, pulled] = await Promise.all([getPendingMemories(cwd), getPulledMemories(cwd)]);
397
+ const stablePayload = [...pending, ...pulled]
398
+ .map((entry) => ({
399
+ id: entry.id,
400
+ content: entry.content,
401
+ tags: [...entry.tags].sort(),
402
+ keywords: [...(entry.keywords ?? [])].sort(),
403
+ category: entry.category ?? null,
404
+ accessLevel: entry.accessLevel ?? "space",
405
+ source: entry.source,
406
+ systemType: entry.systemType,
407
+ createdAt: entry.createdAt,
408
+ }))
409
+ .sort((a, b) => a.id.localeCompare(b.id));
410
+ return createHash("sha1")
411
+ .update(JSON.stringify(stablePayload))
412
+ .digest("hex");
413
+ }
414
+ export async function storeQueryCacheEntry(input, cwd = process.cwd()) {
415
+ const { repoRoot } = await getRepoContext(cwd);
416
+ await ensureUmDir(repoRoot);
417
+ const entries = await getQueryCacheEntries(cwd);
418
+ const now = new Date().toISOString();
419
+ const existing = entries.find((entry) => entry.normalizedQuery === input.normalizedQuery && entry.fingerprint === input.fingerprint);
420
+ const nextEntries = existing
421
+ ? entries.map((entry) => entry.id === existing.id
422
+ ? {
423
+ ...entry,
424
+ query: input.query,
425
+ payload: input.payload,
426
+ updatedAt: now,
427
+ }
428
+ : entry)
429
+ : [
430
+ {
431
+ id: randomUUID(),
432
+ createdAt: now,
433
+ updatedAt: now,
434
+ hits: 0,
435
+ ...input,
436
+ },
437
+ ...entries,
438
+ ];
439
+ await writeJsonFile(getQueryCacheFile(repoRoot), nextEntries.slice(0, 50));
440
+ }
441
+ export async function markQueryCacheHit(entryId, cwd = process.cwd()) {
442
+ const { repoRoot } = await getRepoContext(cwd);
443
+ const entries = await getQueryCacheEntries(cwd);
444
+ await writeJsonFile(getQueryCacheFile(repoRoot), entries.map((entry) => entry.id === entryId
445
+ ? {
446
+ ...entry,
447
+ hits: (entry.hits ?? 0) + 1,
448
+ updatedAt: new Date().toISOString(),
449
+ }
450
+ : entry));
319
451
  }
320
452
  export async function clearPendingMemories(cwd = process.cwd()) {
321
453
  const { repoRoot } = await getRepoContext(cwd);
@@ -401,7 +533,7 @@ export async function resetRepoState(cwd = process.cwd()) {
401
533
  export async function setPulledMemories(memories, cwd = process.cwd()) {
402
534
  const { repoRoot } = await getRepoContext(cwd);
403
535
  await ensureUmDir(repoRoot);
404
- await writeJsonFile(getPulledMemoriesFile(repoRoot), memories);
536
+ await writeJsonFile(getPulledMemoriesFile(repoRoot), normalizeLocalMemoryEntries(memories));
405
537
  await updateRepoContext((state) => ({
406
538
  ...state,
407
539
  updatedAt: new Date().toISOString(),
@@ -419,7 +551,8 @@ export async function setPulledMemories(memories, cwd = process.cwd()) {
419
551
  }
420
552
  export async function getPulledMemories(cwd = process.cwd()) {
421
553
  const { repoRoot } = await getRepoContext(cwd);
422
- return readJsonFile(getPulledMemoriesFile(repoRoot), []);
554
+ const entries = await readJsonFile(getPulledMemoriesFile(repoRoot), []);
555
+ return normalizeLocalMemoryEntries(entries);
423
556
  }
424
557
  export async function setPulledFixes(fixes, cwd = process.cwd()) {
425
558
  const { repoRoot } = await getRepoContext(cwd);
@@ -867,6 +1000,14 @@ export async function completeTask(taskId, status, detail, cwd = process.cwd())
867
1000
  result: detail ?? null,
868
1001
  }, cwd);
869
1002
  }
1003
+ export async function removeTask(taskId, cwd = process.cwd()) {
1004
+ const { repoRoot } = await getRepoContext(cwd);
1005
+ const tasks = await readJsonFile(getTasksFile(repoRoot), []);
1006
+ const nextTasks = tasks.filter((task) => task.id !== taskId);
1007
+ await writeJsonFile(getTasksFile(repoRoot), nextTasks);
1008
+ await syncTransportFromTasks(cwd);
1009
+ await rebuildContextTreeState(cwd);
1010
+ }
870
1011
  export async function addConnectorRun(input, cwd = process.cwd()) {
871
1012
  const { repoRoot } = await getRepoContext(cwd);
872
1013
  await ensureUmDir(repoRoot);
@@ -1024,13 +1165,14 @@ export async function setSessionSummary(summary, cwd = process.cwd()) {
1024
1165
  }), cwd);
1025
1166
  }
1026
1167
  export async function setSessionPanel(panel, focus, cwd = process.cwd()) {
1168
+ const normalizedPanel = normalizeSessionPanel(panel);
1027
1169
  return updateSessionState((state) => ({
1028
1170
  ...state,
1029
1171
  updatedAt: new Date().toISOString(),
1030
- currentPanel: panel,
1172
+ currentPanel: normalizedPanel,
1031
1173
  currentFocus: focus ?? null,
1032
- panelHistory: panel
1033
- ? [panel, ...(state.panelHistory ?? []).filter((entry) => entry !== panel)].slice(0, 10)
1174
+ panelHistory: normalizedPanel
1175
+ ? [normalizedPanel, ...(state.panelHistory ?? []).filter((entry) => entry !== normalizedPanel)].slice(0, 10)
1034
1176
  : (state.panelHistory ?? []),
1035
1177
  }), cwd);
1036
1178
  }
@@ -1080,8 +1222,49 @@ export function summarizeLocalMemoryMatches(entries, query) {
1080
1222
  const needle = query.trim().toLowerCase();
1081
1223
  if (!needle)
1082
1224
  return [];
1225
+ const normalizedWords = needle
1226
+ .replace(/[?!.:,;()[\]{}]/g, " ")
1227
+ .split(/\s+/)
1228
+ .map((word) => word.trim())
1229
+ .filter(Boolean)
1230
+ .filter((word) => !new Set([
1231
+ "a",
1232
+ "an",
1233
+ "and",
1234
+ "are",
1235
+ "do",
1236
+ "does",
1237
+ "how",
1238
+ "implemented",
1239
+ "is",
1240
+ "the",
1241
+ "what",
1242
+ "where",
1243
+ "why",
1244
+ ]).has(word));
1245
+ const synonymMap = {
1246
+ auth: ["authentication", "signin", "sign-in", "jwt", "token", "cookie", "cookies"],
1247
+ authentication: ["auth", "signin", "sign-in", "jwt", "token", "cookie", "cookies"],
1248
+ rate: ["throttle", "limit", "limits", "limiting"],
1249
+ limits: ["limit", "rate", "throttle", "limiting"],
1250
+ };
1083
1251
  return entries.filter((entry) => {
1084
- const haystack = [entry.content, ...entry.tags].join(" ").toLowerCase();
1085
- return haystack.includes(needle);
1252
+ const haystack = [entry.content, ...entry.tags, ...(entry.keywords ?? [])]
1253
+ .join(" ")
1254
+ .toLowerCase();
1255
+ if (haystack.includes(needle))
1256
+ return true;
1257
+ let matchedWords = 0;
1258
+ for (const word of normalizedWords) {
1259
+ const variants = [word, ...(synonymMap[word] ?? [])];
1260
+ if (variants.some((variant) => haystack.includes(variant))) {
1261
+ matchedWords += 1;
1262
+ }
1263
+ }
1264
+ if (normalizedWords.length === 0)
1265
+ return false;
1266
+ if (normalizedWords.length === 1)
1267
+ return matchedWords >= 1;
1268
+ return matchedWords >= Math.min(2, normalizedWords.length);
1086
1269
  });
1087
1270
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "umbrella-context",
3
- "version": "0.1.37",
3
+ "version": "0.1.39",
4
4
  "description": "Umbrella Context CLI for connecting a device to company context spaces, querying saved context, and syncing MCP access.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,7 +27,7 @@
27
27
  "conf": "^13.1.0",
28
28
  "ink": "^5.2.1",
29
29
  "ink-spinner": "^5.0.0",
30
- "ink-text-input": "^5.0.1",
30
+ "ink-text-input": "^6.0.0",
31
31
  "prompts": "^2.4.2",
32
32
  "react": "^18.3.1",
33
33
  "zod": "^3.25.76",