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.
Files changed (38) hide show
  1. package/dist/commands/catalog.d.ts +33 -0
  2. package/dist/commands/catalog.js +211 -0
  3. package/dist/commands/connect.js +14 -14
  4. package/dist/commands/connectors.d.ts +15 -0
  5. package/dist/commands/connectors.js +620 -0
  6. package/dist/commands/curate.d.ts +1 -0
  7. package/dist/commands/curate.js +39 -3
  8. package/dist/commands/debug.d.ts +2 -0
  9. package/dist/commands/debug.js +55 -0
  10. package/dist/commands/hub.d.ts +20 -0
  11. package/dist/commands/hub.js +429 -0
  12. package/dist/commands/interactive.d.ts +2 -0
  13. package/dist/commands/interactive.js +918 -62
  14. package/dist/commands/locations.d.ts +1 -0
  15. package/dist/commands/locations.js +15 -12
  16. package/dist/commands/logout.d.ts +2 -0
  17. package/dist/commands/logout.js +34 -0
  18. package/dist/commands/model.d.ts +11 -0
  19. package/dist/commands/model.js +211 -0
  20. package/dist/commands/providers.d.ts +17 -0
  21. package/dist/commands/providers.js +344 -0
  22. package/dist/commands/pull.js +10 -1
  23. package/dist/commands/push.js +18 -1
  24. package/dist/commands/restart.d.ts +2 -0
  25. package/dist/commands/restart.js +21 -0
  26. package/dist/commands/search.js +19 -1
  27. package/dist/commands/session.d.ts +2 -0
  28. package/dist/commands/session.js +128 -0
  29. package/dist/commands/space.d.ts +1 -0
  30. package/dist/commands/space.js +81 -63
  31. package/dist/commands/status.d.ts +25 -0
  32. package/dist/commands/status.js +104 -16
  33. package/dist/config.d.ts +23 -0
  34. package/dist/config.js +69 -0
  35. package/dist/index.js +26 -4
  36. package/dist/repo-state.d.ts +84 -0
  37. package/dist/repo-state.js +419 -3
  38. package/package.json +1 -1
@@ -1,11 +1,38 @@
1
1
  import { promises as fs } from "fs";
2
2
  import path from "path";
3
3
  import { randomUUID } from "crypto";
4
+ import { execFileSync } from "child_process";
4
5
  const UM_DIR = ".um";
5
6
  const CONTEXT_FILE = "context.json";
6
7
  const PENDING_MEMORIES_FILE = "pending-memories.json";
7
8
  const PULLED_MEMORIES_FILE = "pulled-memories.json";
8
9
  const PULLED_FIXES_FILE = "pulled-fixes.json";
10
+ const CONNECTORS_FILE = "connectors.json";
11
+ const HUB_FILE = "hub.json";
12
+ const CONNECTOR_RUNS_FILE = "connector-runs.json";
13
+ const SESSION_FILE = "session.json";
14
+ const HUB_ASSETS_DIR = "hub";
15
+ const CONNECTOR_ASSETS_DIR = "connectors";
16
+ const CONNECTOR_RUN_REPORTS_DIR = "connector-runs";
17
+ function normalizeSessionState(state) {
18
+ if (!state)
19
+ return null;
20
+ return {
21
+ ...state,
22
+ commandHistory: state.commandHistory ?? [],
23
+ recentQueries: state.recentQueries ?? [],
24
+ recentCurations: state.recentCurations ?? [],
25
+ lastSummary: state.lastSummary ?? null,
26
+ currentPanel: state.currentPanel ?? null,
27
+ currentFocus: state.currentFocus ?? null,
28
+ panelHistory: state.panelHistory ?? [],
29
+ recentProviderIds: state.recentProviderIds ?? [],
30
+ recentModels: state.recentModels ?? [],
31
+ recentHubSlugs: state.recentHubSlugs ?? [],
32
+ recentConnectorSources: state.recentConnectorSources ?? [],
33
+ events: state.events ?? [],
34
+ };
35
+ }
9
36
  async function pathExists(targetPath) {
10
37
  try {
11
38
  await fs.access(targetPath);
@@ -15,19 +42,71 @@ async function pathExists(targetPath) {
15
42
  return false;
16
43
  }
17
44
  }
45
+ async function findNearestPackageRoot(startDir = process.cwd()) {
46
+ let current = path.resolve(startDir);
47
+ while (true) {
48
+ if (await pathExists(path.join(current, "package.json")))
49
+ return current;
50
+ const parent = path.dirname(current);
51
+ if (parent === current)
52
+ return null;
53
+ current = parent;
54
+ }
55
+ }
18
56
  export async function findRepoRoot(startDir = process.cwd()) {
57
+ try {
58
+ const gitRoot = execFileSync("git", ["rev-parse", "--show-toplevel"], {
59
+ cwd: startDir,
60
+ encoding: "utf8",
61
+ stdio: ["ignore", "pipe", "ignore"],
62
+ }).trim();
63
+ if (gitRoot)
64
+ return path.resolve(gitRoot);
65
+ }
66
+ catch {
67
+ // Fall back to local heuristics when git is unavailable or the cwd is not inside a git repo.
68
+ }
19
69
  let current = path.resolve(startDir);
70
+ let nearestPackageJsonDir = null;
20
71
  while (true) {
21
72
  if (await pathExists(path.join(current, ".git")))
22
73
  return current;
23
- if (await pathExists(path.join(current, "package.json")))
24
- return current;
74
+ if (!nearestPackageJsonDir && await pathExists(path.join(current, "package.json"))) {
75
+ nearestPackageJsonDir = current;
76
+ }
25
77
  const parent = path.dirname(current);
26
78
  if (parent === current)
27
- return path.resolve(startDir);
79
+ return nearestPackageJsonDir ?? path.resolve(startDir);
28
80
  current = parent;
29
81
  }
30
82
  }
83
+ async function copyMissingFiles(sourceDir, targetDir) {
84
+ if (!(await pathExists(sourceDir)))
85
+ return;
86
+ await fs.mkdir(targetDir, { recursive: true });
87
+ const entries = await fs.readdir(sourceDir, { withFileTypes: true });
88
+ for (const entry of entries) {
89
+ if (!entry.isFile())
90
+ continue;
91
+ const source = path.join(sourceDir, entry.name);
92
+ const target = path.join(targetDir, entry.name);
93
+ if (await pathExists(target))
94
+ continue;
95
+ await fs.copyFile(source, target);
96
+ }
97
+ }
98
+ function uniqueBy(items, key) {
99
+ const seen = new Set();
100
+ const result = [];
101
+ for (const item of items) {
102
+ const nextKey = key(item);
103
+ if (seen.has(nextKey))
104
+ continue;
105
+ seen.add(nextKey);
106
+ result.push(item);
107
+ }
108
+ return result;
109
+ }
31
110
  function getUmDir(repoRoot) {
32
111
  return path.join(repoRoot, UM_DIR);
33
112
  }
@@ -43,9 +122,26 @@ function getPulledMemoriesFile(repoRoot) {
43
122
  function getPulledFixesFile(repoRoot) {
44
123
  return path.join(getUmDir(repoRoot), PULLED_FIXES_FILE);
45
124
  }
125
+ function getConnectorsFile(repoRoot) {
126
+ return path.join(getUmDir(repoRoot), CONNECTORS_FILE);
127
+ }
128
+ function getHubFile(repoRoot) {
129
+ return path.join(getUmDir(repoRoot), HUB_FILE);
130
+ }
131
+ function getConnectorRunsFile(repoRoot) {
132
+ return path.join(getUmDir(repoRoot), CONNECTOR_RUNS_FILE);
133
+ }
134
+ function getSessionFile(repoRoot) {
135
+ return path.join(getUmDir(repoRoot), SESSION_FILE);
136
+ }
46
137
  async function ensureUmDir(repoRoot) {
47
138
  await fs.mkdir(getUmDir(repoRoot), { recursive: true });
48
139
  }
140
+ async function ensureSubDir(repoRoot, name) {
141
+ const target = path.join(getUmDir(repoRoot), name);
142
+ await fs.mkdir(target, { recursive: true });
143
+ return target;
144
+ }
49
145
  async function readJsonFile(filePath, fallback) {
50
146
  try {
51
147
  const raw = await fs.readFile(filePath, "utf8");
@@ -58,8 +154,47 @@ async function readJsonFile(filePath, fallback) {
58
154
  async function writeJsonFile(filePath, data) {
59
155
  await fs.writeFile(filePath, JSON.stringify(data, null, 2), "utf8");
60
156
  }
157
+ async function migrateLegacyUmDir(startDir, repoRoot) {
158
+ const legacyRoot = await findNearestPackageRoot(startDir);
159
+ if (!legacyRoot || legacyRoot === repoRoot)
160
+ return;
161
+ const legacyUmDir = getUmDir(legacyRoot);
162
+ if (!(await pathExists(legacyUmDir)))
163
+ return;
164
+ await ensureUmDir(repoRoot);
165
+ const mergeArrayFile = async (fileName, fallback, key) => {
166
+ const legacyPath = path.join(legacyUmDir, fileName);
167
+ if (!(await pathExists(legacyPath)))
168
+ return;
169
+ const rootPath = path.join(getUmDir(repoRoot), fileName);
170
+ const legacyItems = await readJsonFile(legacyPath, fallback);
171
+ const rootItems = await readJsonFile(rootPath, fallback);
172
+ const merged = uniqueBy([...rootItems, ...legacyItems], key);
173
+ await writeJsonFile(rootPath, merged);
174
+ };
175
+ const rootContextPath = getContextFile(repoRoot);
176
+ const legacyContextPath = getContextFile(legacyRoot);
177
+ if (!(await pathExists(rootContextPath)) && await pathExists(legacyContextPath)) {
178
+ await fs.copyFile(legacyContextPath, rootContextPath);
179
+ }
180
+ await mergeArrayFile(PENDING_MEMORIES_FILE, [], (item) => item.id);
181
+ await mergeArrayFile(PULLED_MEMORIES_FILE, [], (item) => item.id);
182
+ await mergeArrayFile(PULLED_FIXES_FILE, [], (item) => item.id);
183
+ await mergeArrayFile(CONNECTORS_FILE, [], (item) => item.source);
184
+ await mergeArrayFile(HUB_FILE, [], (item) => item.slug);
185
+ await mergeArrayFile(CONNECTOR_RUNS_FILE, [], (item) => item.id);
186
+ await copyMissingFiles(path.join(legacyUmDir, HUB_ASSETS_DIR), path.join(getUmDir(repoRoot), HUB_ASSETS_DIR));
187
+ await copyMissingFiles(path.join(legacyUmDir, CONNECTOR_ASSETS_DIR), path.join(getUmDir(repoRoot), CONNECTOR_ASSETS_DIR));
188
+ await copyMissingFiles(path.join(legacyUmDir, CONNECTOR_RUN_REPORTS_DIR), path.join(getUmDir(repoRoot), CONNECTOR_RUN_REPORTS_DIR));
189
+ const legacySessionPath = getSessionFile(legacyRoot);
190
+ const rootSessionPath = getSessionFile(repoRoot);
191
+ if (!(await pathExists(rootSessionPath)) && await pathExists(legacySessionPath)) {
192
+ await fs.copyFile(legacySessionPath, rootSessionPath);
193
+ }
194
+ }
61
195
  export async function ensureRepoContext(config, cwd = process.cwd()) {
62
196
  const repoRoot = await findRepoRoot(cwd);
197
+ await migrateLegacyUmDir(cwd, repoRoot);
63
198
  await ensureUmDir(repoRoot);
64
199
  const now = new Date().toISOString();
65
200
  const nextState = {
@@ -89,6 +224,7 @@ export async function ensureRepoContext(config, cwd = process.cwd()) {
89
224
  }
90
225
  export async function getRepoContext(cwd = process.cwd()) {
91
226
  const repoRoot = await findRepoRoot(cwd);
227
+ await migrateLegacyUmDir(cwd, repoRoot);
92
228
  const state = await readJsonFile(getContextFile(repoRoot), null);
93
229
  return { repoRoot, state, umDir: getUmDir(repoRoot) };
94
230
  }
@@ -160,6 +296,286 @@ export async function markPushCompleted(cwd = process.cwd()) {
160
296
  lastPushAt: new Date().toISOString(),
161
297
  }), cwd);
162
298
  }
299
+ export async function getInstalledConnectors(cwd = process.cwd()) {
300
+ const { repoRoot } = await getRepoContext(cwd);
301
+ const connectors = await readJsonFile(getConnectorsFile(repoRoot), []);
302
+ const deduped = uniqueBy(connectors, (item) => item.source);
303
+ if (deduped.length !== connectors.length) {
304
+ await writeJsonFile(getConnectorsFile(repoRoot), deduped);
305
+ }
306
+ return deduped;
307
+ }
308
+ export async function setInstalledConnectors(connectors, cwd = process.cwd()) {
309
+ const { repoRoot } = await getRepoContext(cwd);
310
+ await ensureUmDir(repoRoot);
311
+ await writeJsonFile(getConnectorsFile(repoRoot), uniqueBy(connectors, (item) => item.source));
312
+ await updateRepoContext((state) => ({
313
+ ...state,
314
+ updatedAt: new Date().toISOString(),
315
+ }), cwd);
316
+ }
317
+ export async function getInstalledHubEntries(cwd = process.cwd()) {
318
+ const { repoRoot } = await getRepoContext(cwd);
319
+ const entries = await readJsonFile(getHubFile(repoRoot), []);
320
+ const deduped = uniqueBy(entries, (item) => item.slug);
321
+ if (deduped.length !== entries.length) {
322
+ await writeJsonFile(getHubFile(repoRoot), deduped);
323
+ }
324
+ return deduped;
325
+ }
326
+ export async function setInstalledHubEntries(entries, cwd = process.cwd()) {
327
+ const { repoRoot } = await getRepoContext(cwd);
328
+ await ensureUmDir(repoRoot);
329
+ await writeJsonFile(getHubFile(repoRoot), uniqueBy(entries, (item) => item.slug));
330
+ await updateRepoContext((state) => ({
331
+ ...state,
332
+ updatedAt: new Date().toISOString(),
333
+ }), cwd);
334
+ }
335
+ export async function writeHubAsset(slug, content, cwd = process.cwd()) {
336
+ const { repoRoot } = await getRepoContext(cwd);
337
+ const dir = await ensureSubDir(repoRoot, HUB_ASSETS_DIR);
338
+ const filePath = path.join(dir, `${slug}.md`);
339
+ await fs.writeFile(filePath, content, "utf8");
340
+ return filePath;
341
+ }
342
+ export async function writeHubAssetFiles(slug, files, cwd = process.cwd()) {
343
+ const { repoRoot } = await getRepoContext(cwd);
344
+ const rootDir = await ensureSubDir(repoRoot, HUB_ASSETS_DIR);
345
+ const dir = path.join(rootDir, slug);
346
+ await fs.mkdir(dir, { recursive: true });
347
+ const written = [];
348
+ for (const file of files) {
349
+ const filePath = path.join(dir, file.name);
350
+ await fs.writeFile(filePath, file.content, "utf8");
351
+ written.push(filePath);
352
+ }
353
+ return written;
354
+ }
355
+ export async function writeConnectorAsset(source, content, cwd = process.cwd()) {
356
+ const { repoRoot } = await getRepoContext(cwd);
357
+ const dir = await ensureSubDir(repoRoot, CONNECTOR_ASSETS_DIR);
358
+ const filePath = path.join(dir, `${source}.json`);
359
+ await writeJsonFile(filePath, content);
360
+ return filePath;
361
+ }
362
+ export async function writeConnectorAssetFiles(source, files, cwd = process.cwd()) {
363
+ const { repoRoot } = await getRepoContext(cwd);
364
+ const rootDir = await ensureSubDir(repoRoot, CONNECTOR_ASSETS_DIR);
365
+ const dir = path.join(rootDir, source);
366
+ await fs.mkdir(dir, { recursive: true });
367
+ const written = [];
368
+ for (const file of files) {
369
+ const filePath = path.join(dir, file.name);
370
+ await fs.writeFile(filePath, file.content, "utf8");
371
+ written.push(filePath);
372
+ }
373
+ return written;
374
+ }
375
+ export async function getConnectorRuns(cwd = process.cwd()) {
376
+ const { repoRoot } = await getRepoContext(cwd);
377
+ return readJsonFile(getConnectorRunsFile(repoRoot), []);
378
+ }
379
+ export async function addConnectorRun(input, cwd = process.cwd()) {
380
+ const { repoRoot } = await getRepoContext(cwd);
381
+ await ensureUmDir(repoRoot);
382
+ const runs = await readJsonFile(getConnectorRunsFile(repoRoot), []);
383
+ const entry = {
384
+ id: randomUUID(),
385
+ ranAt: new Date().toISOString(),
386
+ ...input,
387
+ };
388
+ runs.unshift(entry);
389
+ await writeJsonFile(getConnectorRunsFile(repoRoot), runs.slice(0, 25));
390
+ await updateRepoContext((state) => ({
391
+ ...state,
392
+ updatedAt: new Date().toISOString(),
393
+ }), cwd);
394
+ return entry;
395
+ }
396
+ export async function writeConnectorRunReport(run, cwd = process.cwd()) {
397
+ const { repoRoot } = await getRepoContext(cwd);
398
+ const dir = await ensureSubDir(repoRoot, CONNECTOR_RUN_REPORTS_DIR);
399
+ const filePath = path.join(dir, `${run.id}.md`);
400
+ const markdown = [
401
+ `# ${run.connectorName}`,
402
+ "",
403
+ `- Status: ${run.status}`,
404
+ `- Ran At: ${run.ranAt}`,
405
+ `- Connector ID: ${run.connectorId}`,
406
+ "",
407
+ "## Summary",
408
+ "",
409
+ run.summary,
410
+ "",
411
+ ].join("\n");
412
+ await fs.writeFile(filePath, markdown, "utf8");
413
+ return filePath;
414
+ }
415
+ export async function getSessionState(cwd = process.cwd()) {
416
+ const { repoRoot } = await getRepoContext(cwd);
417
+ return normalizeSessionState(await readJsonFile(getSessionFile(repoRoot), null));
418
+ }
419
+ export async function ensureSessionState(cwd = process.cwd()) {
420
+ const { repoRoot } = await getRepoContext(cwd);
421
+ await ensureUmDir(repoRoot);
422
+ const existing = normalizeSessionState(await readJsonFile(getSessionFile(repoRoot), null));
423
+ if (existing) {
424
+ await writeJsonFile(getSessionFile(repoRoot), existing);
425
+ return existing;
426
+ }
427
+ const now = new Date().toISOString();
428
+ const next = {
429
+ version: 1,
430
+ id: randomUUID(),
431
+ startedAt: now,
432
+ updatedAt: now,
433
+ commandHistory: [],
434
+ recentQueries: [],
435
+ recentCurations: [],
436
+ lastSummary: null,
437
+ currentPanel: null,
438
+ currentFocus: null,
439
+ panelHistory: [],
440
+ recentProviderIds: [],
441
+ recentModels: [],
442
+ recentHubSlugs: [],
443
+ recentConnectorSources: [],
444
+ events: [],
445
+ };
446
+ await writeJsonFile(getSessionFile(repoRoot), next);
447
+ return next;
448
+ }
449
+ export async function resetSessionState(cwd = process.cwd()) {
450
+ const { repoRoot } = await getRepoContext(cwd);
451
+ await ensureUmDir(repoRoot);
452
+ const now = new Date().toISOString();
453
+ const next = {
454
+ version: 1,
455
+ id: randomUUID(),
456
+ startedAt: now,
457
+ updatedAt: now,
458
+ commandHistory: [],
459
+ recentQueries: [],
460
+ recentCurations: [],
461
+ lastSummary: "Started a fresh Context session.",
462
+ currentPanel: null,
463
+ currentFocus: null,
464
+ panelHistory: [],
465
+ recentProviderIds: [],
466
+ recentModels: [],
467
+ recentHubSlugs: [],
468
+ recentConnectorSources: [],
469
+ events: [
470
+ {
471
+ id: randomUUID(),
472
+ at: now,
473
+ kind: "session",
474
+ title: "Started a fresh Context session",
475
+ detail: "Local .um data stayed in place, but the live shell history was reset.",
476
+ panel: "session",
477
+ focus: null,
478
+ status: "info",
479
+ },
480
+ ],
481
+ };
482
+ await writeJsonFile(getSessionFile(repoRoot), next);
483
+ return next;
484
+ }
485
+ export async function updateSessionState(updater, cwd = process.cwd()) {
486
+ const { repoRoot } = await getRepoContext(cwd);
487
+ const current = normalizeSessionState(await ensureSessionState(cwd));
488
+ if (!current) {
489
+ throw new Error("Could not initialize repo session state.");
490
+ }
491
+ const next = normalizeSessionState(await updater(current));
492
+ if (!next) {
493
+ throw new Error("Could not update repo session state.");
494
+ }
495
+ await writeJsonFile(getSessionFile(repoRoot), next);
496
+ return next;
497
+ }
498
+ export async function recordSessionCommand(command, cwd = process.cwd()) {
499
+ return updateSessionState((state) => ({
500
+ ...state,
501
+ updatedAt: new Date().toISOString(),
502
+ commandHistory: [...(state.commandHistory ?? []), command].slice(-50),
503
+ }), cwd);
504
+ }
505
+ export async function recordSessionQuery(query, cwd = process.cwd()) {
506
+ return updateSessionState((state) => ({
507
+ ...state,
508
+ updatedAt: new Date().toISOString(),
509
+ recentQueries: [query, ...(state.recentQueries ?? []).filter((entry) => entry !== query)].slice(0, 10),
510
+ }), cwd);
511
+ }
512
+ export async function recordSessionCuration(content, cwd = process.cwd()) {
513
+ return updateSessionState((state) => ({
514
+ ...state,
515
+ updatedAt: new Date().toISOString(),
516
+ recentCurations: [content, ...(state.recentCurations ?? []).filter((entry) => entry !== content)].slice(0, 10),
517
+ }), cwd);
518
+ }
519
+ export async function setSessionSummary(summary, cwd = process.cwd()) {
520
+ return updateSessionState((state) => ({
521
+ ...state,
522
+ updatedAt: new Date().toISOString(),
523
+ lastSummary: summary,
524
+ }), cwd);
525
+ }
526
+ export async function setSessionPanel(panel, focus, cwd = process.cwd()) {
527
+ return updateSessionState((state) => ({
528
+ ...state,
529
+ updatedAt: new Date().toISOString(),
530
+ currentPanel: panel,
531
+ currentFocus: focus ?? null,
532
+ panelHistory: panel
533
+ ? [panel, ...(state.panelHistory ?? []).filter((entry) => entry !== panel)].slice(0, 10)
534
+ : (state.panelHistory ?? []),
535
+ }), cwd);
536
+ }
537
+ export async function recordSessionProvider(providerId, cwd = process.cwd()) {
538
+ return updateSessionState((state) => ({
539
+ ...state,
540
+ updatedAt: new Date().toISOString(),
541
+ recentProviderIds: [providerId, ...(state.recentProviderIds ?? []).filter((entry) => entry !== providerId)].slice(0, 5),
542
+ }), cwd);
543
+ }
544
+ export async function recordSessionModel(modelId, cwd = process.cwd()) {
545
+ return updateSessionState((state) => ({
546
+ ...state,
547
+ updatedAt: new Date().toISOString(),
548
+ recentModels: [modelId, ...(state.recentModels ?? []).filter((entry) => entry !== modelId)].slice(0, 5),
549
+ }), cwd);
550
+ }
551
+ export async function recordSessionHubEntry(slug, cwd = process.cwd()) {
552
+ return updateSessionState((state) => ({
553
+ ...state,
554
+ updatedAt: new Date().toISOString(),
555
+ recentHubSlugs: [slug, ...(state.recentHubSlugs ?? []).filter((entry) => entry !== slug)].slice(0, 5),
556
+ }), cwd);
557
+ }
558
+ export async function recordSessionConnector(source, cwd = process.cwd()) {
559
+ return updateSessionState((state) => ({
560
+ ...state,
561
+ updatedAt: new Date().toISOString(),
562
+ recentConnectorSources: [source, ...(state.recentConnectorSources ?? []).filter((entry) => entry !== source)].slice(0, 5),
563
+ }), cwd);
564
+ }
565
+ export async function recordSessionEvent(event, cwd = process.cwd()) {
566
+ return updateSessionState((state) => ({
567
+ ...state,
568
+ updatedAt: new Date().toISOString(),
569
+ events: [
570
+ {
571
+ id: randomUUID(),
572
+ at: new Date().toISOString(),
573
+ ...event,
574
+ },
575
+ ...(state.events ?? []),
576
+ ].slice(0, 30),
577
+ }), cwd);
578
+ }
163
579
  export function summarizeLocalMemoryMatches(entries, query) {
164
580
  const needle = query.trim().toLowerCase();
165
581
  if (!needle)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "umbrella-context",
3
- "version": "0.1.2",
3
+ "version": "0.1.20",
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": {