engramx 2.0.2 → 3.0.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 +271 -0
- package/README.md +161 -17
- package/dist/{aider-context-BC5R2ZTA.js → aider-context-6IDE3R7U.js} +1 -1
- package/dist/check-2Z3MPZEJ.js +12 -0
- package/dist/{chunk-PEH54LYC.js → chunk-645NBY6L.js} +42 -5
- package/dist/chunk-73IBCRFI.js +215 -0
- package/dist/{chunk-SJT7VS2G.js → chunk-B4UOE64J.js} +46 -11
- package/dist/chunk-FKY6HIT2.js +99 -0
- package/dist/{chunk-533LR4I7.js → chunk-G4U3QOOW.js} +13 -97
- package/dist/chunk-RJC6RNXJ.js +1405 -0
- package/dist/chunk-RM2TBOVW.js +121 -0
- package/dist/chunk-SMU4WR3D.js +187 -0
- package/dist/{chunk-C6GBUOAL.js → chunk-VLTWBTQ7.js} +14 -15
- package/dist/chunk-XVYE4OX2.js +232 -0
- package/dist/chunk-ZUC6OXSL.js +178 -0
- package/dist/cli.js +818 -1533
- package/dist/{core-6IY5L6II.js → core-77F2BVYV.js} +2 -2
- package/dist/{cursor-mdc-GJ7E5LDD.js → cursor-mdc-EEO7PYZ3.js} +1 -1
- package/dist/{exporter-GWU2GF23.js → exporter-ZYJ4WM2F.js} +1 -1
- package/dist/{importer-V62NGZRK.js → importer-4UWQDH4W.js} +1 -1
- package/dist/index.js +3 -3
- package/dist/install-YVMVCFQW.js +121 -0
- package/dist/mcp-client-ROOJF76V.js +9 -0
- package/dist/mcp-config-QD4NPVXB.js +12 -0
- package/dist/{migrate-UKCO6BUU.js → migrate-KJ5K5NWO.js} +1 -1
- package/dist/notify-5POGKMRX.js +36 -0
- package/dist/{plugin-loader-STTGYIL5.js → plugin-loader-SQQB6V74.js} +69 -23
- package/dist/report-C3GTM3HY.js +12 -0
- package/dist/resolver-H7GXVP73.js +21 -0
- package/dist/serve.js +5 -4
- package/dist/{server-KUG7U6SG.js → server-2ZQKXJ5M.js} +74 -4
- package/dist/{windsurf-rules-C7SVDHBL.js → windsurf-rules-XF7MYF6J.js} +1 -1
- package/dist/wizard-UH27IO4I.js +274 -0
- package/package.json +3 -2
- package/dist/{tuner-KFNNGKG3.js → tuner-Y2YENAZC.js} +3 -3
|
@@ -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-77F2BVYV.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-77F2BVYV.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-77F2BVYV.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-VLTWBTQ7.js";
|
|
8
8
|
import {
|
|
9
9
|
GraphStore,
|
|
10
10
|
SUPPORTED_EXTENSIONS,
|
|
@@ -23,8 +23,8 @@ import {
|
|
|
23
23
|
sliceGraphemeSafe,
|
|
24
24
|
stats,
|
|
25
25
|
truncateGraphemeSafe
|
|
26
|
-
} from "./chunk-
|
|
27
|
-
import "./chunk-
|
|
26
|
+
} from "./chunk-B4UOE64J.js";
|
|
27
|
+
import "./chunk-645NBY6L.js";
|
|
28
28
|
export {
|
|
29
29
|
GraphStore,
|
|
30
30
|
SUPPORTED_EXTENSIONS,
|
|
@@ -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
|
+
};
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createMcpProvider
|
|
3
|
+
} from "./chunk-73IBCRFI.js";
|
|
4
|
+
import {
|
|
5
|
+
validateProviderConfig
|
|
6
|
+
} from "./chunk-ZUC6OXSL.js";
|
|
7
|
+
|
|
1
8
|
// src/providers/plugin-loader.ts
|
|
2
9
|
import { existsSync, readdirSync, mkdirSync } from "fs";
|
|
3
10
|
import { join } from "path";
|
|
@@ -23,34 +30,73 @@ function validatePlugin(mod) {
|
|
|
23
30
|
return { plugin: null, reason: "default export is not an object" };
|
|
24
31
|
}
|
|
25
32
|
const p = candidate;
|
|
26
|
-
|
|
27
|
-
"name"
|
|
28
|
-
"label",
|
|
29
|
-
"tier",
|
|
30
|
-
"tokenBudget",
|
|
31
|
-
"timeoutMs",
|
|
32
|
-
"version",
|
|
33
|
-
"resolve",
|
|
34
|
-
"isAvailable"
|
|
35
|
-
];
|
|
36
|
-
for (const field of required) {
|
|
37
|
-
if (p[field] === void 0 || p[field] === null) {
|
|
38
|
-
return { plugin: null, reason: `missing required field: ${field}` };
|
|
39
|
-
}
|
|
33
|
+
if (typeof p.name !== "string" || p.name.length === 0) {
|
|
34
|
+
return { plugin: null, reason: "name must be a non-empty string" };
|
|
40
35
|
}
|
|
41
|
-
if (typeof p.
|
|
42
|
-
return { plugin: null, reason:
|
|
36
|
+
if (typeof p.label !== "string" || p.label.length === 0) {
|
|
37
|
+
return { plugin: null, reason: `[${p.name}] label must be a non-empty string` };
|
|
43
38
|
}
|
|
44
|
-
if (typeof p.
|
|
45
|
-
return { plugin: null, reason:
|
|
39
|
+
if (typeof p.version !== "string" || p.version.length === 0) {
|
|
40
|
+
return { plugin: null, reason: `[${p.name}] version must be a non-empty string` };
|
|
46
41
|
}
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
const hasMcpConfig = p.mcpConfig !== void 0 && p.mcpConfig !== null;
|
|
43
|
+
const hasResolve = typeof p.resolve === "function";
|
|
44
|
+
if (!hasMcpConfig && !hasResolve) {
|
|
45
|
+
return {
|
|
46
|
+
plugin: null,
|
|
47
|
+
reason: `[${p.name}] plugin needs either a resolve() function or an mcpConfig declaration`
|
|
48
|
+
};
|
|
49
49
|
}
|
|
50
|
-
if (
|
|
51
|
-
|
|
50
|
+
if (hasResolve) {
|
|
51
|
+
const classicRequired = [
|
|
52
|
+
"tier",
|
|
53
|
+
"tokenBudget",
|
|
54
|
+
"timeoutMs",
|
|
55
|
+
"isAvailable"
|
|
56
|
+
];
|
|
57
|
+
for (const field of classicRequired) {
|
|
58
|
+
if (p[field] === void 0 || p[field] === null) {
|
|
59
|
+
return { plugin: null, reason: `[${p.name}] missing required field: ${field}` };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (typeof p.isAvailable !== "function") {
|
|
63
|
+
return { plugin: null, reason: `[${p.name}] isAvailable must be a function` };
|
|
64
|
+
}
|
|
65
|
+
if (p.tier !== 1 && p.tier !== 2) {
|
|
66
|
+
return { plugin: null, reason: `[${p.name}] tier must be 1 or 2 (got ${String(p.tier)})` };
|
|
67
|
+
}
|
|
68
|
+
return { plugin: candidate, reason: "" };
|
|
69
|
+
}
|
|
70
|
+
const rawConfig = p.mcpConfig;
|
|
71
|
+
const normalizedConfig = {
|
|
72
|
+
name: p.name,
|
|
73
|
+
label: p.label,
|
|
74
|
+
...rawConfig
|
|
75
|
+
};
|
|
76
|
+
const validation = validateProviderConfig(normalizedConfig);
|
|
77
|
+
if (!validation.ok) {
|
|
78
|
+
return {
|
|
79
|
+
plugin: null,
|
|
80
|
+
reason: `[${p.name}] invalid mcpConfig: ${validation.reason}`
|
|
81
|
+
};
|
|
52
82
|
}
|
|
53
|
-
|
|
83
|
+
const mcpProvider = createMcpProvider(
|
|
84
|
+
validation.value
|
|
85
|
+
);
|
|
86
|
+
const merged = {
|
|
87
|
+
name: p.name,
|
|
88
|
+
label: p.label,
|
|
89
|
+
version: p.version,
|
|
90
|
+
description: p.description,
|
|
91
|
+
author: p.author,
|
|
92
|
+
mcpConfig: p.mcpConfig,
|
|
93
|
+
tier: p.tier ?? mcpProvider.tier,
|
|
94
|
+
tokenBudget: p.tokenBudget ?? mcpProvider.tokenBudget,
|
|
95
|
+
timeoutMs: p.timeoutMs ?? mcpProvider.timeoutMs,
|
|
96
|
+
resolve: mcpProvider.resolve.bind(mcpProvider),
|
|
97
|
+
isAvailable: mcpProvider.isAvailable.bind(mcpProvider)
|
|
98
|
+
};
|
|
99
|
+
return { plugin: merged, reason: "" };
|
|
54
100
|
}
|
|
55
101
|
async function loadPlugins(dir) {
|
|
56
102
|
const pluginsDir = dir ?? getPluginsDir();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
_resetAvailabilityCache,
|
|
3
|
+
_resetMcpProvidersCache,
|
|
4
|
+
boostByMistakes,
|
|
5
|
+
enforcePerProviderBudget,
|
|
6
|
+
resolveRichPacket,
|
|
7
|
+
resolveRichPacketStreaming,
|
|
8
|
+
warmAllProviders
|
|
9
|
+
} from "./chunk-RJC6RNXJ.js";
|
|
10
|
+
import "./chunk-22INHMKB.js";
|
|
11
|
+
import "./chunk-B4UOE64J.js";
|
|
12
|
+
import "./chunk-645NBY6L.js";
|
|
13
|
+
export {
|
|
14
|
+
_resetAvailabilityCache,
|
|
15
|
+
_resetMcpProvidersCache,
|
|
16
|
+
boostByMistakes,
|
|
17
|
+
enforcePerProviderBudget,
|
|
18
|
+
resolveRichPacket,
|
|
19
|
+
resolveRichPacketStreaming,
|
|
20
|
+
warmAllProviders
|
|
21
|
+
};
|
package/dist/serve.js
CHANGED
|
@@ -2,14 +2,15 @@
|
|
|
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
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-B4UOE64J.js";
|
|
13
|
+
import "./chunk-645NBY6L.js";
|
|
13
14
|
|
|
14
15
|
// src/serve.ts
|
|
15
16
|
function clampInt(value, defaultValue, min, max) {
|
|
@@ -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
|
"",
|
|
@@ -10,19 +10,21 @@ import {
|
|
|
10
10
|
safeEqual
|
|
11
11
|
} from "./chunk-N6PPKOPK.js";
|
|
12
12
|
import {
|
|
13
|
-
getComponentStatus,
|
|
14
13
|
summarizeHookLog
|
|
15
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-FKY6HIT2.js";
|
|
16
15
|
import {
|
|
17
16
|
readHookLog
|
|
18
17
|
} from "./chunk-KL6NSPVA.js";
|
|
18
|
+
import {
|
|
19
|
+
getComponentStatus
|
|
20
|
+
} from "./chunk-G4U3QOOW.js";
|
|
19
21
|
import {
|
|
20
22
|
getStore,
|
|
21
23
|
learn,
|
|
22
24
|
query,
|
|
23
25
|
stats
|
|
24
|
-
} from "./chunk-
|
|
25
|
-
import "./chunk-
|
|
26
|
+
} from "./chunk-B4UOE64J.js";
|
|
27
|
+
import "./chunk-645NBY6L.js";
|
|
26
28
|
|
|
27
29
|
// src/server/http.ts
|
|
28
30
|
import { createServer } from "http";
|
|
@@ -1091,6 +1093,72 @@ async function handleQuery(req, res, projectRoot) {
|
|
|
1091
1093
|
json(res, 500, { error: "Query failed", detail: String(err) });
|
|
1092
1094
|
}
|
|
1093
1095
|
}
|
|
1096
|
+
async function handleContextStream(req, res, projectRoot) {
|
|
1097
|
+
const url = parseUrl(req);
|
|
1098
|
+
const filePath = url.searchParams.get("file");
|
|
1099
|
+
if (!filePath) {
|
|
1100
|
+
json(res, 400, { error: "Missing required query parameter 'file'" });
|
|
1101
|
+
return;
|
|
1102
|
+
}
|
|
1103
|
+
const lastEventIdHeader = req.headers["last-event-id"];
|
|
1104
|
+
const resumeAfter = (() => {
|
|
1105
|
+
if (typeof lastEventIdHeader !== "string") return -1;
|
|
1106
|
+
const n = parseInt(lastEventIdHeader, 10);
|
|
1107
|
+
return isNaN(n) ? -1 : n;
|
|
1108
|
+
})();
|
|
1109
|
+
res.writeHead(200, {
|
|
1110
|
+
"Content-Type": "text/event-stream",
|
|
1111
|
+
"Cache-Control": "no-cache, no-transform",
|
|
1112
|
+
Connection: "keep-alive",
|
|
1113
|
+
"X-Accel-Buffering": "no",
|
|
1114
|
+
...corsHeaders(req)
|
|
1115
|
+
});
|
|
1116
|
+
if (typeof res.flushHeaders === "function") res.flushHeaders();
|
|
1117
|
+
const context = {
|
|
1118
|
+
filePath,
|
|
1119
|
+
projectRoot,
|
|
1120
|
+
nodeIds: [],
|
|
1121
|
+
imports: [],
|
|
1122
|
+
hasTests: false,
|
|
1123
|
+
churnRate: 0
|
|
1124
|
+
};
|
|
1125
|
+
const { resolveRichPacketStreaming } = await import("./resolver-H7GXVP73.js");
|
|
1126
|
+
let eventId = 0;
|
|
1127
|
+
let disconnected = false;
|
|
1128
|
+
req.on("close", () => {
|
|
1129
|
+
disconnected = true;
|
|
1130
|
+
});
|
|
1131
|
+
try {
|
|
1132
|
+
for await (const event of resolveRichPacketStreaming(
|
|
1133
|
+
filePath,
|
|
1134
|
+
context
|
|
1135
|
+
)) {
|
|
1136
|
+
if (disconnected) break;
|
|
1137
|
+
if (eventId <= resumeAfter) {
|
|
1138
|
+
eventId++;
|
|
1139
|
+
continue;
|
|
1140
|
+
}
|
|
1141
|
+
const frame = `id: ${eventId}
|
|
1142
|
+
event: ${event.type}
|
|
1143
|
+
data: ${JSON.stringify(
|
|
1144
|
+
event.type === "provider" ? event.result : { providerCount: event.providerCount, durationMs: event.durationMs }
|
|
1145
|
+
)}
|
|
1146
|
+
|
|
1147
|
+
`;
|
|
1148
|
+
try {
|
|
1149
|
+
res.write(frame);
|
|
1150
|
+
} catch {
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1153
|
+
eventId++;
|
|
1154
|
+
}
|
|
1155
|
+
} finally {
|
|
1156
|
+
try {
|
|
1157
|
+
res.end();
|
|
1158
|
+
} catch {
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1094
1162
|
async function handleStats(_req, res, projectRoot) {
|
|
1095
1163
|
try {
|
|
1096
1164
|
const result = await stats(projectRoot);
|
|
@@ -1403,6 +1471,8 @@ function createHttpServer(projectRoot, port) {
|
|
|
1403
1471
|
await handleGraphGodNodes(req, res, projectRoot);
|
|
1404
1472
|
} else if (req.method === "GET" && path === "/api/sse") {
|
|
1405
1473
|
handleSSE(req, res, projectRoot);
|
|
1474
|
+
} else if (req.method === "GET" && path === "/context/stream") {
|
|
1475
|
+
await handleContextStream(req, res, projectRoot);
|
|
1406
1476
|
} else if (req.method === "GET" && (path === "/ui" || path === "/ui/")) {
|
|
1407
1477
|
res.writeHead(200, {
|
|
1408
1478
|
"Content-Type": "text/html; charset=utf-8",
|
|
@@ -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-77F2BVYV.js");
|
|
11
11
|
const store = await getStore(projectRoot);
|
|
12
12
|
try {
|
|
13
13
|
const allNodes = store.getAllNodes();
|