@lore-co/cli 0.1.19 → 0.1.21
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 +34 -2
- package/dist/cli.d.ts +8 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +87 -7
- package/dist/cli.js.map +1 -1
- package/dist/cursor-mcp.d.ts +5 -0
- package/dist/cursor-mcp.d.ts.map +1 -0
- package/dist/cursor-mcp.js +41 -0
- package/dist/cursor-mcp.js.map +1 -0
- package/dist/devin-client.d.ts.map +1 -1
- package/dist/devin-client.js +6 -3
- package/dist/devin-client.js.map +1 -1
- package/dist/generated-assets.d.ts +4 -4
- package/dist/generated-assets.d.ts.map +1 -1
- package/dist/generated-assets.js +4 -4
- package/dist/generated-assets.js.map +1 -1
- package/dist/guard.d.ts.map +1 -1
- package/dist/guard.js +31 -1
- package/dist/guard.js.map +1 -1
- package/dist/remember.d.ts +3 -0
- package/dist/remember.d.ts.map +1 -0
- package/dist/remember.js +159 -0
- package/dist/remember.js.map +1 -0
- package/dist/runtime.d.ts +7 -3
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +248 -110
- package/dist/runtime.js.map +1 -1
- package/dist/self-host.d.ts +1 -1
- package/dist/self-host.js +2 -2
- package/dist/update.js +3 -3
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -104,6 +104,28 @@ excerpts. `--repo` and
|
|
|
104
104
|
response. Requires a connected workspace (`lore connect`) and a server that
|
|
105
105
|
exposes `POST /v1/ask`.
|
|
106
106
|
|
|
107
|
+
## Save knowledge manually
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
lore remember "Use pnpm for this repository." --repo acme/app --category convention
|
|
111
|
+
lore remember "Payment retries must use exponential backoff." --project billing
|
|
112
|
+
lore remember "The legacy endpoint is deprecated." --agent codex --json
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`remember` saves an explicit learning using your existing `lore connect`
|
|
116
|
+
credentials. Supply the statement as a quoted argument; multiline statements
|
|
117
|
+
are supported inside that argument. Use `--repo`, `--project`, `--path`, or
|
|
118
|
+
`--component` to limit where it applies. With no scope flags, it is available
|
|
119
|
+
workspace-wide; the current repository is not inferred. The connected workspace
|
|
120
|
+
determines the organization.
|
|
121
|
+
|
|
122
|
+
`--category` defaults to `other`; run `lore remember --help` for the supported
|
|
123
|
+
categories. `--agent` identifies the source and defaults to `human`. The command
|
|
124
|
+
prints the saved learning's ID, content, scope, category, and status, and reports
|
|
125
|
+
an existing learning when the server deduplicates it. `--json` returns the full
|
|
126
|
+
`{ memory, inserted }` response for scripts. Use `--` before statement text that
|
|
127
|
+
begins with a dash. Manual saves do not require agent hooks or MCP write tools.
|
|
128
|
+
|
|
107
129
|
## Context Guard
|
|
108
130
|
|
|
109
131
|
```sh
|
|
@@ -131,7 +153,7 @@ content-free `guard_check` audit event.
|
|
|
131
153
|
|
|
132
154
|
```sh
|
|
133
155
|
lore update
|
|
134
|
-
lore update --version v0.1.
|
|
156
|
+
lore update --version v0.1.21
|
|
135
157
|
```
|
|
136
158
|
|
|
137
159
|
`update` resolves the latest release to an exact tag, or uses the exact
|
|
@@ -248,6 +270,16 @@ command has subcommand-specific `--help`, and `up`, `down`, and `status` support
|
|
|
248
270
|
|
|
249
271
|
## Runtime behavior
|
|
250
272
|
|
|
273
|
+
Cursor installs five hooks and a `lore-native` MCP server. Its `sessionStart`
|
|
274
|
+
hook instructs the agent to call `lore_context` before each request and
|
|
275
|
+
`lore_complete` after its response. The bridge retrieves scoped context, captures
|
|
276
|
+
teachings, and stages prior attempts even in CLI print mode. Repository identity
|
|
277
|
+
comes from the native session; MCP input cannot override it. Credentials remain
|
|
278
|
+
in Lore's protected config. Keep the server enabled, reconnect with the updated
|
|
279
|
+
CLI (`lore connect --agent cursor`), and start a new conversation to activate it.
|
|
280
|
+
`lore status` checks all five hooks plus the MCP server. Other MCP entries are
|
|
281
|
+
preserved during connect and disconnect.
|
|
282
|
+
|
|
251
283
|
The Claude/Codex/Cursor/Polytoken command-hook handler:
|
|
252
284
|
|
|
253
285
|
- reads native hook JSON from standard input and normalizes Cursor and
|
|
@@ -384,7 +416,7 @@ same-repository, non-draft pull requests bearing the corresponding
|
|
|
384
416
|
`lore:codex-review` or `lore:devin-review` label.
|
|
385
417
|
|
|
386
418
|
Generated jobs require a published standalone binary release and default to
|
|
387
|
-
`treadiehq/lore-releases` at `v0.1.
|
|
419
|
+
`treadiehq/lore-releases` at `v0.1.21`. Set `LORE_CLI_REPOSITORY` to the publicly
|
|
388
420
|
readable `owner/repository` and `LORE_CLI_VERSION` to an existing release tag
|
|
389
421
|
when using another release source.
|
|
390
422
|
|
package/dist/cli.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ export interface LorePaths {
|
|
|
27
27
|
copilotVscodeHooks: string;
|
|
28
28
|
claudeSettings: string;
|
|
29
29
|
cursorHooks: string;
|
|
30
|
+
cursorMcp: string;
|
|
30
31
|
cursorUserData: string;
|
|
31
32
|
openCodeConfig: string;
|
|
32
33
|
polytokenHooks: string;
|
|
@@ -43,10 +44,12 @@ export interface ConnectorConfig {
|
|
|
43
44
|
connectedAt: string;
|
|
44
45
|
timeoutMs: number;
|
|
45
46
|
}
|
|
46
|
-
export declare function getLorePaths(home?: string, environment?: NodeJS.ProcessEnv): LorePaths;
|
|
47
|
+
export declare function getLorePaths(home?: string, environment?: NodeJS.ProcessEnv, cwd?: string): LorePaths;
|
|
47
48
|
export declare function mergeLoreHooks(input: Record<string, unknown>, agent: CommandHookAgentName, paths: LorePaths): Record<string, unknown>;
|
|
48
49
|
export declare function removeLoreHooks(input: Record<string, unknown>): Record<string, unknown>;
|
|
49
50
|
export declare function countLoreHooks(input: Record<string, unknown>): number;
|
|
51
|
+
export declare function mergeLoreCursorMcp(input: unknown, paths: LorePaths): Record<string, unknown>;
|
|
52
|
+
export declare function removeLoreCursorMcp(input: unknown): Record<string, unknown>;
|
|
50
53
|
export declare function mergeLoreCursorHooks(input: Record<string, unknown>, paths: LorePaths): Record<string, unknown>;
|
|
51
54
|
export declare function removeLoreCursorHooks(input: Record<string, unknown>): Record<string, unknown>;
|
|
52
55
|
export declare function countLoreCursorHooks(input: Record<string, unknown>): number;
|
|
@@ -75,6 +78,10 @@ export interface AgentInstallation {
|
|
|
75
78
|
}
|
|
76
79
|
export declare function t3CodeProviderInstallations(settings: unknown, paths: LorePaths): AgentInstallation[];
|
|
77
80
|
export interface ConnectWithCredentialOptions {
|
|
81
|
+
/** Explicit installation root for embedded callers and isolated acceptance tests. */
|
|
82
|
+
home?: string;
|
|
83
|
+
/** Repository root for project-local integrations such as VS Code. */
|
|
84
|
+
cwd?: string;
|
|
78
85
|
apiUrl: string;
|
|
79
86
|
dashboardUrl?: string;
|
|
80
87
|
token: string;
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAsBA,OAAO,EAwBL,KAAK,yBAAyB,EAC/B,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,KAAK,oBAAoB,EAE1B,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -11,6 +11,7 @@ import { CLAUDE_RELIABILITY_INTEGRATION, CODEX_RELIABILITY_INTEGRATION, COPILOT_
|
|
|
11
11
|
import { runHook, } from "./runtime.js";
|
|
12
12
|
import { readInvocationHealthWriteInput, runInvocationHealthWrite, } from "./invocation-health-writer.js";
|
|
13
13
|
import { runAskCommand } from "./ask.js";
|
|
14
|
+
import { runRememberCommand } from "./remember.js";
|
|
14
15
|
import { runGuardCommand } from "./guard.js";
|
|
15
16
|
import { runContinueCommand, runResumeCommand } from "./handoff.js";
|
|
16
17
|
import { runAttachCommand, runLiveHostCommand, runLiveRunCommand, } from "./live.js";
|
|
@@ -35,8 +36,9 @@ const HOOK_EVENTS = [
|
|
|
35
36
|
"SessionEnd",
|
|
36
37
|
];
|
|
37
38
|
/** Tools the Context Guard PreToolUse hook cares about (regex matcher). */
|
|
38
|
-
const GUARD_TOOL_MATCHER = "Edit|Write|MultiEdit|NotebookEdit|ApplyPatch|apply_patch|Bash";
|
|
39
|
+
const GUARD_TOOL_MATCHER = "Edit|Write|MultiEdit|NotebookEdit|ApplyPatch|apply_patch|edit|write|patch|str_replace_editor|Bash|bash|Shell|shell|exec_command|shell_command|run_terminal_cmd";
|
|
39
40
|
const CURSOR_HOOK_EVENTS = [
|
|
41
|
+
"sessionStart",
|
|
40
42
|
"beforeSubmitPrompt",
|
|
41
43
|
"beforeShellExecution",
|
|
42
44
|
"afterAgentResponse",
|
|
@@ -45,6 +47,7 @@ const CURSOR_HOOK_EVENTS = [
|
|
|
45
47
|
const POLYTOKEN_HOOK_EVENTS = [
|
|
46
48
|
"pre_user_prompt",
|
|
47
49
|
"post_model_turn",
|
|
50
|
+
"pre_tool_use",
|
|
48
51
|
];
|
|
49
52
|
const COPILOT_CLI_HOOK_EVENTS = [
|
|
50
53
|
"userPromptTransformed",
|
|
@@ -79,6 +82,7 @@ Usage:
|
|
|
79
82
|
Commands:
|
|
80
83
|
connect Configure Lore and install native agent integrations
|
|
81
84
|
ask Query shared knowledge and prior session context
|
|
85
|
+
remember Save a durable fact, convention, correction, or decision
|
|
82
86
|
guard Control Context Guard (off, assist, enforce)
|
|
83
87
|
resume Continue previous work with saved Lore context
|
|
84
88
|
continue Hand the current work to a different agent (--on <agent>)
|
|
@@ -98,6 +102,7 @@ Commands:
|
|
|
98
102
|
Discover:
|
|
99
103
|
lore connect --help
|
|
100
104
|
lore ask --help
|
|
105
|
+
lore remember --help
|
|
101
106
|
lore guard --help
|
|
102
107
|
lore resume --help
|
|
103
108
|
lore continue --help
|
|
@@ -111,6 +116,7 @@ Discover:
|
|
|
111
116
|
Examples:
|
|
112
117
|
lore connect --token "$LORE_WORKSPACE_TOKEN"
|
|
113
118
|
lore ask "How should payment retries work?"
|
|
119
|
+
lore remember "Use pnpm for this repository." --repo acme/app
|
|
114
120
|
lore resume
|
|
115
121
|
lore continue --on codex
|
|
116
122
|
lore connect github --repo owner/repository
|
|
@@ -183,7 +189,7 @@ function isObject(value) {
|
|
|
183
189
|
function cloneObject(value) {
|
|
184
190
|
return structuredClone(value);
|
|
185
191
|
}
|
|
186
|
-
export function getLorePaths(home, environment = process.env) {
|
|
192
|
+
export function getLorePaths(home, environment = process.env, cwd = process.cwd()) {
|
|
187
193
|
const resolvedHome = resolve(home ?? environment.HOME ?? homedir());
|
|
188
194
|
const loreDirectory = resolve(resolvedHome, ".lore");
|
|
189
195
|
const xdgConfigHome = environment.XDG_CONFIG_HOME?.trim() === undefined ||
|
|
@@ -210,9 +216,10 @@ export function getLorePaths(home, environment = process.env) {
|
|
|
210
216
|
codexHooks: resolve(resolvedHome, ".codex", "hooks.json"),
|
|
211
217
|
copilotCliHooks: resolve(copilotHome, "hooks", "lore.json"),
|
|
212
218
|
copilotVscodeHooks: resolve(environment.LORE_COPILOT_VSCODE_HOOKS?.trim() ||
|
|
213
|
-
resolve(
|
|
219
|
+
resolve(cwd, ".github", "hooks", "lore-vscode.json")),
|
|
214
220
|
claudeSettings: resolve(resolvedHome, ".claude", "settings.json"),
|
|
215
221
|
cursorHooks: resolve(resolvedHome, ".cursor", "hooks.json"),
|
|
222
|
+
cursorMcp: resolve(resolvedHome, ".cursor", "mcp.json"),
|
|
216
223
|
cursorUserData: platform() === "darwin"
|
|
217
224
|
? resolve(resolvedHome, "Library", "Application Support", "Cursor")
|
|
218
225
|
: resolve(resolvedHome, ".config", "Cursor"),
|
|
@@ -365,6 +372,35 @@ function cursorEventHandler(event, paths) {
|
|
|
365
372
|
: 25,
|
|
366
373
|
};
|
|
367
374
|
}
|
|
375
|
+
const CURSOR_MCP_NAME = "lore-native";
|
|
376
|
+
function cursorMcpServer(paths) {
|
|
377
|
+
return {
|
|
378
|
+
type: "stdio", command: process.execPath,
|
|
379
|
+
args: [...(IS_STANDALONE_BINARY ? [] : [fileURLToPath(import.meta.url)]), "cursor-mcp", "--owner", "lore"],
|
|
380
|
+
env: { LORE_HOME: paths.home },
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
function isLoreCursorMcp(value) {
|
|
384
|
+
return isObject(value) && Array.isArray(value.args) && value.args.includes("cursor-mcp")
|
|
385
|
+
&& value.args.includes("--owner") && value.args.includes("lore");
|
|
386
|
+
}
|
|
387
|
+
export function mergeLoreCursorMcp(input, paths) {
|
|
388
|
+
const config = objectConfiguration(input, "cursor");
|
|
389
|
+
if (config.mcpServers !== undefined && !isObject(config.mcpServers))
|
|
390
|
+
throw new Error("Cursor mcpServers must be an object");
|
|
391
|
+
const servers = isObject(config.mcpServers) ? config.mcpServers : {};
|
|
392
|
+
if (servers[CURSOR_MCP_NAME] !== undefined && !isLoreCursorMcp(servers[CURSOR_MCP_NAME])) {
|
|
393
|
+
throw new Error('Cursor MCP name "lore-native" is already owned by another server; rename it before connecting.');
|
|
394
|
+
}
|
|
395
|
+
return { ...config, mcpServers: { ...servers, [CURSOR_MCP_NAME]: cursorMcpServer(paths) } };
|
|
396
|
+
}
|
|
397
|
+
export function removeLoreCursorMcp(input) {
|
|
398
|
+
const config = objectConfiguration(input, "cursor");
|
|
399
|
+
if (!isObject(config.mcpServers) || !isLoreCursorMcp(config.mcpServers[CURSOR_MCP_NAME]))
|
|
400
|
+
return config;
|
|
401
|
+
const { [CURSOR_MCP_NAME]: _lore, ...rest } = config.mcpServers;
|
|
402
|
+
return { ...config, mcpServers: rest };
|
|
403
|
+
}
|
|
368
404
|
function stripLoreFromCursorEvent(value) {
|
|
369
405
|
return Array.isArray(value) ? value.filter((hook) => !isLoreHook(hook)) : [];
|
|
370
406
|
}
|
|
@@ -1156,7 +1192,7 @@ const AGENT_TARGETS = {
|
|
|
1156
1192
|
},
|
|
1157
1193
|
cursor: {
|
|
1158
1194
|
integration: "hooks",
|
|
1159
|
-
expected: CURSOR_HOOK_EVENTS.length,
|
|
1195
|
+
expected: CURSOR_HOOK_EVENTS.length + 1,
|
|
1160
1196
|
runtimeRequired: true,
|
|
1161
1197
|
emptyValue: () => ({}),
|
|
1162
1198
|
configPath: (paths) => paths.cursorHooks,
|
|
@@ -1398,6 +1434,7 @@ async function installRuntime(paths) {
|
|
|
1398
1434
|
rm(paths.runtimeReliabilityStore, { force: true }),
|
|
1399
1435
|
rm(paths.runtimeSignedSnapshot, { force: true }),
|
|
1400
1436
|
rm(paths.runtimeCanonicalJson, { force: true }),
|
|
1437
|
+
rm(resolve(dirname(paths.runtime), "guard-evaluation.js"), { force: true }),
|
|
1401
1438
|
rm(paths.runtimeContextFallback, { force: true }),
|
|
1402
1439
|
rm(paths.runtimeInvocationHealthWriter, { force: true }),
|
|
1403
1440
|
rm(paths.runtimeVersion, { force: true }),
|
|
@@ -1407,6 +1444,7 @@ async function installRuntime(paths) {
|
|
|
1407
1444
|
}
|
|
1408
1445
|
const sourceDirectory = dirname(fileURLToPath(import.meta.url));
|
|
1409
1446
|
const canonicalJsonModule = fileURLToPath(import.meta.resolve("@lore-co/core/canonical-json"));
|
|
1447
|
+
const guardEvaluation = await readFile(fileURLToPath(import.meta.resolve("@lore-co/core/guard-evaluation")), "utf8");
|
|
1410
1448
|
const [runtime, repository, reliabilityStore, signedSnapshot, canonicalJson, contextFallback, invocationHealthWriter,] = await Promise.all([
|
|
1411
1449
|
readFile(resolve(sourceDirectory, "runtime.js"), "utf8"),
|
|
1412
1450
|
readFile(resolve(sourceDirectory, "repository.js"), "utf8"),
|
|
@@ -1422,7 +1460,8 @@ async function installRuntime(paths) {
|
|
|
1422
1460
|
}
|
|
1423
1461
|
const runtimeVersion = `export const RUNTIME_VERSION = ${JSON.stringify(LORE_VERSION)};\n`;
|
|
1424
1462
|
const runtimeFiles = {
|
|
1425
|
-
"lore-hook.mjs": runtime,
|
|
1463
|
+
"lore-hook.mjs": runtime.replaceAll("@lore-co/core/guard-evaluation", "./guard-evaluation.js"),
|
|
1464
|
+
"guard-evaluation.js": guardEvaluation,
|
|
1426
1465
|
"repository.js": repository,
|
|
1427
1466
|
"reliability-store.js": reliabilityStore,
|
|
1428
1467
|
"signed-snapshot.js": standaloneSignedSnapshot,
|
|
@@ -1442,6 +1481,7 @@ async function installRuntime(paths) {
|
|
|
1442
1481
|
},
|
|
1443
1482
|
};
|
|
1444
1483
|
await Promise.all([
|
|
1484
|
+
atomicWrite(resolve(dirname(paths.runtime), "guard-evaluation.js"), guardEvaluation, 0o600),
|
|
1445
1485
|
atomicWrite(paths.runtimeRepository, repository, 0o600),
|
|
1446
1486
|
atomicWrite(paths.runtimeReliabilityStore, reliabilityStore, 0o600),
|
|
1447
1487
|
atomicWrite(paths.runtimeSignedSnapshot, standaloneSignedSnapshot, 0o600),
|
|
@@ -1453,7 +1493,7 @@ async function installRuntime(paths) {
|
|
|
1453
1493
|
]);
|
|
1454
1494
|
// The hook entrypoint is the generation activation marker. Updating it last
|
|
1455
1495
|
// prevents a new runtime from loading before all of its local modules exist.
|
|
1456
|
-
await atomicWrite(paths.runtime,
|
|
1496
|
+
await atomicWrite(paths.runtime, runtimeFiles["lore-hook.mjs"], 0o700);
|
|
1457
1497
|
}
|
|
1458
1498
|
function agentConfigPath(agent, paths) {
|
|
1459
1499
|
return targetFor(agent).configPath(paths);
|
|
@@ -1572,7 +1612,7 @@ export async function connectWithCredential(options) {
|
|
|
1572
1612
|
if (platform() !== "darwin" && platform() !== "linux") {
|
|
1573
1613
|
throw new Error("Lore agent integrations currently support macOS and Linux");
|
|
1574
1614
|
}
|
|
1575
|
-
const paths = getLorePaths();
|
|
1615
|
+
const paths = getLorePaths(options.home, options.home === undefined ? process.env : {}, options.cwd);
|
|
1576
1616
|
const existing = await readConnectorConfig(paths);
|
|
1577
1617
|
const apiUrl = normalizeApiUrl(options.apiUrl);
|
|
1578
1618
|
const dashboardUrl = options.dashboardUrl === undefined
|
|
@@ -1603,17 +1643,30 @@ export async function connectWithCredential(options) {
|
|
|
1603
1643
|
const now = new Date();
|
|
1604
1644
|
const documents = new Map();
|
|
1605
1645
|
const mergedDocuments = new Map();
|
|
1646
|
+
const cursorMcpDocuments = new Map();
|
|
1606
1647
|
for (const installation of installations) {
|
|
1607
1648
|
const key = installationKey(installation);
|
|
1608
1649
|
const document = await readJsonDocument(installation.configPath);
|
|
1609
1650
|
documents.set(key, document);
|
|
1610
1651
|
mergedDocuments.set(key, mergeAgentConfig(document.value, installation.agent, paths));
|
|
1652
|
+
if (installation.agent === "cursor") {
|
|
1653
|
+
const mcpPath = resolve(dirname(installation.configPath), "mcp.json");
|
|
1654
|
+
const mcp = await readJsonDocument(mcpPath);
|
|
1655
|
+
cursorMcpDocuments.set(mcpPath, { document: mcp, merged: mergeLoreCursorMcp(mcp.exists ? mcp.value : {}, paths) });
|
|
1656
|
+
}
|
|
1611
1657
|
}
|
|
1612
1658
|
if (installations.some((installation) => targetFor(installation.agent).runtimeRequired)) {
|
|
1613
1659
|
await installRuntime(paths);
|
|
1614
1660
|
}
|
|
1615
1661
|
const changedHookFiles = [];
|
|
1616
1662
|
const backups = [];
|
|
1663
|
+
for (const [path, { document, merged }] of cursorMcpDocuments) {
|
|
1664
|
+
const result = await writeMergedJson(path, document, merged, now);
|
|
1665
|
+
if (result.changed)
|
|
1666
|
+
changedHookFiles.push(path);
|
|
1667
|
+
if (result.backup)
|
|
1668
|
+
backups.push(result.backup);
|
|
1669
|
+
}
|
|
1617
1670
|
for (const installation of installations) {
|
|
1618
1671
|
const key = installationKey(installation);
|
|
1619
1672
|
const document = documents.get(key);
|
|
@@ -1890,6 +1943,7 @@ async function inspectRuntimeInstallation(required, paths) {
|
|
|
1890
1943
|
}
|
|
1891
1944
|
const runtimeFiles = {
|
|
1892
1945
|
"lore-hook.mjs": paths.runtime,
|
|
1946
|
+
"guard-evaluation.js": resolve(dirname(paths.runtime), "guard-evaluation.js"),
|
|
1893
1947
|
"repository.js": paths.runtimeRepository,
|
|
1894
1948
|
"reliability-store.js": paths.runtimeReliabilityStore,
|
|
1895
1949
|
"signed-snapshot.js": paths.runtimeSignedSnapshot,
|
|
@@ -2003,6 +2057,14 @@ async function getAgentStatus(agent, config, paths, runtime) {
|
|
|
2003
2057
|
units.push(...inspectInstallationUnits(document.value === undefined
|
|
2004
2058
|
? target.emptyValue()
|
|
2005
2059
|
: document.value, agent, paths, index, configPaths.length));
|
|
2060
|
+
if (agent === "cursor") {
|
|
2061
|
+
const mcp = await readJsonDocument(resolve(dirname(path), "mcp.json"));
|
|
2062
|
+
const value = isObject(mcp.value) && isObject(mcp.value.mcpServers) ? mcp.value.mcpServers[CURSOR_MCP_NAME] : undefined;
|
|
2063
|
+
const owned = Number(isLoreCursorMcp(value));
|
|
2064
|
+
installed += owned;
|
|
2065
|
+
units.push({ id: installationUnitId("mcp", index, configPaths.length),
|
|
2066
|
+
state: installationUnitState(owned, Number(exactConfiguration(value, cursorMcpServer(paths)))) });
|
|
2067
|
+
}
|
|
2006
2068
|
}
|
|
2007
2069
|
catch {
|
|
2008
2070
|
invalidConfiguration = true;
|
|
@@ -2129,6 +2191,17 @@ async function disconnectCommand(args) {
|
|
|
2129
2191
|
]);
|
|
2130
2192
|
for (const installation of installations) {
|
|
2131
2193
|
const path = installation.configPath;
|
|
2194
|
+
if (installation.agent === "cursor") {
|
|
2195
|
+
const mcpPath = resolve(dirname(path), "mcp.json");
|
|
2196
|
+
const mcp = await readJsonDocument(mcpPath);
|
|
2197
|
+
if (mcp.exists) {
|
|
2198
|
+
const result = await writeMergedJson(mcpPath, mcp, removeLoreCursorMcp(mcp.value), now);
|
|
2199
|
+
if (result.changed)
|
|
2200
|
+
changedHookFiles.push(mcpPath);
|
|
2201
|
+
if (result.backup)
|
|
2202
|
+
backups.push(result.backup);
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2132
2205
|
const document = await readJsonDocument(path);
|
|
2133
2206
|
if (!document.exists) {
|
|
2134
2207
|
continue;
|
|
@@ -2149,6 +2222,7 @@ async function disconnectCommand(args) {
|
|
|
2149
2222
|
rm(paths.runtimeSignedSnapshot, { force: true }),
|
|
2150
2223
|
rm(paths.runtimeCanonicalJson, { force: true }),
|
|
2151
2224
|
rm(paths.runtimeContextFallback, { force: true }),
|
|
2225
|
+
rm(resolve(dirname(paths.runtime), "guard-evaluation.js"), { force: true }),
|
|
2152
2226
|
rm(paths.runtimeInvocationHealthWriter, { force: true }),
|
|
2153
2227
|
rm(paths.runtimeVersion, { force: true }),
|
|
2154
2228
|
rm(paths.runtimePackage, { force: true }),
|
|
@@ -2431,6 +2505,9 @@ export async function runCli(args = process.argv.slice(2)) {
|
|
|
2431
2505
|
case "ask":
|
|
2432
2506
|
await runAskCommand(commandArgs, await readConnectorConfig(getLorePaths()));
|
|
2433
2507
|
return;
|
|
2508
|
+
case "remember":
|
|
2509
|
+
await runRememberCommand(commandArgs, await readConnectorConfig(getLorePaths()));
|
|
2510
|
+
return;
|
|
2434
2511
|
case "guard":
|
|
2435
2512
|
await runGuardCommand(commandArgs, await readConnectorConfig(getLorePaths()));
|
|
2436
2513
|
return;
|
|
@@ -2494,6 +2571,9 @@ export async function runCli(args = process.argv.slice(2)) {
|
|
|
2494
2571
|
case "hook":
|
|
2495
2572
|
await runHook(commandArgs);
|
|
2496
2573
|
return;
|
|
2574
|
+
case "cursor-mcp":
|
|
2575
|
+
await (await import("./cursor-mcp.js")).runCursorMcpServer();
|
|
2576
|
+
return;
|
|
2497
2577
|
case "internal-health-write": {
|
|
2498
2578
|
const encoded = commandArgs[0] ?? (await readInvocationHealthWriteInput());
|
|
2499
2579
|
await runInvocationHealthWrite(encoded);
|