@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 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,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -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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"}
@@ -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
@@ -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,2 @@
1
+ export declare function initCommand(): Promise<void>;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
package/dist/mcp.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function runMcp(): Promise<void>;
2
+ //# sourceMappingURL=mcp.d.ts.map
@@ -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function resolveProjectSlug(cwd?: string, override?: string): string;
2
+ //# sourceMappingURL=project.d.ts.map
@@ -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"}
@@ -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"}
@@ -0,0 +1,2 @@
1
+ export declare function startCommand(): Promise<void>;
2
+ //# sourceMappingURL=start.d.ts.map
@@ -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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"}
@@ -0,0 +1,2 @@
1
+ export declare function statusCommand(): Promise<void>;
2
+ //# sourceMappingURL=status.d.ts.map
@@ -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