umbrella-context 0.1.36 → 0.1.38
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 +24 -2
- package/dist/adapters/byterover-context-runtime-store.d.ts +30 -11
- package/dist/adapters/byterover-runtime-bridge.js +1 -1
- package/dist/adapters/byterover-transport-task-store.d.ts +20 -9
- package/dist/adapters/umbrella-onboarding.js +6 -2
- package/dist/commands/bridge.js +3 -3
- package/dist/commands/catalog.js +1 -1
- package/dist/commands/connect.js +3 -2
- package/dist/commands/connectors.js +3 -0
- package/dist/commands/curate.d.ts +13 -1
- package/dist/commands/curate.js +146 -10
- package/dist/commands/fix.js +2 -10
- package/dist/commands/interactive.js +21 -10
- package/dist/commands/locations.d.ts +6 -1
- package/dist/commands/locations.js +91 -5
- package/dist/commands/mcp.js +7 -2
- package/dist/commands/pull.d.ts +6 -1
- package/dist/commands/pull.js +119 -3
- package/dist/commands/push.d.ts +6 -1
- package/dist/commands/push.js +147 -3
- package/dist/commands/restart.js +6 -1
- package/dist/commands/search.d.ts +5 -1
- package/dist/commands/search.js +857 -36
- package/dist/commands/session.js +0 -3
- package/dist/commands/setup.js +195 -26
- package/dist/commands/space.js +4 -3
- package/dist/commands/status.d.ts +16 -1
- package/dist/commands/status.js +111 -47
- package/dist/commands/tui.js +351 -122
- package/dist/config.d.ts +1 -0
- package/dist/config.js +5 -0
- package/dist/index.js +21 -3
- package/dist/repo-state.d.ts +115 -0
- package/dist/repo-state.js +195 -12
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -8,10 +8,23 @@ 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
|
-
|
|
11
|
+
Or install it inside the current project:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
npm
|
|
14
|
+
npm i umbrella-context
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
For local testing from a tarball built from this repo:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pnpm pack:umbrella-context:local
|
|
21
|
+
npm install -g ./.artifacts/umbrella-context-local/umbrella-context-<version>.tgz
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
If you want to pack it and launch the packed copy immediately without publishing:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pnpm run:umbrella-context:local
|
|
15
28
|
```
|
|
16
29
|
|
|
17
30
|
## First-time setup
|
|
@@ -20,6 +33,12 @@ npm install -g ./umbrella-context-0.1.1.tgz
|
|
|
20
33
|
umbrella-context setup
|
|
21
34
|
```
|
|
22
35
|
|
|
36
|
+
If you installed it locally instead of globally:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npx umbrella-context setup
|
|
40
|
+
```
|
|
41
|
+
|
|
23
42
|
The setup flow will:
|
|
24
43
|
- connect to your Umbrella server
|
|
25
44
|
- sign you in when needed
|
|
@@ -33,9 +52,12 @@ The setup flow will:
|
|
|
33
52
|
```bash
|
|
34
53
|
umbrella-context query "What do we already know?"
|
|
35
54
|
umbrella-context curate "We learned that..."
|
|
55
|
+
umbrella-context push
|
|
56
|
+
umbrella-context pull
|
|
36
57
|
umbrella-context fix "ETIMEDOUT"
|
|
37
58
|
umbrella-context mcp
|
|
38
59
|
umbrella-context
|
|
39
60
|
```
|
|
40
61
|
|
|
41
62
|
The old `agent-memory` command still works as a compatibility alias.
|
|
63
|
+
The short `um` command works too.
|
|
@@ -1,15 +1,34 @@
|
|
|
1
|
-
import { type VendorBridgeRuntimeSnapshot } from "./byterover-runtime-bridge.js";
|
|
2
|
-
|
|
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:
|
|
7
|
-
generatedAt:
|
|
8
|
-
isHydrated:
|
|
9
|
-
modelName:
|
|
10
|
-
providerName:
|
|
11
|
-
runtimeStatus:
|
|
12
|
-
spaceCount:
|
|
13
|
-
spaceName:
|
|
14
|
-
treeNodes:
|
|
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]?.
|
|
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
|
-
|
|
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:
|
|
7
|
-
generatedAt:
|
|
8
|
-
isHydrated:
|
|
9
|
-
queueDepth:
|
|
10
|
-
recentTaskCount:
|
|
11
|
-
startedTasks:
|
|
12
|
-
transportStatus:
|
|
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 {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { configManager } from "../config.js";
|
|
2
|
-
import { ensureRepoContext } from "../repo-state.js";
|
|
2
|
+
import { ensureRepoContext, findRepoRoot } from "../repo-state.js";
|
|
3
3
|
import { createContextSpace, createUmbrellaCompany, getCliSetup, getCompanyContextSummary, getUmbrellaHealth, listUmbrellaCompanies, signInToUmbrella, toContextSpaces, } from "../umbrella.js";
|
|
4
4
|
export function normalizeUmbrellaServerUrl(value) {
|
|
5
5
|
return value.trim().replace(/\/+$/, "");
|
|
@@ -50,6 +50,7 @@ export async function createUmbrellaOnboardingSpace(serverUrl, companyId, name,
|
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
export async function saveUmbrellaDeviceLink(setup, umbrellaUrl, cwd = process.cwd()) {
|
|
53
|
+
const repoRoot = await findRepoRoot(cwd);
|
|
53
54
|
configManager.set({
|
|
54
55
|
umbrellaUrl,
|
|
55
56
|
serverUrl: setup.baseUrl,
|
|
@@ -62,7 +63,7 @@ export async function saveUmbrellaDeviceLink(setup, umbrellaUrl, cwd = process.c
|
|
|
62
63
|
apiKey: setup.apiKey,
|
|
63
64
|
});
|
|
64
65
|
configManager.upsertLocation({
|
|
65
|
-
repoRoot
|
|
66
|
+
repoRoot,
|
|
66
67
|
companyId: setup.companyId,
|
|
67
68
|
companyName: setup.companyName,
|
|
68
69
|
projectId: setup.activeSpaceId,
|
|
@@ -74,6 +75,9 @@ export async function saveUmbrellaDeviceLink(setup, umbrellaUrl, cwd = process.c
|
|
|
74
75
|
export async function connectUmbrellaDevice(serverUrl, companyId, spaceId, cookie, cwd = process.cwd()) {
|
|
75
76
|
const normalizedServerUrl = normalizeUmbrellaServerUrl(serverUrl);
|
|
76
77
|
const setup = await getCliSetup(normalizedServerUrl, companyId, spaceId, cookie);
|
|
78
|
+
if (!setup.apiKey || setup.apiKey.trim().length === 0) {
|
|
79
|
+
throw new Error("Umbrella returned a Context setup response without an API key. The live deployment is likely out of date for this CLI.");
|
|
80
|
+
}
|
|
77
81
|
await saveUmbrellaDeviceLink(setup, normalizedServerUrl, cwd);
|
|
78
82
|
return setup;
|
|
79
83
|
}
|
package/dist/commands/bridge.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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
|
});
|
package/dist/commands/catalog.js
CHANGED
|
@@ -178,7 +178,7 @@ export const COMMAND_SPECS = [
|
|
|
178
178
|
{
|
|
179
179
|
key: "bridge",
|
|
180
180
|
usage: "/bridge [summary|json]",
|
|
181
|
-
description: "Show the
|
|
181
|
+
description: "Show the internal runtime bridge snapshot",
|
|
182
182
|
action: async (args) => {
|
|
183
183
|
await bridgeCommandAction(args[0] ?? "summary");
|
|
184
184
|
},
|
package/dist/commands/connect.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { configManager } from "../config.js";
|
|
3
|
-
import { ensureRepoContext } from "../repo-state.js";
|
|
3
|
+
import { ensureRepoContext, findRepoRoot } from "../repo-state.js";
|
|
4
4
|
export function connectCommand(cli) {
|
|
5
5
|
cli
|
|
6
6
|
.command("connect", "Connect this device directly to a company context space without the interactive setup flow")
|
|
@@ -29,6 +29,7 @@ export function connectCommand(cli) {
|
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
try {
|
|
32
|
+
const repoRoot = await findRepoRoot(process.cwd());
|
|
32
33
|
const res = await fetch(`${serverUrl}/api/memories?limit=1`, {
|
|
33
34
|
headers: {
|
|
34
35
|
Authorization: `Bearer ${apiKey}`,
|
|
@@ -51,7 +52,7 @@ export function connectCommand(cli) {
|
|
|
51
52
|
apiKey,
|
|
52
53
|
});
|
|
53
54
|
configManager.upsertLocation({
|
|
54
|
-
repoRoot
|
|
55
|
+
repoRoot,
|
|
55
56
|
companyId,
|
|
56
57
|
companyName,
|
|
57
58
|
projectId: spaceId,
|
|
@@ -130,6 +130,9 @@ async function applyConnectorRunEffects(entry, cwd = process.cwd()) {
|
|
|
130
130
|
const staged = await addPendingMemory({
|
|
131
131
|
content: "Slack growth hook captured a reusable campaign note. Replace this placeholder with the real signal before pushing.",
|
|
132
132
|
tags: ["slack", "growth", "draft"],
|
|
133
|
+
keywords: ["slack", "growth", "campaign"],
|
|
134
|
+
category: "team",
|
|
135
|
+
accessLevel: "space",
|
|
133
136
|
systemType: "connector_capture",
|
|
134
137
|
source: "slack-growth-hook",
|
|
135
138
|
}, cwd);
|
|
@@ -1,6 +1,18 @@
|
|
|
1
|
+
type OutputFormat = "text" | "json";
|
|
2
|
+
type CurateViewStatus = "pending";
|
|
1
3
|
export declare function curateCommandAction(content: string, opts?: {
|
|
4
|
+
format?: OutputFormat;
|
|
2
5
|
tag?: string | string[];
|
|
3
6
|
type?: string;
|
|
4
7
|
}): Promise<void>;
|
|
5
|
-
export declare function curateViewCommandAction(
|
|
8
|
+
export declare function curateViewCommandAction(opts?: {
|
|
9
|
+
before?: string;
|
|
10
|
+
detail?: boolean;
|
|
11
|
+
format?: OutputFormat;
|
|
12
|
+
id?: string;
|
|
13
|
+
limit?: number;
|
|
14
|
+
since?: string;
|
|
15
|
+
status?: CurateViewStatus | CurateViewStatus[];
|
|
16
|
+
}): Promise<void>;
|
|
6
17
|
export declare function curateCommand(cli: any): void;
|
|
18
|
+
export {};
|
package/dist/commands/curate.js
CHANGED
|
@@ -1,14 +1,78 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { configManager } from "../config.js";
|
|
3
3
|
import { addPendingMemory, completeTask, createTask, ensureRepoContext, getPendingMemories, getRepoContext, recordSessionCuration, recordSessionEvent, setSessionPanel, } from "../repo-state.js";
|
|
4
|
+
const RELATIVE_TIME_PATTERN = /^(\d+)(m|h|d|w)$/;
|
|
5
|
+
function printCurateResult(format, payload) {
|
|
6
|
+
if (format === "json") {
|
|
7
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
function parseTimeFilter(value) {
|
|
11
|
+
if (!value?.trim())
|
|
12
|
+
return null;
|
|
13
|
+
const relative = RELATIVE_TIME_PATTERN.exec(value.trim());
|
|
14
|
+
if (relative) {
|
|
15
|
+
const amount = Number(relative[1]);
|
|
16
|
+
const unit = relative[2];
|
|
17
|
+
const multipliers = {
|
|
18
|
+
m: 60_000,
|
|
19
|
+
h: 3_600_000,
|
|
20
|
+
d: 86_400_000,
|
|
21
|
+
w: 604_800_000,
|
|
22
|
+
};
|
|
23
|
+
return Date.now() - amount * multipliers[unit];
|
|
24
|
+
}
|
|
25
|
+
const timestamp = new Date(value).getTime();
|
|
26
|
+
return Number.isNaN(timestamp) ? null : timestamp;
|
|
27
|
+
}
|
|
28
|
+
function normalizeStatuses(status) {
|
|
29
|
+
if (!status)
|
|
30
|
+
return ["pending"];
|
|
31
|
+
return Array.isArray(status) ? status : [status];
|
|
32
|
+
}
|
|
33
|
+
function filterCurations(entries, opts) {
|
|
34
|
+
const after = parseTimeFilter(opts.since);
|
|
35
|
+
const before = parseTimeFilter(opts.before);
|
|
36
|
+
const statuses = normalizeStatuses(opts.status);
|
|
37
|
+
if ((opts.since && after === null) || (opts.before && before === null)) {
|
|
38
|
+
return {
|
|
39
|
+
error: 'Invalid time filter. Use ISO date (2026-04-07 or 2026-04-07T09:30:00Z) or relative time like "1h", "24h", "7d", or "2w".',
|
|
40
|
+
filtered: [],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
let filtered = [...entries]
|
|
44
|
+
.filter(() => statuses.includes("pending"))
|
|
45
|
+
.filter((entry) => {
|
|
46
|
+
const createdAt = new Date(entry.createdAt).getTime();
|
|
47
|
+
if (after !== null && createdAt < after)
|
|
48
|
+
return false;
|
|
49
|
+
if (before !== null && createdAt > before)
|
|
50
|
+
return false;
|
|
51
|
+
return true;
|
|
52
|
+
});
|
|
53
|
+
if (opts.id) {
|
|
54
|
+
filtered = filtered.filter((entry) => entry.id === opts.id);
|
|
55
|
+
}
|
|
56
|
+
const limit = typeof opts.limit === "number" && Number.isFinite(opts.limit) && opts.limit > 0 ? opts.limit : 10;
|
|
57
|
+
return { error: null, filtered: filtered.slice(0, limit) };
|
|
58
|
+
}
|
|
4
59
|
export async function curateCommandAction(content, opts = {}) {
|
|
5
60
|
const config = configManager.config;
|
|
61
|
+
const format = opts.format === "json" ? "json" : "text";
|
|
6
62
|
if (!config) {
|
|
63
|
+
if (format === "json") {
|
|
64
|
+
console.log(JSON.stringify({ ok: false, error: "Not configured. Run: umbrella-context setup" }, null, 2));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
7
67
|
console.log(chalk.red("Not configured. Run: umbrella-context setup"));
|
|
8
68
|
return;
|
|
9
69
|
}
|
|
10
70
|
if (!content?.trim()) {
|
|
11
|
-
|
|
71
|
+
if (format === "json") {
|
|
72
|
+
console.log(JSON.stringify({ ok: false, error: 'Usage: umbrella-context curate "What we learned"' }, null, 2));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
console.log(chalk.red('\n Usage: umbrella-context curate "What we learned"'));
|
|
12
76
|
return;
|
|
13
77
|
}
|
|
14
78
|
await ensureRepoContext(config);
|
|
@@ -21,9 +85,13 @@ export async function curateCommandAction(content, opts = {}) {
|
|
|
21
85
|
panel: "curate",
|
|
22
86
|
focus: content.trim(),
|
|
23
87
|
});
|
|
88
|
+
const tags = opts.tag ? (Array.isArray(opts.tag) ? opts.tag : [opts.tag]) : [];
|
|
24
89
|
const entry = await addPendingMemory({
|
|
25
90
|
content: content.trim(),
|
|
26
|
-
tags
|
|
91
|
+
tags,
|
|
92
|
+
keywords: tags,
|
|
93
|
+
category: null,
|
|
94
|
+
accessLevel: "space",
|
|
27
95
|
source: "cli",
|
|
28
96
|
systemType: opts.type || "system1_knowledge",
|
|
29
97
|
});
|
|
@@ -38,41 +106,109 @@ export async function curateCommandAction(content, opts = {}) {
|
|
|
38
106
|
status: "success",
|
|
39
107
|
});
|
|
40
108
|
await completeTask(task.id, "completed", `Saved local draft ${entry.id} in .um.`);
|
|
109
|
+
printCurateResult(format, {
|
|
110
|
+
ok: true,
|
|
111
|
+
action: "curate",
|
|
112
|
+
companyName: config.companyName,
|
|
113
|
+
spaceName: config.projectName,
|
|
114
|
+
pendingEntryId: entry.id,
|
|
115
|
+
tags: entry.tags,
|
|
116
|
+
type: entry.systemType,
|
|
117
|
+
accessLevel: entry.accessLevel,
|
|
118
|
+
umDir,
|
|
119
|
+
});
|
|
120
|
+
if (format === "json") {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
41
123
|
console.log(chalk.green(`\n Saved locally to ${config.companyName} / ${config.projectName}`));
|
|
42
124
|
console.log(chalk.gray(` Pending entry: ${entry.id}`));
|
|
43
125
|
console.log(chalk.gray(` Repo context folder: ${umDir}`));
|
|
44
126
|
console.log(chalk.gray(' Run "umbrella-context push" when you want to sync this to the server.'));
|
|
45
127
|
}
|
|
46
|
-
export async function curateViewCommandAction() {
|
|
128
|
+
export async function curateViewCommandAction(opts = {}) {
|
|
47
129
|
const config = configManager.config;
|
|
130
|
+
const format = opts.format === "json" ? "json" : "text";
|
|
48
131
|
if (!config) {
|
|
132
|
+
if (format === "json") {
|
|
133
|
+
console.log(JSON.stringify({ ok: false, error: "Not configured. Run: umbrella-context setup" }, null, 2));
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
49
136
|
console.log(chalk.red("Not configured. Run: umbrella-context setup"));
|
|
50
137
|
return;
|
|
51
138
|
}
|
|
52
139
|
await ensureRepoContext(config);
|
|
53
|
-
await setSessionPanel("curate", "view");
|
|
140
|
+
await setSessionPanel("curate", opts.id ?? "view");
|
|
54
141
|
const entries = await getPendingMemories();
|
|
142
|
+
const { error, filtered } = filterCurations(entries, opts);
|
|
143
|
+
if (error) {
|
|
144
|
+
if (format === "json") {
|
|
145
|
+
console.log(JSON.stringify({ ok: false, action: "curate.view", error }, null, 2));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
console.log(chalk.red(error));
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (format === "json") {
|
|
152
|
+
console.log(JSON.stringify({
|
|
153
|
+
ok: true,
|
|
154
|
+
action: "curate.view",
|
|
155
|
+
companyName: config.companyName,
|
|
156
|
+
spaceName: config.projectName,
|
|
157
|
+
total: filtered.length,
|
|
158
|
+
statuses: normalizeStatuses(opts.status),
|
|
159
|
+
detail: Boolean(opts.detail || opts.id),
|
|
160
|
+
entries: filtered,
|
|
161
|
+
}, null, 2));
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
55
164
|
console.log(chalk.bold(`\n Local Curations for ${config.companyName} / ${config.projectName}\n`));
|
|
56
|
-
if (
|
|
57
|
-
console.log(chalk.yellow(" No local curations
|
|
165
|
+
if (filtered.length === 0) {
|
|
166
|
+
console.log(chalk.yellow(" No local curations matched this view."));
|
|
58
167
|
console.log(chalk.gray(' Try: umbrella-context curate "What you learned"'));
|
|
59
168
|
return;
|
|
60
169
|
}
|
|
61
|
-
|
|
170
|
+
filtered.forEach((entry, index) => {
|
|
62
171
|
const tags = entry.tags.length > 0 ? ` [${entry.tags.join(", ")}]` : "";
|
|
63
172
|
console.log(` ${index + 1}. ${entry.content}${tags}`);
|
|
64
|
-
console.log(chalk.gray(` ${entry.systemType} • ${entry.createdAt} • ${entry.id}`));
|
|
173
|
+
console.log(chalk.gray(` pending • ${entry.systemType} • ${entry.createdAt} • ${entry.id}`));
|
|
174
|
+
if (opts.detail || opts.id) {
|
|
175
|
+
const keywords = entry.keywords.length > 0 ? entry.keywords.join(", ") : "none";
|
|
176
|
+
console.log(chalk.gray(` access: ${entry.accessLevel} • category: ${entry.category ?? "uncategorized"} • source: ${entry.source}`));
|
|
177
|
+
console.log(chalk.gray(` keywords: ${keywords}`));
|
|
178
|
+
}
|
|
65
179
|
});
|
|
66
180
|
}
|
|
67
181
|
export function curateCommand(cli) {
|
|
68
182
|
cli
|
|
69
|
-
.command("curate [...content]",
|
|
183
|
+
.command("curate [...content]", `Save context locally in this repo so it can be pushed later
|
|
184
|
+
|
|
185
|
+
Good examples:
|
|
186
|
+
- "Auth uses JWT with 24h expiry in httpOnly cookies via auth middleware"
|
|
187
|
+
- "Rate limit is 100 req/min per user using Redis sliding windows"
|
|
188
|
+
Bad examples:
|
|
189
|
+
- "Authentication"
|
|
190
|
+
- "Rate limiting"`)
|
|
70
191
|
.option("--tag <tag>", "Add tags (repeatable)")
|
|
71
192
|
.option("--type <type>", "system1_knowledge or system2_reasoning")
|
|
193
|
+
.option("--format <format>", "Output format (text or json)")
|
|
194
|
+
.option("--detail", "When used with curate view, show richer entry detail")
|
|
195
|
+
.option("--limit <limit>", "When used with curate view, limit the number of entries returned")
|
|
196
|
+
.option("--since <time>", "When used with curate view, show entries after a time like 1h, 24h, 7d, or an ISO date")
|
|
197
|
+
.option("--before <time>", "When used with curate view, show entries before a time like 1h, 24h, 7d, or an ISO date")
|
|
198
|
+
.option("--status <status>", "When used with curate view, filter by status (currently: pending)")
|
|
199
|
+
.example('curate "JWT auth uses httpOnly cookies"')
|
|
200
|
+
.example('curate "Auth middleware" --tag auth --tag cookies --format json')
|
|
201
|
+
.example("curate view")
|
|
202
|
+
.example("curate view --since 1h --detail")
|
|
203
|
+
.example("curate view 123e4567-e89b-12d3-a456-426614174000 --format json")
|
|
72
204
|
.action(async (content, opts) => {
|
|
73
205
|
const parts = Array.isArray(content) ? content : [content];
|
|
74
206
|
if (parts.length === 1 && parts[0] === "view") {
|
|
75
|
-
await curateViewCommandAction();
|
|
207
|
+
await curateViewCommandAction(opts);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (parts[0] === "view") {
|
|
211
|
+
await curateViewCommandAction({ ...opts, id: parts[1] });
|
|
76
212
|
return;
|
|
77
213
|
}
|
|
78
214
|
await curateCommandAction(parts.join(" "), opts);
|
package/dist/commands/fix.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { configManager } from "../config.js";
|
|
3
|
-
import { addTaskReasoningContent, addTaskToolCall, appendTaskStreamingContent, completeTask, createTask, patchTaskLifecycle, recordSessionEvent, setSessionPanel, } from "../repo-state.js";
|
|
3
|
+
import { addTaskReasoningContent, addTaskToolCall, appendTaskStreamingContent, completeTask, createTask, patchTaskLifecycle, removeTask, recordSessionEvent, setSessionPanel, } from "../repo-state.js";
|
|
4
4
|
export function fixCommand(cli) {
|
|
5
5
|
cli.command("fix <error>", "Search for known fixes to an error").action(async (error) => {
|
|
6
6
|
const config = configManager.config;
|
|
@@ -54,15 +54,7 @@ export function fixCommand(cli) {
|
|
|
54
54
|
});
|
|
55
55
|
await addTaskReasoningContent(task.id, `Server returned ${data.results.length} known fix candidate${data.results.length === 1 ? "" : "s"}.`);
|
|
56
56
|
if (data.results.length === 0) {
|
|
57
|
-
await
|
|
58
|
-
await recordSessionEvent({
|
|
59
|
-
kind: "query",
|
|
60
|
-
title: `No known fixes found for "${error}"`,
|
|
61
|
-
detail: "The shared fixes store did not contain this error signal.",
|
|
62
|
-
panel: "fix",
|
|
63
|
-
focus: error,
|
|
64
|
-
status: "warning",
|
|
65
|
-
});
|
|
57
|
+
await removeTask(task.id);
|
|
66
58
|
console.log(chalk.yellow(`\n No known fixes for "${error}"`));
|
|
67
59
|
return;
|
|
68
60
|
}
|
|
@@ -46,7 +46,7 @@ function printWelcomeHeader(providerLabel, modelLabel) {
|
|
|
46
46
|
console.log(` ${chalk.yellow("/reset")} Reset this repo's local Context state`);
|
|
47
47
|
console.log(` ${chalk.yellow("/")} Full command list`);
|
|
48
48
|
console.log(divider());
|
|
49
|
-
console.log(` ${chalk.gray("Shortcuts:")}
|
|
49
|
+
console.log(` ${chalk.gray("Shortcuts:")} start with ${chalk.yellow("?")} to query, or start with ${chalk.yellow("+")} to curate quickly.`);
|
|
50
50
|
console.log("");
|
|
51
51
|
}
|
|
52
52
|
async function printRuntimeSnapshot() {
|
|
@@ -794,7 +794,7 @@ export async function interactiveCommand(_args) {
|
|
|
794
794
|
await setSessionPanel("home", configManager.config.projectName);
|
|
795
795
|
await printRuntimeSnapshot();
|
|
796
796
|
await printHomeView(configManager.config);
|
|
797
|
-
console.log(chalk.gray(" Type / to see commands. Use
|
|
797
|
+
console.log(chalk.gray(" Type / to see commands. Use ? to query or + to curate.\n"));
|
|
798
798
|
while (true) {
|
|
799
799
|
const currentConfig = configManager.config;
|
|
800
800
|
if (!currentConfig) {
|
|
@@ -837,21 +837,32 @@ export async function interactiveCommand(_args) {
|
|
|
837
837
|
}
|
|
838
838
|
continue;
|
|
839
839
|
}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
840
|
+
if (raw.startsWith("?")) {
|
|
841
|
+
const query = raw.slice(1).trim();
|
|
842
|
+
if (!query) {
|
|
843
|
+
console.log(chalk.yellow("Use ? followed by a real question, for example ? what do we already know about auth timeouts"));
|
|
844
|
+
continue;
|
|
845
|
+
}
|
|
846
|
+
commandHistory.push(`/query ${query}`);
|
|
847
|
+
await recordSessionCommand(`/query ${query}`);
|
|
848
|
+
await recordSessionQuery(query);
|
|
849
|
+
await setSessionSummary(`Queried Context: ${query.length > 48 ? `${query.slice(0, 48)}...` : query}`);
|
|
847
850
|
try {
|
|
848
|
-
await searchCommandAction(
|
|
851
|
+
await searchCommandAction(query);
|
|
849
852
|
}
|
|
850
853
|
catch (err) {
|
|
851
854
|
console.log(chalk.red(`Command failed: ${err.message}`));
|
|
852
855
|
}
|
|
853
856
|
continue;
|
|
854
857
|
}
|
|
858
|
+
const { command, args } = parseInteractiveInput(raw);
|
|
859
|
+
const spec = resolveCommand(command);
|
|
860
|
+
if (!raw.startsWith("/") && !spec) {
|
|
861
|
+
console.log(chalk.yellow("That text was not run automatically."));
|
|
862
|
+
console.log(chalk.gray("Use /query <question> or start with ? to search Context."));
|
|
863
|
+
console.log(chalk.gray("Use /curate <note> or start with + to save something locally."));
|
|
864
|
+
continue;
|
|
865
|
+
}
|
|
855
866
|
if (!spec) {
|
|
856
867
|
console.log(chalk.yellow(`Unknown command: ${raw}. Type / to see available commands.`));
|
|
857
868
|
continue;
|
|
@@ -1,2 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
type OutputFormat = "text" | "json";
|
|
2
|
+
export declare function locationsCommandAction(opts?: {
|
|
3
|
+
format?: OutputFormat;
|
|
4
|
+
detail?: boolean;
|
|
5
|
+
}): Promise<void>;
|
|
2
6
|
export declare function locationsCommand(cli: any): void;
|
|
7
|
+
export {};
|