engramx 2.0.1 → 2.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/CHANGELOG.md +288 -0
- package/README.md +55 -0
- package/dist/{aider-context-BC5R2ZTA.js → aider-context-J557IHIP.js} +1 -1
- package/dist/auth-KB2ZRMS3.js +14 -0
- package/dist/check-2Z3MPZEJ.js +12 -0
- package/dist/{chunk-C6GBUOAL.js → chunk-4XA6ENNL.js} +1 -1
- package/dist/{chunk-533LR4I7.js → chunk-G4U3QOOW.js} +13 -97
- package/dist/chunk-N6PPKOPK.js +105 -0
- package/dist/chunk-RM2TBOVW.js +121 -0
- package/dist/chunk-SMU4WR3D.js +187 -0
- package/dist/chunk-XFE6ZANP.js +99 -0
- package/dist/chunk-XVYE4OX2.js +232 -0
- package/dist/{chunk-SJT7VS2G.js → chunk-ZVWRIVWQ.js} +17 -0
- package/dist/cli.js +593 -322
- package/dist/{core-6IY5L6II.js → core-TSXA5XZH.js} +1 -1
- package/dist/{cursor-mdc-GJ7E5LDD.js → cursor-mdc-VEOFFDVO.js} +1 -1
- package/dist/{exporter-GWU2GF23.js → exporter-AWXS34AS.js} +1 -1
- package/dist/{importer-V62NGZRK.js → importer-3Q5M6QBL.js} +1 -1
- package/dist/index.js +2 -2
- package/dist/install-YVMVCFQW.js +121 -0
- package/dist/notify-5POGKMRX.js +36 -0
- package/dist/report-C3GTM3HY.js +12 -0
- package/dist/serve.js +4 -3
- package/dist/{server-6AOI7NQP.js → server-A6MUVKQK.js} +127 -31
- package/dist/{windsurf-rules-C7SVDHBL.js → windsurf-rules-RWPKBHRD.js} +1 -1
- package/dist/wizard-AOXWMSXW.js +274 -0
- package/package.json +1 -1
|
@@ -33,7 +33,7 @@ function buildSection(heading, bullets) {
|
|
|
33
33
|
return [`## ${heading}`, "", ...bullets, ""].join("\n");
|
|
34
34
|
}
|
|
35
35
|
async function generateCursorMdc(projectPath) {
|
|
36
|
-
const { getStore } = await import("./core-
|
|
36
|
+
const { getStore } = await import("./core-TSXA5XZH.js");
|
|
37
37
|
const store = await getStore(projectPath);
|
|
38
38
|
try {
|
|
39
39
|
const allNodes = store.getAllNodes();
|
|
@@ -12,7 +12,7 @@ function buildSection(heading, nodes) {
|
|
|
12
12
|
return [`## ${heading}`, "", ...bullets, ""].join("\n");
|
|
13
13
|
}
|
|
14
14
|
async function exportCcs(projectRoot) {
|
|
15
|
-
const { getStore } = await import("./core-
|
|
15
|
+
const { getStore } = await import("./core-TSXA5XZH.js");
|
|
16
16
|
const store = await getStore(projectRoot);
|
|
17
17
|
try {
|
|
18
18
|
const allNodes = store.getAllNodes();
|
|
@@ -25,7 +25,7 @@ async function importCcs(projectRoot) {
|
|
|
25
25
|
if (!existsSync(filePath)) {
|
|
26
26
|
return { nodesCreated: 0, sectionsFound: 0 };
|
|
27
27
|
}
|
|
28
|
-
const { getStore } = await import("./core-
|
|
28
|
+
const { getStore } = await import("./core-TSXA5XZH.js");
|
|
29
29
|
const store = await getStore(projectRoot);
|
|
30
30
|
try {
|
|
31
31
|
const raw = readFileSync(filePath, "utf-8");
|
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
generateSummary,
|
|
5
5
|
install,
|
|
6
6
|
uninstall
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-4XA6ENNL.js";
|
|
8
8
|
import {
|
|
9
9
|
GraphStore,
|
|
10
10
|
SUPPORTED_EXTENSIONS,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
sliceGraphemeSafe,
|
|
24
24
|
stats,
|
|
25
25
|
truncateGraphemeSafe
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-ZVWRIVWQ.js";
|
|
27
27
|
import "./chunk-PEH54LYC.js";
|
|
28
28
|
export {
|
|
29
29
|
GraphStore,
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
// src/update/install.ts
|
|
2
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
3
|
+
import { existsSync } from "fs";
|
|
4
|
+
import { dirname } from "path";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
var PACKAGE_NAME = "engramx";
|
|
7
|
+
function detectPackageManager() {
|
|
8
|
+
let installPath = null;
|
|
9
|
+
try {
|
|
10
|
+
installPath = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
} catch {
|
|
12
|
+
installPath = null;
|
|
13
|
+
}
|
|
14
|
+
if (!installPath) {
|
|
15
|
+
return { manager: null, installPath: null, reason: "none" };
|
|
16
|
+
}
|
|
17
|
+
const lower = installPath.toLowerCase();
|
|
18
|
+
if (lower.includes("/pnpm/") || lower.includes("\\pnpm\\")) {
|
|
19
|
+
return { manager: "pnpm", installPath, reason: "pnpm-path-marker" };
|
|
20
|
+
}
|
|
21
|
+
if (lower.includes("/.yarn/") || lower.includes("\\.yarn\\")) {
|
|
22
|
+
return { manager: "yarn", installPath, reason: "yarn-path-marker" };
|
|
23
|
+
}
|
|
24
|
+
if (lower.includes("/bun/") || lower.includes("\\bun\\")) {
|
|
25
|
+
return { manager: "bun", installPath, reason: "bun-path-marker" };
|
|
26
|
+
}
|
|
27
|
+
return { manager: "npm", installPath, reason: "npm-fallback" };
|
|
28
|
+
}
|
|
29
|
+
function upgradeCommand(manager, channel = "latest") {
|
|
30
|
+
const target = `${PACKAGE_NAME}@${channel}`;
|
|
31
|
+
switch (manager) {
|
|
32
|
+
case "npm":
|
|
33
|
+
return { cmd: "npm", args: ["install", "-g", target] };
|
|
34
|
+
case "pnpm":
|
|
35
|
+
return { cmd: "pnpm", args: ["add", "-g", target] };
|
|
36
|
+
case "yarn":
|
|
37
|
+
return { cmd: "yarn", args: ["global", "add", target] };
|
|
38
|
+
case "bun":
|
|
39
|
+
return { cmd: "bun", args: ["add", "-g", target] };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function managerOnPath(manager) {
|
|
43
|
+
try {
|
|
44
|
+
const r = spawnSync(manager, ["--version"], {
|
|
45
|
+
encoding: "utf-8",
|
|
46
|
+
timeout: 2e3
|
|
47
|
+
});
|
|
48
|
+
return r.status === 0;
|
|
49
|
+
} catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function runUpgrade(opts = {}) {
|
|
54
|
+
const channel = opts.channel ?? "latest";
|
|
55
|
+
const detected = opts.manager !== void 0 ? { manager: opts.manager, installPath: null, reason: "override" } : detectPackageManager();
|
|
56
|
+
if (detected.manager === null) {
|
|
57
|
+
return {
|
|
58
|
+
ok: false,
|
|
59
|
+
message: "Could not detect how engram was installed. Run your package manager's upgrade manually.",
|
|
60
|
+
executed: null,
|
|
61
|
+
stderrTail: null
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (!managerOnPath(detected.manager)) {
|
|
65
|
+
return {
|
|
66
|
+
ok: false,
|
|
67
|
+
message: `${detected.manager} not found on PATH. Install it or use a different package manager.`,
|
|
68
|
+
executed: null,
|
|
69
|
+
stderrTail: null
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const { cmd, args } = upgradeCommand(detected.manager, channel);
|
|
73
|
+
const executed = `${cmd} ${args.join(" ")}`;
|
|
74
|
+
if (opts.dryRun) {
|
|
75
|
+
return {
|
|
76
|
+
ok: true,
|
|
77
|
+
message: `Would run: ${executed}`,
|
|
78
|
+
executed,
|
|
79
|
+
stderrTail: null
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
execFileSync(cmd, args, {
|
|
84
|
+
stdio: "inherit",
|
|
85
|
+
timeout: 12e4
|
|
86
|
+
});
|
|
87
|
+
return {
|
|
88
|
+
ok: true,
|
|
89
|
+
message: `Upgrade complete via ${detected.manager}.`,
|
|
90
|
+
executed,
|
|
91
|
+
stderrTail: null
|
|
92
|
+
};
|
|
93
|
+
} catch (err) {
|
|
94
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
95
|
+
const tail = msg.split("\n").slice(-5).join("\n");
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
message: `Upgrade failed via ${detected.manager}. Try manually: ${executed}`,
|
|
99
|
+
executed,
|
|
100
|
+
stderrTail: tail
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function manualCommand(channel = "latest") {
|
|
105
|
+
return `npm install -g ${PACKAGE_NAME}@${channel}`;
|
|
106
|
+
}
|
|
107
|
+
function safeEnvironment() {
|
|
108
|
+
if (existsSync("/opt/homebrew/bin/engram") || existsSync("/usr/local/Homebrew/bin/engram")) {
|
|
109
|
+
}
|
|
110
|
+
return { ok: true };
|
|
111
|
+
}
|
|
112
|
+
var PACKAGE = PACKAGE_NAME;
|
|
113
|
+
export {
|
|
114
|
+
PACKAGE,
|
|
115
|
+
detectPackageManager,
|
|
116
|
+
managerOnPath,
|
|
117
|
+
manualCommand,
|
|
118
|
+
runUpgrade,
|
|
119
|
+
safeEnvironment,
|
|
120
|
+
upgradeCommand
|
|
121
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cachePath,
|
|
3
|
+
isNewer,
|
|
4
|
+
optedOut
|
|
5
|
+
} from "./chunk-RM2TBOVW.js";
|
|
6
|
+
|
|
7
|
+
// src/update/notify.ts
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
import { existsSync, readFileSync } from "fs";
|
|
10
|
+
var printedThisProcess = false;
|
|
11
|
+
function maybePrintUpdateHint(currentVersion) {
|
|
12
|
+
if (printedThisProcess) return null;
|
|
13
|
+
if (optedOut()) return null;
|
|
14
|
+
const path = cachePath();
|
|
15
|
+
if (!existsSync(path)) return null;
|
|
16
|
+
let latest = null;
|
|
17
|
+
try {
|
|
18
|
+
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
19
|
+
if (typeof parsed?.latest === "string") latest = parsed.latest;
|
|
20
|
+
} catch {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
if (!latest) return null;
|
|
24
|
+
if (!isNewer(latest, currentVersion)) return null;
|
|
25
|
+
const hint = chalk.dim("\u{1F4A1} ") + chalk.yellow(`engram v${latest}`) + chalk.dim(" is available \u2014 run ") + chalk.white("engram update") + chalk.dim(` (you're on v${currentVersion})`);
|
|
26
|
+
process.stderr.write(hint + "\n");
|
|
27
|
+
printedThisProcess = true;
|
|
28
|
+
return hint;
|
|
29
|
+
}
|
|
30
|
+
function _resetPrintedFlag() {
|
|
31
|
+
printedThisProcess = false;
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
_resetPrintedFlag,
|
|
35
|
+
maybePrintUpdateHint
|
|
36
|
+
};
|
package/dist/serve.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
import {
|
|
3
3
|
MAX_MISTAKE_LABEL_CHARS,
|
|
4
4
|
benchmark,
|
|
5
|
+
formatThousands,
|
|
5
6
|
godNodes,
|
|
6
7
|
mistakes,
|
|
7
8
|
path,
|
|
8
9
|
query,
|
|
9
10
|
stats,
|
|
10
11
|
truncateGraphemeSafe
|
|
11
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ZVWRIVWQ.js";
|
|
12
13
|
import "./chunk-PEH54LYC.js";
|
|
13
14
|
|
|
14
15
|
// src/serve.ts
|
|
@@ -111,8 +112,8 @@ AMBIGUOUS: ${s.ambiguousPct}%`;
|
|
|
111
112
|
case "benchmark": {
|
|
112
113
|
const b = await benchmark(PROJECT_ROOT);
|
|
113
114
|
return [
|
|
114
|
-
`Full corpus: ~${b.naiveFullCorpus
|
|
115
|
-
`Avg graph query: ~${b.avgQueryTokens
|
|
115
|
+
`Full corpus: ~${formatThousands(b.naiveFullCorpus)} tokens`,
|
|
116
|
+
`Avg graph query: ~${formatThousands(b.avgQueryTokens)} tokens`,
|
|
116
117
|
`Reduction vs full corpus: ${b.reductionVsFull}x`,
|
|
117
118
|
`Reduction vs relevant files: ${b.reductionVsRelevant}x`,
|
|
118
119
|
"",
|
|
@@ -3,9 +3,18 @@ import {
|
|
|
3
3
|
getContextCache
|
|
4
4
|
} from "./chunk-CIQQ5Y3S.js";
|
|
5
5
|
import {
|
|
6
|
-
|
|
6
|
+
getOrCreateToken,
|
|
7
|
+
isHostValid,
|
|
8
|
+
isOriginAllowed,
|
|
9
|
+
parseCookies,
|
|
10
|
+
safeEqual
|
|
11
|
+
} from "./chunk-N6PPKOPK.js";
|
|
12
|
+
import {
|
|
7
13
|
summarizeHookLog
|
|
8
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-XFE6ZANP.js";
|
|
15
|
+
import {
|
|
16
|
+
getComponentStatus
|
|
17
|
+
} from "./chunk-G4U3QOOW.js";
|
|
9
18
|
import {
|
|
10
19
|
readHookLog
|
|
11
20
|
} from "./chunk-KL6NSPVA.js";
|
|
@@ -14,7 +23,7 @@ import {
|
|
|
14
23
|
learn,
|
|
15
24
|
query,
|
|
16
25
|
stats
|
|
17
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-ZVWRIVWQ.js";
|
|
18
27
|
import "./chunk-PEH54LYC.js";
|
|
19
28
|
|
|
20
29
|
// src/server/http.ts
|
|
@@ -1006,6 +1015,14 @@ var PROVIDERS = [
|
|
|
1006
1015
|
"context7",
|
|
1007
1016
|
"obsidian"
|
|
1008
1017
|
];
|
|
1018
|
+
var serverToken = "";
|
|
1019
|
+
var serverPort = 0;
|
|
1020
|
+
function currentToken() {
|
|
1021
|
+
return serverToken;
|
|
1022
|
+
}
|
|
1023
|
+
function authCookie(token) {
|
|
1024
|
+
return `engram_token=${token}; HttpOnly; SameSite=Strict; Path=/`;
|
|
1025
|
+
}
|
|
1009
1026
|
function parseUrl(req) {
|
|
1010
1027
|
return new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
|
|
1011
1028
|
}
|
|
@@ -1014,23 +1031,42 @@ async function readBody(req) {
|
|
|
1014
1031
|
for await (const chunk of req) chunks.push(chunk);
|
|
1015
1032
|
return Buffer.concat(chunks).toString("utf-8");
|
|
1016
1033
|
}
|
|
1017
|
-
function
|
|
1034
|
+
function corsHeaders(req) {
|
|
1035
|
+
const origin = req.headers.origin;
|
|
1036
|
+
if (!origin || !isOriginAllowed(origin, serverPort)) return {};
|
|
1037
|
+
return {
|
|
1038
|
+
"Access-Control-Allow-Origin": origin,
|
|
1039
|
+
"Access-Control-Allow-Credentials": "true",
|
|
1040
|
+
"Vary": "Origin"
|
|
1041
|
+
};
|
|
1042
|
+
}
|
|
1043
|
+
function json(res, status, data, extraHeaders = {}) {
|
|
1018
1044
|
res.writeHead(status, {
|
|
1019
1045
|
"Content-Type": "application/json",
|
|
1020
|
-
|
|
1021
|
-
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
|
1022
|
-
"Access-Control-Allow-Headers": "Authorization, Content-Type"
|
|
1046
|
+
...extraHeaders
|
|
1023
1047
|
});
|
|
1024
1048
|
res.end(JSON.stringify(data));
|
|
1025
1049
|
}
|
|
1026
1050
|
function checkAuth(req, res) {
|
|
1027
|
-
const
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1051
|
+
const expected = currentToken();
|
|
1052
|
+
const auth = req.headers.authorization ?? "";
|
|
1053
|
+
if (auth.startsWith("Bearer ")) {
|
|
1054
|
+
const presented = auth.slice(7).trim();
|
|
1055
|
+
if (safeEqual(presented, expected)) return true;
|
|
1056
|
+
}
|
|
1057
|
+
const cookies = parseCookies(req.headers.cookie);
|
|
1058
|
+
if (cookies.engram_token && safeEqual(cookies.engram_token, expected)) {
|
|
1059
|
+
return true;
|
|
1060
|
+
}
|
|
1031
1061
|
json(res, 401, { error: "Unauthorized" });
|
|
1032
1062
|
return false;
|
|
1033
1063
|
}
|
|
1064
|
+
function requireJsonContentType(req, res) {
|
|
1065
|
+
const ct = (req.headers["content-type"] ?? "").toLowerCase();
|
|
1066
|
+
if (ct.startsWith("application/json")) return true;
|
|
1067
|
+
json(res, 415, { error: "Content-Type must be application/json" });
|
|
1068
|
+
return false;
|
|
1069
|
+
}
|
|
1034
1070
|
function handleHealth(_req, res, startedAt) {
|
|
1035
1071
|
json(res, 200, {
|
|
1036
1072
|
ok: true,
|
|
@@ -1219,12 +1255,12 @@ async function handleGraphGodNodes(_req, res, projectRoot) {
|
|
|
1219
1255
|
}
|
|
1220
1256
|
var sseClients = /* @__PURE__ */ new Set();
|
|
1221
1257
|
var hookLogWatcher = null;
|
|
1222
|
-
function handleSSE(
|
|
1258
|
+
function handleSSE(req, res, projectRoot) {
|
|
1223
1259
|
res.writeHead(200, {
|
|
1224
1260
|
"Content-Type": "text/event-stream",
|
|
1225
1261
|
"Cache-Control": "no-cache",
|
|
1226
1262
|
"Connection": "keep-alive",
|
|
1227
|
-
|
|
1263
|
+
...corsHeaders(req)
|
|
1228
1264
|
});
|
|
1229
1265
|
res.write('data: {"type":"connected"}\n\n');
|
|
1230
1266
|
sseClients.add(res);
|
|
@@ -1277,23 +1313,73 @@ function removePid(projectRoot) {
|
|
|
1277
1313
|
function createHttpServer(projectRoot, port) {
|
|
1278
1314
|
return new Promise((resolve, reject) => {
|
|
1279
1315
|
const startedAt = Date.now();
|
|
1316
|
+
const tokenInfo = getOrCreateToken();
|
|
1317
|
+
serverToken = tokenInfo.token;
|
|
1318
|
+
serverPort = port;
|
|
1280
1319
|
const server = createServer(async (req, res) => {
|
|
1320
|
+
if (!isHostValid(req.headers.host, port)) {
|
|
1321
|
+
res.writeHead(400);
|
|
1322
|
+
res.end();
|
|
1323
|
+
return;
|
|
1324
|
+
}
|
|
1325
|
+
const origin = req.headers.origin;
|
|
1326
|
+
if (origin && !isOriginAllowed(origin, port)) {
|
|
1327
|
+
res.writeHead(403);
|
|
1328
|
+
res.end();
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
if (origin && isOriginAllowed(origin, port)) {
|
|
1332
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
1333
|
+
res.setHeader("Access-Control-Allow-Credentials", "true");
|
|
1334
|
+
res.setHeader("Vary", "Origin");
|
|
1335
|
+
}
|
|
1281
1336
|
if (req.method === "OPTIONS") {
|
|
1282
1337
|
res.writeHead(204, {
|
|
1283
|
-
"Access-Control-Allow-Origin": "*",
|
|
1284
1338
|
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
|
|
1285
1339
|
"Access-Control-Allow-Headers": "Authorization, Content-Type"
|
|
1286
1340
|
});
|
|
1287
1341
|
res.end();
|
|
1288
1342
|
return;
|
|
1289
1343
|
}
|
|
1290
|
-
if (!checkAuth(req, res)) return;
|
|
1291
1344
|
const url = parseUrl(req);
|
|
1292
1345
|
const path = url.pathname;
|
|
1346
|
+
if (req.method === "GET" && path === "/health") {
|
|
1347
|
+
handleHealth(req, res, startedAt);
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
if (req.method === "GET" && path === "/favicon.ico") {
|
|
1351
|
+
const svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><rect width="100" height="100" rx="20" fill="#0a0a0b"/><text x="50" y="62" font-size="56" text-anchor="middle" fill="#10b981" font-family="Menlo,monospace">◆</text></svg>';
|
|
1352
|
+
res.writeHead(200, {
|
|
1353
|
+
"Content-Type": "image/svg+xml",
|
|
1354
|
+
"Cache-Control": "public, max-age=86400"
|
|
1355
|
+
});
|
|
1356
|
+
res.end(svg);
|
|
1357
|
+
return;
|
|
1358
|
+
}
|
|
1359
|
+
if (req.method === "GET" && (path === "/ui" || path === "/ui/")) {
|
|
1360
|
+
const queryToken = url.searchParams.get("token");
|
|
1361
|
+
if (queryToken) {
|
|
1362
|
+
const fetchSite = req.headers["sec-fetch-site"];
|
|
1363
|
+
const siteOk = fetchSite === void 0 || fetchSite === "none" || fetchSite === "same-origin";
|
|
1364
|
+
if (siteOk && safeEqual(queryToken, currentToken())) {
|
|
1365
|
+
res.writeHead(302, {
|
|
1366
|
+
Location: "/ui",
|
|
1367
|
+
"Set-Cookie": authCookie(currentToken()),
|
|
1368
|
+
"Referrer-Policy": "no-referrer",
|
|
1369
|
+
"Cache-Control": "no-store",
|
|
1370
|
+
"X-Content-Type-Options": "nosniff"
|
|
1371
|
+
});
|
|
1372
|
+
res.end();
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
if (!checkAuth(req, res)) return;
|
|
1378
|
+
if (req.method === "POST" || req.method === "PUT" || req.method === "DELETE") {
|
|
1379
|
+
if (!requireJsonContentType(req, res)) return;
|
|
1380
|
+
}
|
|
1293
1381
|
try {
|
|
1294
|
-
if (req.method === "GET" && path === "/
|
|
1295
|
-
handleHealth(req, res, startedAt);
|
|
1296
|
-
} else if (req.method === "GET" && path === "/query") {
|
|
1382
|
+
if (req.method === "GET" && path === "/query") {
|
|
1297
1383
|
await handleQuery(req, res, projectRoot);
|
|
1298
1384
|
} else if (req.method === "GET" && path === "/stats") {
|
|
1299
1385
|
await handleStats(req, res, projectRoot);
|
|
@@ -1322,16 +1408,11 @@ function createHttpServer(projectRoot, port) {
|
|
|
1322
1408
|
} else if (req.method === "GET" && (path === "/ui" || path === "/ui/")) {
|
|
1323
1409
|
res.writeHead(200, {
|
|
1324
1410
|
"Content-Type": "text/html; charset=utf-8",
|
|
1325
|
-
"Cache-Control": "no-cache"
|
|
1411
|
+
"Cache-Control": "no-cache",
|
|
1412
|
+
"Set-Cookie": authCookie(currentToken()),
|
|
1413
|
+
"X-Content-Type-Options": "nosniff"
|
|
1326
1414
|
});
|
|
1327
1415
|
res.end(buildDashboardHtml());
|
|
1328
|
-
} else if (req.method === "GET" && path === "/favicon.ico") {
|
|
1329
|
-
const svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><rect width="100" height="100" rx="20" fill="#0a0a0b"/><text x="50" y="62" font-size="56" text-anchor="middle" fill="#10b981" font-family="Menlo,monospace">◆</text></svg>';
|
|
1330
|
-
res.writeHead(200, {
|
|
1331
|
-
"Content-Type": "image/svg+xml",
|
|
1332
|
-
"Cache-Control": "public, max-age=86400"
|
|
1333
|
-
});
|
|
1334
|
-
res.end(svg);
|
|
1335
1416
|
} else {
|
|
1336
1417
|
json(res, 404, { error: "Not found" });
|
|
1337
1418
|
}
|
|
@@ -1351,7 +1432,7 @@ function createHttpServer(projectRoot, port) {
|
|
|
1351
1432
|
};
|
|
1352
1433
|
process.on("SIGINT", cleanup);
|
|
1353
1434
|
process.on("SIGTERM", cleanup);
|
|
1354
|
-
resolve();
|
|
1435
|
+
resolve(tokenInfo);
|
|
1355
1436
|
});
|
|
1356
1437
|
});
|
|
1357
1438
|
}
|
|
@@ -1359,11 +1440,26 @@ function createHttpServer(projectRoot, port) {
|
|
|
1359
1440
|
// src/server/index.ts
|
|
1360
1441
|
var DEFAULT_PORT = 7337;
|
|
1361
1442
|
async function startHttpServer(projectRoot, port = DEFAULT_PORT) {
|
|
1362
|
-
await createHttpServer(projectRoot, port);
|
|
1363
|
-
|
|
1364
|
-
|
|
1443
|
+
const tokenInfo = await createHttpServer(projectRoot, port);
|
|
1444
|
+
const url = `http://127.0.0.1:${port}`;
|
|
1445
|
+
process.stdout.write(`engram HTTP server listening on ${url}
|
|
1446
|
+
`);
|
|
1447
|
+
if (tokenInfo.source === "env") {
|
|
1448
|
+
process.stderr.write(
|
|
1449
|
+
"engram: auth token from ENGRAM_API_TOKEN env var\n"
|
|
1450
|
+
);
|
|
1451
|
+
} else if (tokenInfo.source === "file") {
|
|
1452
|
+
process.stderr.write(
|
|
1453
|
+
`engram: auth token at ${tokenInfo.path}
|
|
1365
1454
|
`
|
|
1366
|
-
|
|
1455
|
+
);
|
|
1456
|
+
} else {
|
|
1457
|
+
process.stderr.write(
|
|
1458
|
+
`engram: auth token generated at ${tokenInfo.path} (0600)
|
|
1459
|
+
curl -H "Authorization: Bearer $(cat ${tokenInfo.path})" ${url}/stats
|
|
1460
|
+
`
|
|
1461
|
+
);
|
|
1462
|
+
}
|
|
1367
1463
|
}
|
|
1368
1464
|
export {
|
|
1369
1465
|
startHttpServer
|
|
@@ -7,7 +7,7 @@ function buildSection(heading, lines) {
|
|
|
7
7
|
return [`## ${heading}`, "", ...lines, ""].join("\n");
|
|
8
8
|
}
|
|
9
9
|
async function generateWindsurfRules(projectRoot) {
|
|
10
|
-
const { getStore } = await import("./core-
|
|
10
|
+
const { getStore } = await import("./core-TSXA5XZH.js");
|
|
11
11
|
const store = await getStore(projectRoot);
|
|
12
12
|
try {
|
|
13
13
|
const allNodes = store.getAllNodes();
|