umbrella-context 0.1.35 → 0.1.37

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/README.md CHANGED
@@ -8,6 +8,12 @@ Use this CLI to connect a laptop or IDE to an Umbrella company context space.
8
8
  npm install -g umbrella-context
9
9
  ```
10
10
 
11
+ Or install it inside the current project:
12
+
13
+ ```bash
14
+ npm i umbrella-context
15
+ ```
16
+
11
17
  For local testing from a tarball:
12
18
 
13
19
  ```bash
@@ -20,6 +26,12 @@ npm install -g ./umbrella-context-0.1.1.tgz
20
26
  umbrella-context setup
21
27
  ```
22
28
 
29
+ If you installed it locally instead of globally:
30
+
31
+ ```bash
32
+ npx umbrella-context setup
33
+ ```
34
+
23
35
  The setup flow will:
24
36
  - connect to your Umbrella server
25
37
  - sign you in when needed
@@ -33,9 +45,12 @@ The setup flow will:
33
45
  ```bash
34
46
  umbrella-context query "What do we already know?"
35
47
  umbrella-context curate "We learned that..."
48
+ umbrella-context push
49
+ umbrella-context pull
36
50
  umbrella-context fix "ETIMEDOUT"
37
51
  umbrella-context mcp
38
52
  umbrella-context
39
53
  ```
40
54
 
41
55
  The old `agent-memory` command still works as a compatibility alias.
56
+ The short `um` command works too.
@@ -1,15 +1,34 @@
1
- import { type VendorBridgeRuntimeSnapshot } from "./byterover-runtime-bridge.js";
2
- export declare const useUmbrellaContextRuntimeBridgeStore: any;
1
+ import { type VendorBridgeConnectorsState, type VendorBridgeContextTreeState, type VendorBridgeHubState, type VendorBridgeModelState, type VendorBridgeProviderState, type VendorBridgeRuntimeSnapshot, type VendorBridgeSpaceState } from "./byterover-runtime-bridge.js";
2
+ type UmbrellaContextRuntimeBridgeState = {
3
+ company: VendorBridgeRuntimeSnapshot["company"];
4
+ connectorsStore: VendorBridgeConnectorsState | null;
5
+ generatedAt: string | null;
6
+ hubStore: VendorBridgeHubState | null;
7
+ isHydrated: boolean;
8
+ modelStore: VendorBridgeModelState | null;
9
+ providerStore: VendorBridgeProviderState | null;
10
+ repo: VendorBridgeRuntimeSnapshot["repo"] | null;
11
+ services: VendorBridgeRuntimeSnapshot["services"] | null;
12
+ space: VendorBridgeRuntimeSnapshot["space"];
13
+ spaceStore: VendorBridgeSpaceState | null;
14
+ treeStore: VendorBridgeContextTreeState | null;
15
+ };
16
+ type UmbrellaContextRuntimeBridgeActions = {
17
+ hydrateFromSnapshot: (snapshot: VendorBridgeRuntimeSnapshot) => void;
18
+ reset: () => void;
19
+ };
20
+ export declare const useUmbrellaContextRuntimeBridgeStore: import("zustand").UseBoundStore<import("zustand").StoreApi<UmbrellaContextRuntimeBridgeActions & UmbrellaContextRuntimeBridgeState>>;
3
21
  export declare function hydrateUmbrellaContextRuntimeBridgeFromSnapshot(snapshot: VendorBridgeRuntimeSnapshot): void;
4
22
  export declare function hydrateUmbrellaContextRuntimeBridge(cwd?: string): Promise<VendorBridgeRuntimeSnapshot>;
5
23
  export declare function getUmbrellaContextRuntimeSummary(): {
6
- companyName: any;
7
- generatedAt: any;
8
- isHydrated: any;
9
- modelName: any;
10
- providerName: any;
11
- runtimeStatus: any;
12
- spaceCount: any;
13
- spaceName: any;
14
- treeNodes: any;
24
+ companyName: string | null;
25
+ generatedAt: string | null;
26
+ isHydrated: boolean;
27
+ modelName: string | null;
28
+ providerName: string | null;
29
+ runtimeStatus: "failure" | "warning" | "running" | "idle";
30
+ spaceCount: number;
31
+ spaceName: string | null;
32
+ treeNodes: number;
15
33
  };
34
+ export {};
@@ -211,7 +211,7 @@ async function buildConnectorsSnapshot(cwd = process.cwd()) {
211
211
  installed,
212
212
  installedSources: installed.map((entry) => entry.source),
213
213
  isLoading: false,
214
- recentRunSource: runs[0]?.source ?? null,
214
+ recentRunSource: runs[0]?.connectorId ?? null,
215
215
  recentSource: sessionState?.recentConnectorSources?.[0] ?? null,
216
216
  runs,
217
217
  };
@@ -1,13 +1,24 @@
1
- import { type VendorBridgeRuntimeSnapshot } from "./byterover-runtime-bridge.js";
2
- export declare const useUmbrellaTransportTaskBridgeStore: any;
1
+ import { type VendorBridgeRuntimeSnapshot, type VendorBridgeTasksState, type VendorBridgeTransportState } from "./byterover-runtime-bridge.js";
2
+ type UmbrellaTransportTaskBridgeState = {
3
+ generatedAt: string | null;
4
+ isHydrated: boolean;
5
+ taskStore: VendorBridgeTasksState;
6
+ transportStore: VendorBridgeTransportState | null;
7
+ };
8
+ type UmbrellaTransportTaskBridgeActions = {
9
+ hydrateFromSnapshot: (snapshot: VendorBridgeRuntimeSnapshot) => void;
10
+ reset: () => void;
11
+ };
12
+ export declare const useUmbrellaTransportTaskBridgeStore: import("zustand").UseBoundStore<import("zustand").StoreApi<UmbrellaTransportTaskBridgeActions & UmbrellaTransportTaskBridgeState>>;
3
13
  export declare function hydrateUmbrellaTransportTaskBridgeFromSnapshot(snapshot: VendorBridgeRuntimeSnapshot): void;
4
14
  export declare function hydrateUmbrellaTransportTaskBridge(cwd?: string): Promise<VendorBridgeRuntimeSnapshot>;
5
15
  export declare function getUmbrellaTransportTaskBridgeSummary(): {
6
- activeTaskId: any;
7
- generatedAt: any;
8
- isHydrated: any;
9
- queueDepth: any;
10
- recentTaskCount: any;
11
- startedTasks: any;
12
- transportStatus: any;
16
+ activeTaskId: string | null;
17
+ generatedAt: string | null;
18
+ isHydrated: boolean;
19
+ queueDepth: number;
20
+ recentTaskCount: number;
21
+ startedTasks: number;
22
+ transportStatus: "failure" | "warning" | "running" | "idle";
13
23
  };
24
+ export {};
@@ -74,6 +74,9 @@ export async function saveUmbrellaDeviceLink(setup, umbrellaUrl, cwd = process.c
74
74
  export async function connectUmbrellaDevice(serverUrl, companyId, spaceId, cookie, cwd = process.cwd()) {
75
75
  const normalizedServerUrl = normalizeUmbrellaServerUrl(serverUrl);
76
76
  const setup = await getCliSetup(normalizedServerUrl, companyId, spaceId, cookie);
77
+ if (!setup.apiKey || setup.apiKey.trim().length === 0) {
78
+ throw new Error("Umbrella returned a Context setup response without an API key. The live deployment is likely out of date for this CLI.");
79
+ }
77
80
  await saveUmbrellaDeviceLink(setup, normalizedServerUrl, cwd);
78
81
  return setup;
79
82
  }
@@ -10,7 +10,7 @@ export async function bridgeCommandAction(action) {
10
10
  return;
11
11
  }
12
12
  const summary = await buildVendorRuntimeBridgeSummary();
13
- console.log(chalk.bold("\n ByteRover Runtime Bridge\n"));
13
+ console.log(chalk.bold("\n Umbrella Runtime Bridge\n"));
14
14
  console.log(` Company: ${summary.company}`);
15
15
  console.log(` Space: ${summary.space}`);
16
16
  console.log(` Repo: ${summary.repoRoot}`);
@@ -29,11 +29,11 @@ export async function bridgeCommandAction(action) {
29
29
  console.log(` nodes=${summary.tree.nodes} transport=${summary.tree.runtimeStatus}`);
30
30
  console.log(` provider=${summary.tree.runtimeProvider ?? "none"}`);
31
31
  console.log("");
32
- console.log(chalk.gray(" Use `umbrella-context bridge json` to inspect the full projected upstream-shaped snapshot."));
32
+ console.log(chalk.gray(" Use `umbrella-context bridge json` to inspect the full projected runtime snapshot."));
33
33
  }
34
34
  export function bridgeCommand(cli) {
35
35
  cli
36
- .command("bridge [action]", "Project the local .um runtime into ByteRover-shaped store snapshots")
36
+ .command("bridge [action]", "Project the local .um runtime into the internal bridge snapshot")
37
37
  .action(async (action) => {
38
38
  await bridgeCommandAction(action);
39
39
  });
@@ -178,7 +178,7 @@ export const COMMAND_SPECS = [
178
178
  {
179
179
  key: "bridge",
180
180
  usage: "/bridge [summary|json]",
181
- description: "Show the ByteRover-shaped runtime bridge for parity work",
181
+ description: "Show the internal runtime bridge snapshot",
182
182
  action: async (args) => {
183
183
  await bridgeCommandAction(args[0] ?? "summary");
184
184
  },
@@ -49,6 +49,15 @@ function describeSetupFailure(error) {
49
49
  if (error.status === 403 && path.includes("/learning")) {
50
50
  return "This account can reach Umbrella, but it is blocked from that company's Context area. Usually that means the account is not attached to that company yet.";
51
51
  }
52
+ if (error.status === 422 && path.includes("/learning")) {
53
+ return `Umbrella reached the company Context service, but that service said it is not ready yet: ${error.message}`;
54
+ }
55
+ if (error.status === 404 && path.endsWith("/learning/cli-setup")) {
56
+ return "This Umbrella server is missing the Context setup endpoint that this CLI expects. The live deployment likely needs to be updated.";
57
+ }
58
+ if (error.status >= 500 && path.includes("/learning")) {
59
+ return `Umbrella hit an internal Context setup error while calling ${path}. That usually means the live server is missing Context bootstrap configuration or is running an older deployment.`;
60
+ }
52
61
  if (error.status === 403) {
53
62
  return `Umbrella refused this request with 403 Forbidden while calling ${path}. Usually that means this account is authenticated but does not have permission for that step yet.`;
54
63
  }
@@ -118,7 +118,7 @@ function SpacePanelView(props) {
118
118
  if (mode === "create") {
119
119
  return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Create a New Space" }), _jsx(Text, { color: "gray", children: "Spaces are team lanes inside one company, like Growth, Engineering, or Marketing." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Company", value: companyName }), _jsx(StatusLine, { label: "Current space", value: currentSpaceName })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "yellow", children: "New space name" }), _jsx(TextInput, { value: draftName, onChange: onDraftChange })] }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: _jsx(Text, { color: "gray", children: "Press Enter to create the new space, or Esc to go back to the list." }) })] }));
120
120
  }
121
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Company Spaces" }), _jsx(Text, { color: "gray", children: "This is the live team-lane picker for the current company, similar to ByteRover's space switch flow." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Company", value: companyName }), _jsx(StatusLine, { label: "Current space", value: currentSpaceName }), _jsx(StatusLine, { label: "Available spaces", value: String(spaces.length) })] }), _jsx(Section, { title: "Select a Space", children: spaces.length === 0 ? (_jsx(Text, { color: "yellow", children: "No spaces found yet. Press n to create the first one." })) : spaces.map((space, index) => {
121
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Company Spaces" }), _jsx(Text, { color: "gray", children: "This is the live team-lane picker for the current company." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Company", value: companyName }), _jsx(StatusLine, { label: "Current space", value: currentSpaceName }), _jsx(StatusLine, { label: "Available spaces", value: String(spaces.length) })] }), _jsx(Section, { title: "Select a Space", children: spaces.length === 0 ? (_jsx(Text, { color: "yellow", children: "No spaces found yet. Press n to create the first one." })) : spaces.map((space, index) => {
122
122
  const highlighted = index === selectedIndex;
123
123
  const active = space.name === currentSpaceName;
124
124
  return (_jsxs(Text, { color: highlighted ? "yellow" : active ? "green" : "white", children: [highlighted ? ">" : " ", " ", space.name, space.isPrimary ? " (core)" : "", active ? " (active)" : ""] }, space.id));
@@ -142,7 +142,7 @@ function ProviderPanelView(props) {
142
142
  : "This is only needed for OpenAI-compatible providers.";
143
143
  return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Connect a Provider" }), _jsx(Text, { color: "gray", children: help }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "yellow", children: label }), _jsx(TextInput, { value: connectDraftValue, onChange: onConnectDraftChange })] }), _jsx(Text, { color: "gray", children: "Press Enter to continue. Esc goes back one step." })] }));
144
144
  }
145
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Provider Runtime" }), _jsx(Text, { color: "gray", children: "This is the device-side runtime picker, closer to ByteRover's provider flow." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Connected providers", value: String(providers.length) }), _jsx(StatusLine, { label: "Active provider", value: providers.find((entry) => entry.id === activeProviderId)?.name ?? "Not connected" }), _jsx(StatusLine, { label: "Active model", value: activeModel ?? "Not selected" }), _jsx(StatusLine, { label: "State", value: readinessState })] }), _jsx(Section, { title: "Select a Provider", children: providers.length === 0 ? (_jsx(Text, { color: "yellow", children: "No providers are connected yet. Press c to start the live connect flow." })) : providers.map((provider, index) => {
145
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Provider Runtime" }), _jsx(Text, { color: "gray", children: "This is the device-side runtime picker for Context work." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Connected providers", value: String(providers.length) }), _jsx(StatusLine, { label: "Active provider", value: providers.find((entry) => entry.id === activeProviderId)?.name ?? "Not connected" }), _jsx(StatusLine, { label: "Active model", value: activeModel ?? "Not selected" }), _jsx(StatusLine, { label: "State", value: readinessState })] }), _jsx(Section, { title: "Select a Provider", children: providers.length === 0 ? (_jsx(Text, { color: "yellow", children: "No providers are connected yet. Press c to start the live connect flow." })) : providers.map((provider, index) => {
146
146
  const highlighted = index === selectedIndex;
147
147
  const active = provider.id === activeProviderId;
148
148
  const recent = provider.id === recentProviderId;
@@ -151,7 +151,7 @@ function ProviderPanelView(props) {
151
151
  }
152
152
  function ModelPanelView(props) {
153
153
  const { activeModel, providerName, recentModel, selectedIndex, models } = props;
154
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Model Runtime" }), _jsx(Text, { color: "gray", children: "This is the live model picker for the active provider, closer to ByteRover's model flow." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Provider", value: providerName }), _jsx(StatusLine, { label: "Active model", value: activeModel ?? "Not selected" }), _jsx(StatusLine, { label: "Available models", value: String(models.length) })] }), _jsx(Section, { title: "Select a Model", children: models.length === 0 ? (_jsx(Text, { color: "yellow", children: "No models are available for the active provider yet." })) : models.map((model, index) => {
154
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Model Runtime" }), _jsx(Text, { color: "gray", children: "This is the live model picker for the active provider." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Provider", value: providerName }), _jsx(StatusLine, { label: "Active model", value: activeModel ?? "Not selected" }), _jsx(StatusLine, { label: "Available models", value: String(models.length) })] }), _jsx(Section, { title: "Select a Model", children: models.length === 0 ? (_jsx(Text, { color: "yellow", children: "No models are available for the active provider yet." })) : models.map((model, index) => {
155
155
  const highlighted = index === selectedIndex;
156
156
  const active = model === activeModel;
157
157
  const recent = model === recentModel;
@@ -214,6 +214,11 @@ function App() {
214
214
  const vendorTaskStore = useUmbrellaTransportTaskBridgeStore((state) => state.taskStore);
215
215
  const vendorTransportStore = useUmbrellaTransportTaskBridgeStore((state) => state.transportStore);
216
216
  const vendorTreeStore = useUmbrellaContextRuntimeBridgeStore((state) => state.treeStore);
217
+ const vendorProviderStore = useUmbrellaContextRuntimeBridgeStore((state) => state.providerStore);
218
+ const vendorModelStore = useUmbrellaContextRuntimeBridgeStore((state) => state.modelStore);
219
+ const vendorSpaceStore = useUmbrellaContextRuntimeBridgeStore((state) => state.spaceStore);
220
+ const vendorHubStore = useUmbrellaContextRuntimeBridgeStore((state) => state.hubStore);
221
+ const vendorConnectorsStore = useUmbrellaContextRuntimeBridgeStore((state) => state.connectorsStore);
217
222
  const [selectedPanelIndex, setSelectedPanelIndex] = useState(0);
218
223
  const [activePanel, setActivePanel] = useState(configManager.config ? "home" : "setup");
219
224
  const [refreshTick, setRefreshTick] = useState(0);
@@ -299,6 +304,20 @@ function App() {
299
304
  useEffect(() => {
300
305
  void setSessionPanel(activePanel, configManager.config?.projectName ?? null);
301
306
  }, [activePanel]);
307
+ const readiness = useMemo(() => getProviderReadinessSummary(), [refreshTick, refreshState]);
308
+ const vendorTransportSummary = getUmbrellaTransportTaskBridgeSummary();
309
+ const vendorContextSummary = getUmbrellaContextRuntimeSummary();
310
+ const vendorTasks = useMemo(() => buildVendorTasksList(vendorTaskStore), [vendorTaskStore]);
311
+ const vendorActivity = useMemo(() => buildActivityItems(vendorTransportStore, refreshState?.session?.events ?? []), [vendorTransportStore, refreshState?.session?.events]);
312
+ const vendorProviders = useMemo(() => vendorProviderStore?.providers ?? [], [vendorProviderStore]);
313
+ const vendorModels = useMemo(() => (vendorModelStore?.models ?? []).map((model) => model.label), [vendorModelStore]);
314
+ const vendorSpaces = useMemo(() => (vendorSpaceStore?.spaces ?? []).map((space) => ({
315
+ id: space.id,
316
+ name: space.name,
317
+ isPrimary: space.isPrimary,
318
+ })), [vendorSpaceStore]);
319
+ const vendorRecentTransportEvents = useMemo(() => (vendorTransportStore?.events ?? []).slice(0, 5), [vendorTransportStore]);
320
+ const vendorRootTreeNodes = useMemo(() => (vendorTreeStore?.nodes ?? []).filter((node) => node.depth <= 1).slice(0, 8), [vendorTreeStore]);
302
321
  useEffect(() => {
303
322
  if (activePanel !== "spaces" || busyLabel)
304
323
  return;
@@ -359,25 +378,6 @@ function App() {
359
378
  setActivityPanelSelectedIndex(0);
360
379
  setActivityPanelMode("browse");
361
380
  }, [activePanel, busyLabel, refreshState, vendorActivity]);
362
- const readiness = useMemo(() => getProviderReadinessSummary(), [refreshTick, refreshState]);
363
- const vendorTransportSummary = getUmbrellaTransportTaskBridgeSummary();
364
- const vendorContextSummary = getUmbrellaContextRuntimeSummary();
365
- const vendorProviderStore = useUmbrellaContextRuntimeBridgeStore((state) => state.providerStore);
366
- const vendorModelStore = useUmbrellaContextRuntimeBridgeStore((state) => state.modelStore);
367
- const vendorSpaceStore = useUmbrellaContextRuntimeBridgeStore((state) => state.spaceStore);
368
- const vendorHubStore = useUmbrellaContextRuntimeBridgeStore((state) => state.hubStore);
369
- const vendorConnectorsStore = useUmbrellaContextRuntimeBridgeStore((state) => state.connectorsStore);
370
- const vendorTasks = useMemo(() => buildVendorTasksList(vendorTaskStore), [vendorTaskStore]);
371
- const vendorActivity = useMemo(() => buildActivityItems(vendorTransportStore, refreshState?.session?.events ?? []), [vendorTransportStore, refreshState?.session?.events]);
372
- const vendorProviders = useMemo(() => vendorProviderStore?.providers ?? [], [vendorProviderStore]);
373
- const vendorModels = useMemo(() => (vendorModelStore?.models ?? []).map((model) => model.label), [vendorModelStore]);
374
- const vendorSpaces = useMemo(() => (vendorSpaceStore?.spaces ?? []).map((space) => ({
375
- id: space.id,
376
- name: space.name,
377
- isPrimary: space.isPrimary,
378
- })), [vendorSpaceStore]);
379
- const vendorRecentTransportEvents = useMemo(() => (vendorTransportStore?.events ?? []).slice(0, 5), [vendorTransportStore]);
380
- const vendorRootTreeNodes = useMemo(() => (vendorTreeStore?.nodes ?? []).filter((node) => node.depth <= 1).slice(0, 8), [vendorTreeStore]);
381
381
  async function runPanelAction(busyText, action, successMessage) {
382
382
  setBusyLabel(busyText);
383
383
  setMessage(null);
@@ -1274,7 +1274,7 @@ function App() {
1274
1274
  mainContent = (_jsx(ConnectorsPanelView, { installedSources: vendorConnectorsStore?.installedSources ?? [], recentSource: vendorConnectorsStore?.recentSource ?? null, recentRunSource: vendorConnectorsStore?.recentRunSource ?? null, registryEntries: registryEntries, selectedIndex: connectorsPanelSelectedIndex }));
1275
1275
  }
1276
1276
  else {
1277
- mainContent = (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Session Memory" }), _jsx(Text, { color: "gray", children: "This is the live terminal memory saved inside the repo, plus the vendor-style runtime stores hydrated from the same Context engine." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Session ID", value: refreshState.session?.id ?? "None" }), _jsx(StatusLine, { label: "Current panel", value: refreshState.session?.currentPanel ?? "None" }), _jsx(StatusLine, { label: "Current focus", value: refreshState.session?.currentFocus ?? "None" }), _jsx(StatusLine, { label: "Commands", value: String(refreshState.session?.commandHistory.length ?? 0) }), _jsx(StatusLine, { label: "Events", value: String(refreshState.session?.events.length ?? 0) }), _jsx(StatusLine, { label: "Transport", value: vendorTransportStore?.status ?? refreshState.transport.status }), _jsx(StatusLine, { label: "Tree summary", value: vendorTreeStore?.summaryHandle ?? refreshState.treeState.summaryHandle })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Section, { title: "Transport and Tasks", children: [_jsx(StatusLine, { label: "Queue depth", value: String(vendorTransportStore?.queue.length ?? 0) }), _jsx(StatusLine, { label: "Recent tasks", value: String(vendorTasks.length) }), _jsx(StatusLine, { label: "Active task", value: vendorTransportSummary.activeTaskId ?? "None" }), _jsx(StatusLine, { label: "Started tasks", value: String(vendorTransportSummary.startedTasks) }), vendorRecentTransportEvents.length ? (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, color: "yellow", children: "Recent transport events" }), vendorRecentTransportEvents.map((event) => (_jsxs(Text, { color: "gray", children: [new Date(event.at).toLocaleString(), " | ", event.kind, " | ", event.title] }, `${event.kind}-${event.at}-${event.taskId ?? "no-task"}`)))] })) : (_jsx(Text, { color: "gray", children: "No transport events yet." }))] }), _jsxs(Section, { title: "Context Runtime Tree", children: [_jsx(StatusLine, { label: "Nodes", value: String(vendorTreeStore?.nodes.length ?? 0) }), _jsx(StatusLine, { label: "Pending drafts", value: String(vendorTreeStore?.stats.pendingDrafts ?? 0) }), _jsx(StatusLine, { label: "Pulled context", value: String(vendorTreeStore?.stats.pulledContext ?? 0) }), _jsx(StatusLine, { label: "Known fixes", value: String(vendorTreeStore?.stats.pulledFixes ?? 0) }), _jsx(StatusLine, { label: "Runtime transport", value: vendorTreeStore?.runtime.transportStatus ?? "idle" }), vendorRootTreeNodes.length ? (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, color: "yellow", children: "Top runtime nodes" }), vendorRootTreeNodes.map((node) => (_jsx(Text, { color: "gray", children: `${" ".repeat(node.depth)}- ${node.label}${node.detail ? ` | ${node.detail}` : ""}` }, node.id)))] })) : (_jsx(Text, { color: "gray", children: "The context tree has not been built yet." }))] }), _jsxs(Section, { title: "Session Continuity", children: [_jsx(StatusLine, { label: "Panel history", value: refreshState.session?.panelHistory.join(" -> ") || "None" }), _jsx(StatusLine, { label: "Recent providers", value: refreshState.session?.recentProviderIds.join(", ") || "None" }), _jsx(StatusLine, { label: "Recent models", value: refreshState.session?.recentModels.join(", ") || "None" }), _jsx(StatusLine, { label: "Recent hub items", value: refreshState.session?.recentHubSlugs.join(", ") || "None" }), _jsx(StatusLine, { label: "Recent connectors", value: refreshState.session?.recentConnectorSources.join(", ") || "None" })] }), _jsxs(Section, { title: "Vendor Bridge Runtime", children: [_jsx(StatusLine, { label: "Hydrated", value: vendorTransportSummary.isHydrated ? "Yes" : "No" }), _jsx(StatusLine, { label: "Generated", value: formatAgo(vendorTransportSummary.generatedAt) }), _jsx(StatusLine, { label: "Bridge queue", value: String(vendorTransportSummary.queueDepth) }), _jsx(StatusLine, { label: "Bridge tasks", value: String(vendorTransportSummary.recentTaskCount) }), _jsx(StatusLine, { label: "Bridge company", value: vendorContextSummary.companyName ?? "Unlinked company" }), _jsx(StatusLine, { label: "Bridge space", value: vendorContextSummary.spaceName ?? "Unlinked space" }), _jsx(StatusLine, { label: "Bridge provider", value: vendorContextSummary.providerName ?? "No provider" }), _jsx(StatusLine, { label: "Bridge model", value: vendorContextSummary.modelName ?? "No model" }), _jsx(StatusLine, { label: "Tree nodes", value: String(vendorContextSummary.treeNodes) }), _jsx(StatusLine, { label: "Runtime status", value: vendorContextSummary.runtimeStatus })] })] })] }));
1277
+ mainContent = (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Session Memory" }), _jsx(Text, { color: "gray", children: "This is the live terminal memory saved inside the repo, plus the internal runtime stores hydrated from the same Context engine." }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(StatusLine, { label: "Session ID", value: refreshState.session?.id ?? "None" }), _jsx(StatusLine, { label: "Current panel", value: refreshState.session?.currentPanel ?? "None" }), _jsx(StatusLine, { label: "Current focus", value: refreshState.session?.currentFocus ?? "None" }), _jsx(StatusLine, { label: "Commands", value: String(refreshState.session?.commandHistory.length ?? 0) }), _jsx(StatusLine, { label: "Events", value: String(refreshState.session?.events.length ?? 0) }), _jsx(StatusLine, { label: "Transport", value: vendorTransportStore?.status ?? refreshState.transport.status }), _jsx(StatusLine, { label: "Tree summary", value: vendorTreeStore?.summaryHandle ?? refreshState.treeState.summaryHandle })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Section, { title: "Transport and Tasks", children: [_jsx(StatusLine, { label: "Queue depth", value: String(vendorTransportStore?.queue.length ?? 0) }), _jsx(StatusLine, { label: "Recent tasks", value: String(vendorTasks.length) }), _jsx(StatusLine, { label: "Active task", value: vendorTransportSummary.activeTaskId ?? "None" }), _jsx(StatusLine, { label: "Started tasks", value: String(vendorTransportSummary.startedTasks) }), vendorRecentTransportEvents.length ? (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, color: "yellow", children: "Recent transport events" }), vendorRecentTransportEvents.map((event) => (_jsxs(Text, { color: "gray", children: [new Date(event.at).toLocaleString(), " | ", event.kind, " | ", event.title] }, `${event.kind}-${event.at}-${event.taskId ?? "no-task"}`)))] })) : (_jsx(Text, { color: "gray", children: "No transport events yet." }))] }), _jsxs(Section, { title: "Context Runtime Tree", children: [_jsx(StatusLine, { label: "Nodes", value: String(vendorTreeStore?.nodes.length ?? 0) }), _jsx(StatusLine, { label: "Pending drafts", value: String(vendorTreeStore?.stats.pendingDrafts ?? 0) }), _jsx(StatusLine, { label: "Pulled context", value: String(vendorTreeStore?.stats.pulledContext ?? 0) }), _jsx(StatusLine, { label: "Known fixes", value: String(vendorTreeStore?.stats.pulledFixes ?? 0) }), _jsx(StatusLine, { label: "Runtime transport", value: vendorTreeStore?.runtime.transportStatus ?? "idle" }), vendorRootTreeNodes.length ? (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, color: "yellow", children: "Top runtime nodes" }), vendorRootTreeNodes.map((node) => (_jsx(Text, { color: "gray", children: `${" ".repeat(node.depth)}- ${node.label}${node.detail ? ` | ${node.detail}` : ""}` }, node.id)))] })) : (_jsx(Text, { color: "gray", children: "The context tree has not been built yet." }))] }), _jsxs(Section, { title: "Session Continuity", children: [_jsx(StatusLine, { label: "Panel history", value: refreshState.session?.panelHistory.join(" -> ") || "None" }), _jsx(StatusLine, { label: "Recent providers", value: refreshState.session?.recentProviderIds.join(", ") || "None" }), _jsx(StatusLine, { label: "Recent models", value: refreshState.session?.recentModels.join(", ") || "None" }), _jsx(StatusLine, { label: "Recent hub items", value: refreshState.session?.recentHubSlugs.join(", ") || "None" }), _jsx(StatusLine, { label: "Recent connectors", value: refreshState.session?.recentConnectorSources.join(", ") || "None" })] }), _jsxs(Section, { title: "Runtime Bridge", children: [_jsx(StatusLine, { label: "Hydrated", value: vendorTransportSummary.isHydrated ? "Yes" : "No" }), _jsx(StatusLine, { label: "Generated", value: formatAgo(vendorTransportSummary.generatedAt) }), _jsx(StatusLine, { label: "Bridge queue", value: String(vendorTransportSummary.queueDepth) }), _jsx(StatusLine, { label: "Bridge tasks", value: String(vendorTransportSummary.recentTaskCount) }), _jsx(StatusLine, { label: "Bridge company", value: vendorContextSummary.companyName ?? "Unlinked company" }), _jsx(StatusLine, { label: "Bridge space", value: vendorContextSummary.spaceName ?? "Unlinked space" }), _jsx(StatusLine, { label: "Bridge provider", value: vendorContextSummary.providerName ?? "No provider" }), _jsx(StatusLine, { label: "Bridge model", value: vendorContextSummary.modelName ?? "No model" }), _jsx(StatusLine, { label: "Tree nodes", value: String(vendorContextSummary.treeNodes) }), _jsx(StatusLine, { label: "Runtime status", value: vendorContextSummary.runtimeStatus })] })] })] }));
1278
1278
  }
1279
1279
  return (_jsxs(PanelShell, { activePanel: activePanel, footer: footer, message: busyLabel ? `${busyLabel}` : message, selectedPanelIndex: selectedPanelIndex, children: [mainContent, inputMode ? (_jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "yellow", children: inputMode === "query" ? "Ask Context" : "Save a local Context note" }), _jsx(TextInput, { value: inputValue, onChange: setInputValue })] })) : null] }));
1280
1280
  }
package/dist/index.js CHANGED
@@ -66,7 +66,7 @@ cli.command("query [...args]", "Alias for search").action(async (args) => {
66
66
  await searchCommandAction(args.join(" "));
67
67
  });
68
68
  cli.help();
69
- cli.version("0.1.35");
69
+ cli.version("0.1.37");
70
70
  const argv = process.argv.slice(2);
71
71
  if (argv[0] === "curate" && argv[1] === "view" && argv.length === 2) {
72
72
  await curateViewCommandAction();
package/dist/umbrella.js CHANGED
@@ -24,8 +24,12 @@ function isLocalOnlyUmbrellaUrl(value) {
24
24
  }
25
25
  }
26
26
  async function requestJson(url, options) {
27
+ const parsedUrl = new URL(url);
28
+ const requestOrigin = `${parsedUrl.protocol}//${parsedUrl.host}`;
27
29
  const headers = {
28
30
  Accept: "application/json",
31
+ Origin: requestOrigin,
32
+ Referer: `${requestOrigin}/`,
29
33
  };
30
34
  if (options?.body !== undefined) {
31
35
  headers["Content-Type"] = "application/json";
@@ -42,8 +46,7 @@ async function requestJson(url, options) {
42
46
  });
43
47
  }
44
48
  catch (error) {
45
- const parsed = new URL(url);
46
- const origin = `${parsed.protocol}//${parsed.host}`;
49
+ const origin = requestOrigin;
47
50
  const localHint = isLocalOnlyUmbrellaUrl(origin)
48
51
  ? " That address only works if Umbrella is running on this same computer. If Umbrella lives on another machine, use that machine's real URL or IP instead."
49
52
  : "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "umbrella-context",
3
- "version": "0.1.35",
3
+ "version": "0.1.37",
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": {
@@ -30,8 +30,8 @@
30
30
  "ink-text-input": "^5.0.1",
31
31
  "prompts": "^2.4.2",
32
32
  "react": "^18.3.1",
33
- "zustand": "^5.0.8",
34
- "zod": "^3.25.76"
33
+ "zod": "^3.25.76",
34
+ "zustand": "^5.0.12"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/node": "^22.10.5",