@engram-cli/engram 0.1.0
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 +103 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +78 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +39 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +69 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +41 -0
- package/dist/config.js.map +1 -0
- package/dist/emit.d.ts +18 -0
- package/dist/emit.d.ts.map +1 -0
- package/dist/emit.js +42 -0
- package/dist/emit.js.map +1 -0
- package/dist/init.d.ts +2 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +99 -0
- package/dist/init.js.map +1 -0
- package/dist/mcp.d.ts +2 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +75 -0
- package/dist/mcp.js.map +1 -0
- package/dist/project.d.ts +2 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.js +13 -0
- package/dist/project.js.map +1 -0
- package/dist/start.d.ts +2 -0
- package/dist/start.d.ts.map +1 -0
- package/dist/start.js +219 -0
- package/dist/start.js.map +1 -0
- package/dist/status.d.ts +2 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +20 -0
- package/dist/status.js.map +1 -0
- package/package.json +47 -0
- package/templates/engram-terminal.bash +40 -0
- package/templates/engram-terminal.zsh +30 -0
- package/templates/post-checkout +23 -0
- package/templates/post-commit +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Engram CLI
|
|
2
|
+
|
|
3
|
+
`npx @engram-cli/engram` — start, status, init, and MCP entry for the Engram local-first developer context hub.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
| Command | Purpose |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `engram start` | Start **Supermemory Local** (`:6767`) and the **Engram backend** (`:7731`) in the foreground. One terminal, prefixed logs, Ctrl+C stops both. |
|
|
10
|
+
| `engram status` | Check whether the Engram backend is reachable. |
|
|
11
|
+
| `engram mcp` | Run the stdio MCP server for Cursor / Claude Code / other MCP clients. |
|
|
12
|
+
| `engram init` | Install per-repo git hooks (`post-checkout`, `post-commit`) and append the terminal capture hook to `~/.zshrc` and `~/.bashrc`. Idempotent. |
|
|
13
|
+
| `engram emit` | Internal command used by hooks to send events to the backend. |
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
From the monorepo:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
cd cli && npm install && npm run build
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
For global use once published:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx @engram-cli/engram init
|
|
27
|
+
npx @engram-cli/engram start
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Environment variables
|
|
31
|
+
|
|
32
|
+
| Variable | Default | Purpose |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| `ENGRAM_BACKEND_URL` | `http://localhost:7731` | Engram backend base URL |
|
|
35
|
+
| `SUPERMEMORY_BASE_URL` | `http://localhost:6767` | Supermemory Local base URL |
|
|
36
|
+
| `SUPERMEMORY_API_KEY` | from repo `.env` | Required by the backend; the CLI prints a warning if `~/.supermemory/api-key` differs from `.env` |
|
|
37
|
+
| `ENGRAM_PROJECT` | auto from git root | Project slug override for MCP and hooks |
|
|
38
|
+
| `ENGRAM_SESSION_ID` | auto-generated | Session identifier for events |
|
|
39
|
+
|
|
40
|
+
## MCP setup (Cursor)
|
|
41
|
+
|
|
42
|
+
Add to `~/.cursor/mcp.json` (or Cursor Settings → MCP):
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"mcpServers": {
|
|
47
|
+
"engram": {
|
|
48
|
+
"command": "npx",
|
|
49
|
+
"args": ["-y", "@engram-cli/engram", "mcp"],
|
|
50
|
+
"env": { "ENGRAM_BACKEND_URL": "http://localhost:7731" }
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Available tools:
|
|
57
|
+
|
|
58
|
+
- `engram_load_capsule` — load the saved project capsule
|
|
59
|
+
- `engram_context` — assemble live Context from Supermemory
|
|
60
|
+
- `engram_search` — search project memories with a natural-language query
|
|
61
|
+
|
|
62
|
+
## Development
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
cd cli
|
|
66
|
+
npm run dev # tsx src/cli.ts start
|
|
67
|
+
npm run build
|
|
68
|
+
npm run typecheck
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Smoke test (starts and stops real services):
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
bash scripts/smoke.sh
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Publish (npm org `engram-cli`)
|
|
78
|
+
|
|
79
|
+
Log in as an org owner (`npm login` as `shubh1305`). Publish **contracts**, then the CLI:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# 1) Contracts
|
|
83
|
+
cd packages/contracts
|
|
84
|
+
npm run build
|
|
85
|
+
npm publish --access public
|
|
86
|
+
|
|
87
|
+
# 2) CLI — switch the local file: dep to the registry version, then publish
|
|
88
|
+
cd ../../cli
|
|
89
|
+
# in package.json: "@engram-cli/contracts": "^0.1.0"
|
|
90
|
+
npm install
|
|
91
|
+
npm run build
|
|
92
|
+
npm publish --access public
|
|
93
|
+
# restore "file:../packages/contracts" for monorepo work after publishing
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
After publish:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
npx @engram-cli/engram start
|
|
100
|
+
npx @engram-cli/engram init
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Note: `engram start` looks for monorepo `backend/` via path walk. From a published install outside this repo, start the backend from a clone (or keep using the monorepo) until a standalone start path ships.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { startCommand } from "./start.js";
|
|
4
|
+
import { statusCommand } from "./status.js";
|
|
5
|
+
import { runMcp } from "./mcp.js";
|
|
6
|
+
import { initCommand } from "./init.js";
|
|
7
|
+
import { emitCommand } from "./emit.js";
|
|
8
|
+
import { readFileSync } from "node:fs";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
function getVersion() {
|
|
13
|
+
try {
|
|
14
|
+
const pkg = JSON.parse(readFileSync(path.join(__dirname, "..", "package.json"), "utf8"));
|
|
15
|
+
return pkg.version ?? "0.0.0";
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return "0.0.0";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const program = new Command("engram")
|
|
22
|
+
.version(getVersion())
|
|
23
|
+
.description("Engram CLI + MCP — local-first developer context hub");
|
|
24
|
+
program
|
|
25
|
+
.command("start")
|
|
26
|
+
.description("Start Supermemory Local and the Engram backend in the foreground")
|
|
27
|
+
.action(async () => {
|
|
28
|
+
await startCommand();
|
|
29
|
+
});
|
|
30
|
+
program
|
|
31
|
+
.command("status")
|
|
32
|
+
.description("Check whether the Engram backend is reachable")
|
|
33
|
+
.action(async () => {
|
|
34
|
+
await statusCommand();
|
|
35
|
+
});
|
|
36
|
+
program
|
|
37
|
+
.command("mcp")
|
|
38
|
+
.description("Run the stdio MCP server for Cursor / Claude Code")
|
|
39
|
+
.action(async () => {
|
|
40
|
+
await runMcp();
|
|
41
|
+
});
|
|
42
|
+
program
|
|
43
|
+
.command("init")
|
|
44
|
+
.description("Install git hooks and terminal hook into the current repo")
|
|
45
|
+
.action(async () => {
|
|
46
|
+
await initCommand();
|
|
47
|
+
});
|
|
48
|
+
program
|
|
49
|
+
.command("emit")
|
|
50
|
+
.description("Emit an event to the Engram backend (used by hooks)")
|
|
51
|
+
.requiredOption("--source <source>", "event source: terminal | git")
|
|
52
|
+
.requiredOption("--type <type>", "event type: command | branch_switch | commit")
|
|
53
|
+
.requiredOption("--content <content>", "event content")
|
|
54
|
+
.option("--cwd <cwd>", "working directory")
|
|
55
|
+
.option("--exit-code <n>", "exit code for command events", parseInt)
|
|
56
|
+
.option("--session-id <id>", "session id")
|
|
57
|
+
.option("--project <project>", "project slug override")
|
|
58
|
+
.option("--dry-run", "print event JSON instead of sending")
|
|
59
|
+
.action(async (opts) => {
|
|
60
|
+
const result = await emitCommand({
|
|
61
|
+
source: opts.source,
|
|
62
|
+
eventType: opts.type,
|
|
63
|
+
content: opts.content,
|
|
64
|
+
cwd: opts.cwd,
|
|
65
|
+
exitCode: opts.exitCode,
|
|
66
|
+
sessionId: opts.sessionId,
|
|
67
|
+
project: opts.project,
|
|
68
|
+
dryRun: opts.dryRun,
|
|
69
|
+
});
|
|
70
|
+
if (!result.sent) {
|
|
71
|
+
process.exitCode = 0;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
program.parseAsync(process.argv).catch((err) => {
|
|
75
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
76
|
+
process.exit(1);
|
|
77
|
+
});
|
|
78
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type MemoryEvent } from "@engram-cli/contracts";
|
|
2
|
+
export interface HealthResponse {
|
|
3
|
+
ok: boolean;
|
|
4
|
+
supermemory?: boolean;
|
|
5
|
+
supabase?: boolean | null;
|
|
6
|
+
}
|
|
7
|
+
export interface EventResponse {
|
|
8
|
+
accepted: boolean;
|
|
9
|
+
dropped?: boolean;
|
|
10
|
+
id?: string;
|
|
11
|
+
reason?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface SearchResult {
|
|
14
|
+
id?: string;
|
|
15
|
+
chunk?: string;
|
|
16
|
+
memory?: string;
|
|
17
|
+
similarity?: number;
|
|
18
|
+
metadata?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface SearchResponse {
|
|
21
|
+
project: string;
|
|
22
|
+
containerTag: string;
|
|
23
|
+
total: number;
|
|
24
|
+
results: SearchResult[];
|
|
25
|
+
}
|
|
26
|
+
export declare class EngramClient {
|
|
27
|
+
private baseUrl;
|
|
28
|
+
constructor(baseUrl: string);
|
|
29
|
+
private url;
|
|
30
|
+
private request;
|
|
31
|
+
health(): Promise<HealthResponse>;
|
|
32
|
+
postEvent(event: MemoryEvent): Promise<EventResponse>;
|
|
33
|
+
getContext(project: string, ide?: string): Promise<unknown>;
|
|
34
|
+
loadCapsule(project: string): Promise<unknown>;
|
|
35
|
+
search(project: string, q: string, limit?: number): Promise<SearchResponse>;
|
|
36
|
+
/** Fire-and-forget event ingest. Never throws. */
|
|
37
|
+
postEventSilent(event: MemoryEvent): void;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,qBAAa,YAAY;IACX,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,MAAM;IAEnC,OAAO,CAAC,GAAG;YAIG,OAAO;IA2Bf,MAAM,IAAI,OAAO,CAAC,cAAc,CAAC;IAIjC,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC;IAOrD,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAM3D,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAO9C,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,cAAc,CAAC;IAO7E,kDAAkD;IAClD,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;CAK1C"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export class EngramClient {
|
|
2
|
+
baseUrl;
|
|
3
|
+
constructor(baseUrl) {
|
|
4
|
+
this.baseUrl = baseUrl;
|
|
5
|
+
}
|
|
6
|
+
url(path) {
|
|
7
|
+
return `${this.baseUrl.replace(/\/$/, "")}${path}`;
|
|
8
|
+
}
|
|
9
|
+
async request(path, init) {
|
|
10
|
+
const res = await fetch(this.url(path), {
|
|
11
|
+
...init,
|
|
12
|
+
headers: {
|
|
13
|
+
"content-type": "application/json",
|
|
14
|
+
...(init?.headers ?? {}),
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
const text = await res.text();
|
|
18
|
+
let body = undefined;
|
|
19
|
+
if (text) {
|
|
20
|
+
try {
|
|
21
|
+
body = JSON.parse(text);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
body = text;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (!res.ok) {
|
|
28
|
+
const msg = typeof body === "object" && body && "message" in body
|
|
29
|
+
? String(body.message)
|
|
30
|
+
: text || res.statusText;
|
|
31
|
+
throw new Error(`${res.status} ${path}: ${msg}`);
|
|
32
|
+
}
|
|
33
|
+
return body;
|
|
34
|
+
}
|
|
35
|
+
async health() {
|
|
36
|
+
return this.request("/health");
|
|
37
|
+
}
|
|
38
|
+
async postEvent(event) {
|
|
39
|
+
return this.request("/event", {
|
|
40
|
+
method: "POST",
|
|
41
|
+
body: JSON.stringify(event),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async getContext(project, ide) {
|
|
45
|
+
const q = new URLSearchParams({ project });
|
|
46
|
+
if (ide)
|
|
47
|
+
q.set("ide", ide);
|
|
48
|
+
return this.request(`/context?${q}`);
|
|
49
|
+
}
|
|
50
|
+
async loadCapsule(project) {
|
|
51
|
+
return this.request("/capsule/load", {
|
|
52
|
+
method: "POST",
|
|
53
|
+
body: JSON.stringify({ project }),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
async search(project, q, limit = 10) {
|
|
57
|
+
return this.request("/search", {
|
|
58
|
+
method: "POST",
|
|
59
|
+
body: JSON.stringify({ project, q, limit }),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/** Fire-and-forget event ingest. Never throws. */
|
|
63
|
+
postEventSilent(event) {
|
|
64
|
+
void this.postEvent(event).catch(() => {
|
|
65
|
+
// silently drop — hooks must never block the shell
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const DEFAULT_BACKEND_URL = "http://localhost:7731";
|
|
2
|
+
export declare const DEFAULT_SUPERMEMORY_URL = "http://localhost:6767";
|
|
3
|
+
export interface CliConfig {
|
|
4
|
+
backendUrl: string;
|
|
5
|
+
supermemoryUrl: string;
|
|
6
|
+
project?: string;
|
|
7
|
+
sessionId: string;
|
|
8
|
+
cwd: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function env(key: string, fallback: string): string;
|
|
11
|
+
export declare function getBackendUrl(): string;
|
|
12
|
+
export declare function getSupermemoryUrl(): string;
|
|
13
|
+
export declare function getProjectOverride(): string | undefined;
|
|
14
|
+
export declare function getSessionId(): string;
|
|
15
|
+
export declare function getRepoRootFromGit(cwd?: string): string | undefined;
|
|
16
|
+
export declare function makeConfig(): CliConfig;
|
|
17
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,mBAAmB,0BAA0B,CAAC;AAC3D,eAAO,MAAM,uBAAuB,0BAA0B,CAAC;AAE/D,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAEvD;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,kBAAkB,CAAC,GAAG,SAAgB,GAAG,MAAM,GAAG,SAAS,CAW1E;AAED,wBAAgB,UAAU,IAAI,SAAS,CAQtC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
export const DEFAULT_BACKEND_URL = "http://localhost:7731";
|
|
3
|
+
export const DEFAULT_SUPERMEMORY_URL = "http://localhost:6767";
|
|
4
|
+
export function env(key, fallback) {
|
|
5
|
+
return process.env[key] ?? fallback;
|
|
6
|
+
}
|
|
7
|
+
export function getBackendUrl() {
|
|
8
|
+
return env("ENGRAM_BACKEND_URL", DEFAULT_BACKEND_URL).replace(/\/$/, "");
|
|
9
|
+
}
|
|
10
|
+
export function getSupermemoryUrl() {
|
|
11
|
+
return env("SUPERMEMORY_BASE_URL", DEFAULT_SUPERMEMORY_URL).replace(/\/$/, "");
|
|
12
|
+
}
|
|
13
|
+
export function getProjectOverride() {
|
|
14
|
+
return process.env.ENGRAM_PROJECT;
|
|
15
|
+
}
|
|
16
|
+
export function getSessionId() {
|
|
17
|
+
return process.env.ENGRAM_SESSION_ID ?? `cli-${Date.now()}-${process.pid}`;
|
|
18
|
+
}
|
|
19
|
+
export function getRepoRootFromGit(cwd = process.cwd()) {
|
|
20
|
+
try {
|
|
21
|
+
const out = execSync("git rev-parse --show-toplevel", {
|
|
22
|
+
cwd,
|
|
23
|
+
encoding: "utf8",
|
|
24
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
25
|
+
});
|
|
26
|
+
return out.trim() || undefined;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function makeConfig() {
|
|
33
|
+
return {
|
|
34
|
+
backendUrl: getBackendUrl(),
|
|
35
|
+
supermemoryUrl: getSupermemoryUrl(),
|
|
36
|
+
project: getProjectOverride(),
|
|
37
|
+
sessionId: getSessionId(),
|
|
38
|
+
cwd: process.cwd(),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,MAAM,CAAC,MAAM,mBAAmB,GAAG,uBAAuB,CAAC;AAC3D,MAAM,CAAC,MAAM,uBAAuB,GAAG,uBAAuB,CAAC;AAU/D,MAAM,UAAU,GAAG,CAAC,GAAW,EAAE,QAAgB;IAC/C,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,GAAG,CAAC,oBAAoB,EAAE,mBAAmB,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,GAAG,CAAC,sBAAsB,EAAE,uBAAuB,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACjF,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IACpD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,QAAQ,CAAC,+BAA+B,EAAE;YACpD,GAAG;YACH,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;SAClC,CAAC,CAAC;QACH,OAAO,GAAG,CAAC,IAAI,EAAE,IAAI,SAAS,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO;QACL,UAAU,EAAE,aAAa,EAAE;QAC3B,cAAc,EAAE,iBAAiB,EAAE;QACnC,OAAO,EAAE,kBAAkB,EAAE;QAC7B,SAAS,EAAE,YAAY,EAAE;QACzB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;KACnB,CAAC;AACJ,CAAC"}
|
package/dist/emit.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface EmitCommandOptions {
|
|
2
|
+
source: "terminal" | "git";
|
|
3
|
+
eventType: "command" | "branch_switch" | "commit";
|
|
4
|
+
content: string;
|
|
5
|
+
cwd?: string;
|
|
6
|
+
exitCode?: number;
|
|
7
|
+
stderr?: string;
|
|
8
|
+
sessionId?: string;
|
|
9
|
+
project?: string;
|
|
10
|
+
dryRun?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function emitCommand(opts: EmitCommandOptions): Promise<{
|
|
13
|
+
sent: boolean;
|
|
14
|
+
id?: string;
|
|
15
|
+
}>;
|
|
16
|
+
/** Fire-and-forget. Never blocks the shell or prints to stderr. */
|
|
17
|
+
export declare function emitCommandSilent(opts: EmitCommandOptions): void;
|
|
18
|
+
//# sourceMappingURL=emit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit.d.ts","sourceRoot":"","sources":["../src/emit.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,UAAU,GAAG,KAAK,CAAC;IAC3B,SAAS,EAAE,SAAS,GAAG,eAAe,GAAG,QAAQ,CAAC;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAmCzC;AAED,mEAAmE;AACnE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI,CAIhE"}
|
package/dist/emit.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { isSignalCommand } from "@engram-cli/contracts";
|
|
2
|
+
import { EngramClient } from "./client.js";
|
|
3
|
+
import { getBackendUrl, getSessionId } from "./config.js";
|
|
4
|
+
import { resolveProjectSlug } from "./project.js";
|
|
5
|
+
export async function emitCommand(opts) {
|
|
6
|
+
const project = resolveProjectSlug(opts.cwd, opts.project);
|
|
7
|
+
const sessionId = opts.sessionId ?? getSessionId();
|
|
8
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
9
|
+
const timestamp = new Date().toISOString();
|
|
10
|
+
if (opts.eventType === "command") {
|
|
11
|
+
const exitCode = opts.exitCode ?? 0;
|
|
12
|
+
if (exitCode === 0 && !isSignalCommand(opts.content)) {
|
|
13
|
+
return { sent: false };
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
const event = {
|
|
17
|
+
source: opts.source,
|
|
18
|
+
event_type: opts.eventType,
|
|
19
|
+
content: opts.content,
|
|
20
|
+
project,
|
|
21
|
+
cwd,
|
|
22
|
+
timestamp,
|
|
23
|
+
session_id: sessionId,
|
|
24
|
+
};
|
|
25
|
+
if (opts.eventType === "command") {
|
|
26
|
+
event.exit_code = opts.exitCode ?? 0;
|
|
27
|
+
}
|
|
28
|
+
if (opts.dryRun) {
|
|
29
|
+
console.log(JSON.stringify(event, null, 2));
|
|
30
|
+
return { sent: false };
|
|
31
|
+
}
|
|
32
|
+
const client = new EngramClient(getBackendUrl());
|
|
33
|
+
const res = await client.postEvent(event);
|
|
34
|
+
return { sent: res.accepted && !res.dropped, id: res.id };
|
|
35
|
+
}
|
|
36
|
+
/** Fire-and-forget. Never blocks the shell or prints to stderr. */
|
|
37
|
+
export function emitCommandSilent(opts) {
|
|
38
|
+
void emitCommand(opts).catch(() => {
|
|
39
|
+
// swallow — shell hooks must not interrupt the prompt
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=emit.js.map
|
package/dist/emit.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit.js","sourceRoot":"","sources":["../src/emit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoB,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAclD,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAwB;IAExB,MAAM,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,YAAY,EAAE,CAAC;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACtC,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAE3C,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;QACpC,IAAI,QAAQ,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACrD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAgB;QACzB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,UAAU,EAAE,IAAI,CAAC,SAAS;QAC1B,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,OAAO;QACP,GAAG;QACH,SAAS;QACT,UAAU,EAAE,SAAS;KACtB,CAAC;IAEF,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACjC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;IACvC,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5C,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACzB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,aAAa,EAAE,CAAC,CAAC;IACjD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC1C,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC;AAC5D,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,iBAAiB,CAAC,IAAwB;IACxD,KAAK,WAAW,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;QAChC,sDAAsD;IACxD,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/init.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAiFA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAyCjD"}
|
package/dist/init.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { execSync } from "node:child_process";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { normalizeProjectSlug } from "@engram-cli/contracts";
|
|
6
|
+
import { getBackendUrl } from "./config.js";
|
|
7
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const ENGRAM_RC_BLOCK_START = "# >>> engram terminal hook >>>";
|
|
9
|
+
const ENGRAM_RC_BLOCK_END = "# <<< engram terminal hook <<<";
|
|
10
|
+
const ENGRAM_HOOK_MARKER = "# Engram capture hook (managed by npx @engram-cli/engram init)";
|
|
11
|
+
function findMonorepoRoot() {
|
|
12
|
+
let dir = __dirname;
|
|
13
|
+
for (let i = 0; i < 4; i++) {
|
|
14
|
+
dir = path.dirname(dir);
|
|
15
|
+
if (fs.existsSync(path.join(dir, "cli")) &&
|
|
16
|
+
fs.existsSync(path.join(dir, "terminal-hook")) &&
|
|
17
|
+
fs.existsSync(path.join(dir, "git-hooks"))) {
|
|
18
|
+
return dir;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
function getRepoRoot() {
|
|
24
|
+
try {
|
|
25
|
+
return execSync("git rev-parse --show-toplevel", {
|
|
26
|
+
encoding: "utf8",
|
|
27
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
28
|
+
}).trim();
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
throw new Error("Not inside a git repository. Run `git init` first.");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function getProjectName(repoRoot) {
|
|
35
|
+
return normalizeProjectSlug(path.basename(repoRoot));
|
|
36
|
+
}
|
|
37
|
+
function ensureDir(dir) {
|
|
38
|
+
if (!fs.existsSync(dir))
|
|
39
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
40
|
+
}
|
|
41
|
+
function installGitHook(name, sourcePath, hooksDir) {
|
|
42
|
+
const targetPath = path.join(hooksDir, name);
|
|
43
|
+
const source = fs.readFileSync(sourcePath, "utf8");
|
|
44
|
+
if (fs.existsSync(targetPath)) {
|
|
45
|
+
const existing = fs.readFileSync(targetPath, "utf8");
|
|
46
|
+
if (existing.includes(ENGRAM_HOOK_MARKER)) {
|
|
47
|
+
console.log(`[engram] ${name} already installed`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// merge by appending our source below the marker
|
|
51
|
+
const merged = existing.trimEnd() + "\n\n" + ENGRAM_HOOK_MARKER + "\n" + source;
|
|
52
|
+
fs.writeFileSync(targetPath, merged, { mode: 0o755 });
|
|
53
|
+
console.log(`[engram] updated ${name}`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
fs.writeFileSync(targetPath, ENGRAM_HOOK_MARKER + "\n" + source, { mode: 0o755 });
|
|
57
|
+
console.log(`[engram] installed ${name}`);
|
|
58
|
+
}
|
|
59
|
+
function installTerminalHook(shellRcPath, hookSourcePath) {
|
|
60
|
+
const rc = fs.existsSync(shellRcPath) ? fs.readFileSync(shellRcPath, "utf8") : "";
|
|
61
|
+
if (rc.includes(ENGRAM_RC_BLOCK_START)) {
|
|
62
|
+
console.log(`[engram] terminal hook already in ${shellRcPath}`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const hook = fs.readFileSync(hookSourcePath, "utf8");
|
|
66
|
+
const block = `${ENGRAM_RC_BLOCK_START}\n${hook}\n${ENGRAM_RC_BLOCK_END}\n`;
|
|
67
|
+
fs.writeFileSync(shellRcPath, rc.trimEnd() + "\n\n" + block, { mode: 0o644 });
|
|
68
|
+
console.log(`[engram] ${rc ? "appended" : "created"} terminal hook in ${shellRcPath}`);
|
|
69
|
+
}
|
|
70
|
+
export async function initCommand() {
|
|
71
|
+
const repoRoot = getRepoRoot();
|
|
72
|
+
const project = getProjectName(repoRoot);
|
|
73
|
+
const hooksDir = path.join(repoRoot, ".git", "hooks");
|
|
74
|
+
const monorepoRoot = findMonorepoRoot();
|
|
75
|
+
const bundledTemplates = path.resolve(__dirname, "..", "templates");
|
|
76
|
+
const terminalHookDir = fs.existsSync(path.join(bundledTemplates, "engram-terminal.zsh"))
|
|
77
|
+
? bundledTemplates
|
|
78
|
+
: monorepoRoot
|
|
79
|
+
? path.join(monorepoRoot, "terminal-hook")
|
|
80
|
+
: undefined;
|
|
81
|
+
const gitHooksDir = fs.existsSync(path.join(bundledTemplates, "post-checkout"))
|
|
82
|
+
? bundledTemplates
|
|
83
|
+
: monorepoRoot
|
|
84
|
+
? path.join(monorepoRoot, "git-hooks")
|
|
85
|
+
: undefined;
|
|
86
|
+
if (!terminalHookDir || !gitHooksDir) {
|
|
87
|
+
throw new Error("Could not locate Engram hook templates. " +
|
|
88
|
+
"Make sure `engram` is installed from the monorepo or npm, or install hooks manually.");
|
|
89
|
+
}
|
|
90
|
+
ensureDir(hooksDir);
|
|
91
|
+
installGitHook("post-checkout", path.join(gitHooksDir, "post-checkout"), hooksDir);
|
|
92
|
+
installGitHook("post-commit", path.join(gitHooksDir, "post-commit"), hooksDir);
|
|
93
|
+
installTerminalHook(path.join(process.env.HOME ?? "~", ".zshrc"), path.join(terminalHookDir, "engram-terminal.zsh"));
|
|
94
|
+
installTerminalHook(path.join(process.env.HOME ?? "~", ".bashrc"), path.join(terminalHookDir, "engram-terminal.bash"));
|
|
95
|
+
console.log(`\n[engram] init complete for project "${project}"`);
|
|
96
|
+
console.log(`[engram] backend: ${getBackendUrl()}`);
|
|
97
|
+
console.log(`[engram] next: run \\\"engram start\\\" in another terminal, then reload your shell`);
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=init.js.map
|
package/dist/init.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE/D,MAAM,qBAAqB,GAAG,gCAAgC,CAAC;AAC/D,MAAM,mBAAmB,GAAG,gCAAgC,CAAC;AAC7D,MAAM,kBAAkB,GAAG,gEAAgE,CAAC;AAE5F,SAAS,gBAAgB;IACvB,IAAI,GAAG,GAAG,SAAS,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACxB,IACE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACpC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;YAC9C,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,EAC1C,CAAC;YACD,OAAO,GAAG,CAAC;QACb,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,+BAA+B,EAAE;YAC/C,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC;SAClC,CAAC,CAAC,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;IACxE,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,QAAgB;IACtC,OAAO,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,SAAS,CAAC,GAAW;IAC5B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,cAAc,CAAC,IAAY,EAAE,UAAkB,EAAE,QAAgB;IACxE,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAEnD,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACrD,IAAI,QAAQ,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,oBAAoB,CAAC,CAAC;YAClD,OAAO;QACT,CAAC;QACD,iDAAiD;QACjD,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,MAAM,GAAG,kBAAkB,GAAG,IAAI,GAAG,MAAM,CAAC;QAChF,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC;QACxC,OAAO;IACT,CAAC;IAED,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI,GAAG,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAClF,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,mBAAmB,CAAC,WAAmB,EAAE,cAAsB;IACtE,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAClF,IAAI,EAAE,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,qCAAqC,WAAW,EAAE,CAAC,CAAC;QAChE,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,GAAG,qBAAqB,KAAK,IAAI,KAAK,mBAAmB,IAAI,CAAC;IAC5E,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,EAAE,CAAC,OAAO,EAAE,GAAG,MAAM,GAAG,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9E,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,qBAAqB,WAAW,EAAE,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAEtD,MAAM,YAAY,GAAG,gBAAgB,EAAE,CAAC;IACxC,MAAM,gBAAgB,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;IACpE,MAAM,eAAe,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,CAAC;QACvF,CAAC,CAAC,gBAAgB;QAClB,CAAC,CAAC,YAAY;YACZ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,eAAe,CAAC;YAC1C,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,WAAW,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,eAAe,CAAC,CAAC;QAC7E,CAAC,CAAC,gBAAgB;QAClB,CAAC,CAAC,YAAY;YACZ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,WAAW,CAAC;YACtC,CAAC,CAAC,SAAS,CAAC;IAEhB,IAAI,CAAC,eAAe,IAAI,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CACb,0CAA0C;YACxC,sFAAsF,CACzF,CAAC;IACJ,CAAC;IAED,SAAS,CAAC,QAAQ,CAAC,CAAC;IACpB,cAAc,CAAC,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,QAAQ,CAAC,CAAC;IACnF,cAAc,CAAC,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,EAAE,QAAQ,CAAC,CAAC;IAE/E,mBAAmB,CACjB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,EAAE,QAAQ,CAAC,EAC5C,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,qBAAqB,CAAC,CAClD,CAAC;IACF,mBAAmB,CACjB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,EAAE,SAAS,CAAC,EAC7C,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,sBAAsB,CAAC,CACnD,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,yCAAyC,OAAO,GAAG,CAAC,CAAC;IACjE,OAAO,CAAC,GAAG,CAAC,qBAAqB,aAAa,EAAE,EAAE,CAAC,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,qFAAqF,CAAC,CAAC;AACrG,CAAC"}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAiCA,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CA2E5C"}
|
package/dist/mcp.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, McpError, ErrorCode, } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
import { EngramClient } from "./client.js";
|
|
5
|
+
import { getBackendUrl } from "./config.js";
|
|
6
|
+
import { resolveProjectSlug } from "./project.js";
|
|
7
|
+
function makeTool(name, description, args) {
|
|
8
|
+
const properties = {};
|
|
9
|
+
const required = [];
|
|
10
|
+
for (const arg of args) {
|
|
11
|
+
properties[arg.name] = { type: arg.type, description: arg.description };
|
|
12
|
+
if (arg.required)
|
|
13
|
+
required.push(arg.name);
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
name,
|
|
17
|
+
description,
|
|
18
|
+
inputSchema: { type: "object", properties, required },
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export async function runMcp() {
|
|
22
|
+
const backendUrl = getBackendUrl();
|
|
23
|
+
const client = new EngramClient(backendUrl);
|
|
24
|
+
const server = new Server({ name: "engram", version: "0.1.0" }, { capabilities: { tools: {} } });
|
|
25
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
26
|
+
tools: [
|
|
27
|
+
makeTool("engram_load_capsule", "Load the saved project capsule for a given Engram project. Returns the frozen snapshot including recent files, errors, failed commands, git state, and notes.", [{ name: "project", type: "string", description: "Engram project slug", required: true }]),
|
|
28
|
+
makeTool("engram_context", "Assemble the current live Context capsule for a project from Supermemory. This is read-only and reflects the latest captured intent.", [{ name: "project", type: "string", description: "Engram project slug", required: true }]),
|
|
29
|
+
makeTool("engram_search", "Search the Supermemory graph for a project using a natural-language query.", [
|
|
30
|
+
{ name: "project", type: "string", description: "Engram project slug", required: true },
|
|
31
|
+
{ name: "q", type: "string", description: "Natural language query", required: true },
|
|
32
|
+
{ name: "limit", type: "number", description: "Max results (default 10)", required: false },
|
|
33
|
+
]),
|
|
34
|
+
],
|
|
35
|
+
}));
|
|
36
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
37
|
+
const { name, arguments: rawArgs } = request.params;
|
|
38
|
+
const args = rawArgs ?? {};
|
|
39
|
+
if (name === "engram_load_capsule") {
|
|
40
|
+
const project = resolveProjectSlug(undefined, String(args.project ?? ""));
|
|
41
|
+
const capsule = await client.loadCapsule(project);
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{ type: "text", text: JSON.stringify(capsule, null, 2) },
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (name === "engram_context") {
|
|
49
|
+
const project = resolveProjectSlug(undefined, String(args.project ?? ""));
|
|
50
|
+
const context = await client.getContext(project, "cursor");
|
|
51
|
+
return {
|
|
52
|
+
content: [
|
|
53
|
+
{ type: "text", text: JSON.stringify(context, null, 2) },
|
|
54
|
+
],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (name === "engram_search") {
|
|
58
|
+
const project = resolveProjectSlug(undefined, String(args.project ?? ""));
|
|
59
|
+
const q = String(args.q ?? "");
|
|
60
|
+
const limit = typeof args.limit === "number" ? args.limit : 10;
|
|
61
|
+
if (!q)
|
|
62
|
+
throw new McpError(ErrorCode.InvalidParams, "Missing query parameter q");
|
|
63
|
+
const results = await client.search(project, q, limit);
|
|
64
|
+
return {
|
|
65
|
+
content: [
|
|
66
|
+
{ type: "text", text: JSON.stringify(results, null, 2) },
|
|
67
|
+
],
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
71
|
+
});
|
|
72
|
+
const transport = new StdioServerTransport();
|
|
73
|
+
await server.connect(transport);
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.d.ts","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAIA,wBAAgB,kBAAkB,CAAC,GAAG,SAAgB,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CASjF"}
|
package/dist/project.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { normalizeProjectSlug } from "@engram-cli/contracts";
|
|
3
|
+
import { getRepoRootFromGit } from "./config.js";
|
|
4
|
+
export function resolveProjectSlug(cwd = process.cwd(), override) {
|
|
5
|
+
if (override)
|
|
6
|
+
return normalizeProjectSlug(override);
|
|
7
|
+
const root = getRepoRootFromGit(cwd);
|
|
8
|
+
if (!root) {
|
|
9
|
+
throw new Error("Could not determine Engram project. Run inside a git repo or set ENGRAM_PROJECT.");
|
|
10
|
+
}
|
|
11
|
+
return normalizeProjectSlug(path.basename(root));
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../src/project.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,UAAU,kBAAkB,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,QAAiB;IACvE,IAAI,QAAQ;QAAE,OAAO,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACb,kFAAkF,CACnF,CAAC;IACJ,CAAC;IACD,OAAO,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;AACnD,CAAC"}
|
package/dist/start.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../src/start.ts"],"names":[],"mappings":"AAgLA,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAmElD"}
|
package/dist/start.js
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { getBackendUrl, getSupermemoryUrl } from "./config.js";
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
const SM_DATA_DIR = path.join(os.homedir(), ".supermemory");
|
|
10
|
+
const SM_API_KEY_FILE = path.join(SM_DATA_DIR, "api-key");
|
|
11
|
+
const REPO_ENV = path.resolve(__dirname, "..", "..", ".env");
|
|
12
|
+
function findMonorepoRoot() {
|
|
13
|
+
let dir = __dirname;
|
|
14
|
+
for (let i = 0; i < 4; i++) {
|
|
15
|
+
dir = path.dirname(dir);
|
|
16
|
+
if (fs.existsSync(path.join(dir, "backend")) && fs.existsSync(path.join(dir, "packages"))) {
|
|
17
|
+
return dir;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
function findBackendDir() {
|
|
23
|
+
const root = findMonorepoRoot();
|
|
24
|
+
if (!root)
|
|
25
|
+
return undefined;
|
|
26
|
+
const backend = path.join(root, "backend");
|
|
27
|
+
return fs.existsSync(backend) ? backend : undefined;
|
|
28
|
+
}
|
|
29
|
+
function findSupermemoryBinary() {
|
|
30
|
+
const root = findMonorepoRoot();
|
|
31
|
+
const home = os.homedir();
|
|
32
|
+
const globalCandidates = [
|
|
33
|
+
path.join(home, ".local", "bin", "supermemory-server"),
|
|
34
|
+
"/usr/local/bin/supermemory-server",
|
|
35
|
+
"/opt/homebrew/bin/supermemory-server",
|
|
36
|
+
];
|
|
37
|
+
const localCandidates = [
|
|
38
|
+
root && path.join(root, "node_modules", ".bin", "supermemory-server"),
|
|
39
|
+
root && path.join(root, "backend", "node_modules", ".bin", "supermemory-server"),
|
|
40
|
+
path.join(__dirname, "..", "node_modules", ".bin", "supermemory-server"),
|
|
41
|
+
path.join(__dirname, "..", "..", "backend", "node_modules", ".bin", "supermemory-server"),
|
|
42
|
+
].filter(Boolean);
|
|
43
|
+
for (const candidate of [...localCandidates, ...globalCandidates]) {
|
|
44
|
+
if (fs.existsSync(candidate))
|
|
45
|
+
return candidate;
|
|
46
|
+
}
|
|
47
|
+
return "npx";
|
|
48
|
+
}
|
|
49
|
+
function readApiKeyFile() {
|
|
50
|
+
try {
|
|
51
|
+
return fs.readFileSync(SM_API_KEY_FILE, "utf8").trim();
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function readEnvFile(key) {
|
|
58
|
+
try {
|
|
59
|
+
const text = fs.readFileSync(REPO_ENV, "utf8");
|
|
60
|
+
const match = text.match(new RegExp(`^${key}=([^\r\n]+)`, "m"));
|
|
61
|
+
return match?.[1]?.trim();
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function warnIfApiKeyMismatch() {
|
|
68
|
+
const fileKey = readApiKeyFile();
|
|
69
|
+
const envKey = readEnvFile("SUPERMEMORY_API_KEY");
|
|
70
|
+
if (fileKey && envKey && fileKey !== envKey) {
|
|
71
|
+
console.warn("[engram] warning: ~/.supermemory/api-key differs from repo .env SUPERMEMORY_API_KEY. " +
|
|
72
|
+
"Copy the new key into .env and restart.");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function sleep(ms) {
|
|
76
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
77
|
+
}
|
|
78
|
+
async function waitForReachable(url, label, opts = {}, timeoutMs = 30000) {
|
|
79
|
+
const deadline = Date.now() + timeoutMs;
|
|
80
|
+
const headers = {};
|
|
81
|
+
if (opts.withAuth) {
|
|
82
|
+
const apiKey = readEnvFile("SUPERMEMORY_API_KEY") ?? "";
|
|
83
|
+
headers.Authorization = `Bearer ${apiKey}`;
|
|
84
|
+
}
|
|
85
|
+
const probePath = opts.path ?? "/";
|
|
86
|
+
while (Date.now() < deadline) {
|
|
87
|
+
try {
|
|
88
|
+
const res = await fetch(`${url}${probePath}`, {
|
|
89
|
+
headers,
|
|
90
|
+
signal: AbortSignal.timeout(3000),
|
|
91
|
+
});
|
|
92
|
+
if (!opts.requireOk || res.ok)
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// not up yet
|
|
97
|
+
}
|
|
98
|
+
await sleep(250);
|
|
99
|
+
}
|
|
100
|
+
throw new Error(`${label} did not become reachable at ${url}${probePath} within ${timeoutMs}ms`);
|
|
101
|
+
}
|
|
102
|
+
function prefixStream(stream, prefix, out) {
|
|
103
|
+
if (!stream)
|
|
104
|
+
return;
|
|
105
|
+
let buffer = "";
|
|
106
|
+
stream.on("data", (chunk) => {
|
|
107
|
+
buffer += chunk.toString("utf8");
|
|
108
|
+
const lines = buffer.split("\n");
|
|
109
|
+
buffer = lines.pop() ?? "";
|
|
110
|
+
for (const line of lines) {
|
|
111
|
+
if (line)
|
|
112
|
+
out.write(`${prefix} ${line}\n`);
|
|
113
|
+
else
|
|
114
|
+
out.write("\n");
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
stream.on("end", () => {
|
|
118
|
+
if (buffer)
|
|
119
|
+
out.write(`${prefix} ${buffer}\n`);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
function stopAll(children) {
|
|
123
|
+
for (const child of children) {
|
|
124
|
+
try {
|
|
125
|
+
child.process.kill("SIGTERM");
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// ignore
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
setTimeout(() => {
|
|
132
|
+
for (const child of children) {
|
|
133
|
+
try {
|
|
134
|
+
if (!child.process.killed)
|
|
135
|
+
child.process.kill("SIGKILL");
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// ignore
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}, 4000).unref();
|
|
142
|
+
}
|
|
143
|
+
function waitForChildren(children, timeoutMs) {
|
|
144
|
+
return new Promise((resolve) => {
|
|
145
|
+
const deadline = Date.now() + timeoutMs;
|
|
146
|
+
const check = () => {
|
|
147
|
+
if (children.every((c) => c.process.exitCode !== null)) {
|
|
148
|
+
resolve();
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (Date.now() >= deadline) {
|
|
152
|
+
resolve();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
setTimeout(check, 250);
|
|
156
|
+
};
|
|
157
|
+
check();
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
export async function startCommand() {
|
|
161
|
+
const backendUrl = getBackendUrl();
|
|
162
|
+
const supermemoryUrl = getSupermemoryUrl();
|
|
163
|
+
const backendDir = findBackendDir();
|
|
164
|
+
const smBin = findSupermemoryBinary();
|
|
165
|
+
if (!backendDir) {
|
|
166
|
+
throw new Error("Could not locate the Engram backend directory. " +
|
|
167
|
+
"Make sure engram is installed next to the backend folder, or run from the monorepo.");
|
|
168
|
+
}
|
|
169
|
+
const children = [];
|
|
170
|
+
let shuttingDown = false;
|
|
171
|
+
const shutdown = () => {
|
|
172
|
+
if (shuttingDown)
|
|
173
|
+
return;
|
|
174
|
+
shuttingDown = true;
|
|
175
|
+
console.log("\n[engram] shutting down...");
|
|
176
|
+
stopAll(children);
|
|
177
|
+
};
|
|
178
|
+
process.on("SIGINT", shutdown);
|
|
179
|
+
process.on("SIGTERM", shutdown);
|
|
180
|
+
try {
|
|
181
|
+
const smArgs = smBin === "npx" ? ["supermemory-server"] : [];
|
|
182
|
+
const sm = spawn(smBin, smArgs, {
|
|
183
|
+
cwd: os.homedir(),
|
|
184
|
+
env: {
|
|
185
|
+
...process.env,
|
|
186
|
+
SUPERMEMORY_DATA_DIR: SM_DATA_DIR,
|
|
187
|
+
},
|
|
188
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
189
|
+
detached: false,
|
|
190
|
+
});
|
|
191
|
+
children.push({ name: "[supermemory]", process: sm });
|
|
192
|
+
prefixStream(sm.stdout, "[supermemory]", process.stdout);
|
|
193
|
+
prefixStream(sm.stderr, "[supermemory]", process.stderr);
|
|
194
|
+
console.log(`[engram] starting Supermemory Local (${supermemoryUrl})...`);
|
|
195
|
+
await waitForReachable(supermemoryUrl, "Supermemory", { withAuth: true });
|
|
196
|
+
warnIfApiKeyMismatch();
|
|
197
|
+
console.log(`[engram] starting Engram backend (${backendUrl})...`);
|
|
198
|
+
const backend = spawn("npm", ["run", "start"], {
|
|
199
|
+
cwd: backendDir,
|
|
200
|
+
env: process.env,
|
|
201
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
202
|
+
detached: false,
|
|
203
|
+
});
|
|
204
|
+
children.push({ name: "[engram]", process: backend });
|
|
205
|
+
prefixStream(backend.stdout, "[engram]", process.stdout);
|
|
206
|
+
prefixStream(backend.stderr, "[engram]", process.stderr);
|
|
207
|
+
await waitForReachable(backendUrl, "Engram backend", { path: "/health", requireOk: true });
|
|
208
|
+
console.log(`[engram] ready — backend ${backendUrl} · supermemory ${supermemoryUrl}`);
|
|
209
|
+
console.log("[engram] press Ctrl+C to stop both services");
|
|
210
|
+
// Keep process alive until children exit (or force exit after shutdown timeout)
|
|
211
|
+
await waitForChildren(children, Number.POSITIVE_INFINITY);
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
shutdown();
|
|
215
|
+
await waitForChildren(children, 10000);
|
|
216
|
+
throw err;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../src/start.ts"],"names":[],"mappings":"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"}
|
package/dist/status.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAGA,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAiBnD"}
|
package/dist/status.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { EngramClient } from "./client.js";
|
|
2
|
+
import { getBackendUrl } from "./config.js";
|
|
3
|
+
export async function statusCommand() {
|
|
4
|
+
const url = getBackendUrl();
|
|
5
|
+
const client = new EngramClient(url);
|
|
6
|
+
try {
|
|
7
|
+
const health = await client.health();
|
|
8
|
+
console.log(`backend: ${url} — ok: ${health.ok}`);
|
|
9
|
+
console.log(`supermemory: ${health.supermemory ? "up" : "down"}`);
|
|
10
|
+
if (health.supabase !== undefined && health.supabase !== null) {
|
|
11
|
+
console.log(`supabase: ${health.supabase ? "up" : "down"}`);
|
|
12
|
+
}
|
|
13
|
+
process.exit(0);
|
|
14
|
+
}
|
|
15
|
+
catch (err) {
|
|
16
|
+
console.error(`backend unreachable (${url}): ${err instanceof Error ? err.message : String(err)}`);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,UAAU,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QAClD,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QAClE,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YAC9D,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CACX,wBAAwB,GAAG,MAAM,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACpF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@engram-cli/engram",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI + MCP entry for Engram — local-first developer context hub",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/cli.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"engram": "./dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc -p tsconfig.json",
|
|
12
|
+
"dev": "tsx --env-file=../.env src/cli.ts",
|
|
13
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
14
|
+
"smoke": "bash scripts/smoke.sh",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@engram-cli/contracts": "^0.1.0",
|
|
19
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
20
|
+
"commander": "^13.0.0",
|
|
21
|
+
"zod": "^3.25.76"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^22.15.32",
|
|
25
|
+
"tsx": "^4.20.3",
|
|
26
|
+
"typescript": "^5.8.3"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"templates",
|
|
31
|
+
"README.md"
|
|
32
|
+
],
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=20"
|
|
36
|
+
},
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"engram",
|
|
42
|
+
"mcp",
|
|
43
|
+
"developer-context",
|
|
44
|
+
"supermemory",
|
|
45
|
+
"cli"
|
|
46
|
+
]
|
|
47
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Engram terminal capture hook for bash.
|
|
3
|
+
# Source this from ~/.bashrc or let `npx @engram-cli/engram init` append it.
|
|
4
|
+
|
|
5
|
+
export ENGRAM_SESSION_ID="${ENGRAM_SESSION_ID:-bash-$$-${SECONDS}}"
|
|
6
|
+
|
|
7
|
+
_engram_last_command=""
|
|
8
|
+
_engram_in_prompt=0
|
|
9
|
+
|
|
10
|
+
function _engram_debug_trap() {
|
|
11
|
+
if [[ "$_engram_in_prompt" -eq 0 ]]; then
|
|
12
|
+
_engram_last_command="$BASH_COMMAND"
|
|
13
|
+
fi
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function _engram_precmd() {
|
|
17
|
+
_engram_in_prompt=1
|
|
18
|
+
local exit_code=$?
|
|
19
|
+
if [[ -n "$_engram_last_command" ]]; then
|
|
20
|
+
# avoid re-emitting the prompt command itself
|
|
21
|
+
case "$_engram_last_command" in
|
|
22
|
+
_engram_precmd*|PROMPT_COMMAND=*) ;;
|
|
23
|
+
*)
|
|
24
|
+
local trimmed="${_engram_last_command#"${_engram_last_command%%[![:space:]]*}"}"
|
|
25
|
+
if [[ -n "$trimmed" ]]; then
|
|
26
|
+
engram emit --source terminal --type command \
|
|
27
|
+
--content "$_engram_last_command" \
|
|
28
|
+
--cwd "$PWD" \
|
|
29
|
+
--exit-code "$exit_code" \
|
|
30
|
+
--session-id "$ENGRAM_SESSION_ID" >/dev/null 2>&1
|
|
31
|
+
fi
|
|
32
|
+
;;
|
|
33
|
+
esac
|
|
34
|
+
fi
|
|
35
|
+
_engram_last_command=""
|
|
36
|
+
_engram_in_prompt=0
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
trap '_engram_debug_trap' DEBUG
|
|
40
|
+
PROMPT_COMMAND='_engram_precmd'
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/bin/zsh
|
|
2
|
+
# Engram terminal capture hook for zsh.
|
|
3
|
+
# Source this from ~/.zshrc or let `npx @engram-cli/engram init` append it.
|
|
4
|
+
|
|
5
|
+
export ENGRAM_SESSION_ID="${ENGRAM_SESSION_ID:-zsh-${$}-${EPOCHSECONDS}}"
|
|
6
|
+
|
|
7
|
+
_engram_last_command=""
|
|
8
|
+
|
|
9
|
+
function _engram_preexec() {
|
|
10
|
+
_engram_last_command="$1"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function _engram_precmd() {
|
|
14
|
+
local exit_code=$?
|
|
15
|
+
if [[ -n "$_engram_last_command" ]]; then
|
|
16
|
+
# ignore pure whitespace and shell-internal noise
|
|
17
|
+
local trimmed="${_engram_last_command#"${_engram_last_command%%[![:space:]]*}"}"
|
|
18
|
+
if [[ -n "$trimmed" ]]; then
|
|
19
|
+
engram emit --source terminal --type command \
|
|
20
|
+
--content "$_engram_last_command" \
|
|
21
|
+
--cwd "$PWD" \
|
|
22
|
+
--exit-code "$exit_code" \
|
|
23
|
+
--session-id "$ENGRAM_SESSION_ID" >/dev/null 2>&1
|
|
24
|
+
fi
|
|
25
|
+
fi
|
|
26
|
+
_engram_last_command=""
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
preexec_functions+=(_engram_preexec)
|
|
30
|
+
precmd_functions+=(_engram_precmd)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Engram git hook: post-checkout
|
|
3
|
+
# Emits a branch_switch event when the checked-out branch actually changes.
|
|
4
|
+
|
|
5
|
+
PREV_REF=$1
|
|
6
|
+
NEW_REF=$2
|
|
7
|
+
FLAG=$3
|
|
8
|
+
|
|
9
|
+
if [ "$FLAG" -ne 1 ]; then
|
|
10
|
+
exit 0
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || git describe --tags --exact-match 2>/dev/null || git rev-parse --short HEAD)
|
|
14
|
+
if [ -z "$BRANCH" ]; then
|
|
15
|
+
exit 0
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
export ENGRAM_SESSION_ID="${ENGRAM_SESSION_ID:-git-$$}"
|
|
19
|
+
|
|
20
|
+
engram emit --source git --type branch_switch \
|
|
21
|
+
--content "$BRANCH" \
|
|
22
|
+
--cwd "$PWD" \
|
|
23
|
+
--session-id "$ENGRAM_SESSION_ID" >/dev/null 2>&1
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
# Engram git hook: post-commit
|
|
3
|
+
# Emits a commit event with the subject line only — no diffs.
|
|
4
|
+
|
|
5
|
+
SUBJECT=$(git log -1 --pretty=%s)
|
|
6
|
+
if [ -z "$SUBJECT" ]; then
|
|
7
|
+
exit 0
|
|
8
|
+
fi
|
|
9
|
+
|
|
10
|
+
export ENGRAM_SESSION_ID="${ENGRAM_SESSION_ID:-git-$$}"
|
|
11
|
+
|
|
12
|
+
engram emit --source git --type commit \
|
|
13
|
+
--content "$SUBJECT" \
|
|
14
|
+
--cwd "$PWD" \
|
|
15
|
+
--session-id "$ENGRAM_SESSION_ID" >/dev/null 2>&1
|