@askexenow/exe-os 0.9.69 → 0.9.70
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/deploy/stack-manifests/v0.9.json +96 -16
- package/dist/bin/agentic-ontology-backfill.js +6 -0
- package/dist/bin/agentic-reflection-backfill.js +6 -0
- package/dist/bin/agentic-semantic-label.js +6 -0
- package/dist/bin/backfill-conversations.js +6 -0
- package/dist/bin/backfill-responses.js +6 -0
- package/dist/bin/backfill-vectors.js +6 -0
- package/dist/bin/bulk-sync-postgres.js +6 -0
- package/dist/bin/cleanup-stale-review-tasks.js +6 -0
- package/dist/bin/cli.js +1257 -178
- package/dist/bin/exe-agent.js +6 -0
- package/dist/bin/exe-assign.js +6 -0
- package/dist/bin/exe-boot.js +6 -0
- package/dist/bin/exe-call.js +6 -0
- package/dist/bin/exe-cloud.js +6 -0
- package/dist/bin/exe-dispatch.js +6 -0
- package/dist/bin/exe-doctor.js +6 -0
- package/dist/bin/exe-export-behaviors.js +6 -0
- package/dist/bin/exe-forget.js +6 -0
- package/dist/bin/exe-gateway.js +151 -110
- package/dist/bin/exe-heartbeat.js +6 -0
- package/dist/bin/exe-kill.js +6 -0
- package/dist/bin/exe-launch-agent.js +6 -0
- package/dist/bin/exe-new-employee.js +6 -0
- package/dist/bin/exe-pending-messages.js +6 -0
- package/dist/bin/exe-pending-notifications.js +6 -0
- package/dist/bin/exe-pending-reviews.js +6 -0
- package/dist/bin/exe-rename.js +13 -4
- package/dist/bin/exe-review.js +6 -0
- package/dist/bin/exe-search.js +6 -0
- package/dist/bin/exe-session-cleanup.js +6 -0
- package/dist/bin/exe-start-codex.js +6 -0
- package/dist/bin/exe-start-opencode.js +6 -0
- package/dist/bin/exe-status.js +6 -0
- package/dist/bin/exe-team.js +6 -0
- package/dist/bin/git-sweep.js +6 -0
- package/dist/bin/graph-backfill.js +150 -110
- package/dist/bin/graph-export.js +6 -0
- package/dist/bin/intercom-check.js +6 -0
- package/dist/bin/registry-proxy.js +207 -0
- package/dist/bin/scan-tasks.js +6 -0
- package/dist/bin/setup.js +6 -0
- package/dist/bin/shard-migrate.js +6 -0
- package/dist/bin/stack-update.js +128 -0
- package/dist/gateway/index.js +151 -110
- package/dist/hooks/bug-report-worker.js +6 -0
- package/dist/hooks/codex-stop-task-finalizer.js +6 -0
- package/dist/hooks/commit-complete.js +6 -0
- package/dist/hooks/error-recall.js +6 -0
- package/dist/hooks/ingest.js +6 -0
- package/dist/hooks/instructions-loaded.js +6 -0
- package/dist/hooks/notification.js +6 -0
- package/dist/hooks/post-compact.js +6 -0
- package/dist/hooks/post-tool-combined.js +6 -0
- package/dist/hooks/pre-compact.js +6 -0
- package/dist/hooks/pre-tool-use.js +6 -0
- package/dist/hooks/prompt-submit.js +6 -0
- package/dist/hooks/session-end.js +6 -0
- package/dist/hooks/session-start.js +6 -0
- package/dist/hooks/stop.js +6 -0
- package/dist/hooks/subagent-stop.js +6 -0
- package/dist/hooks/summary-worker.js +6 -0
- package/dist/index.js +151 -110
- package/dist/lib/employee-templates.js +6 -0
- package/dist/lib/exe-daemon.js +382 -234
- package/dist/lib/hybrid-search.js +6 -0
- package/dist/lib/registry-proxy.js +162 -0
- package/dist/lib/schedules.js +6 -0
- package/dist/lib/store.js +6 -0
- package/dist/mcp/server.js +318 -222
- package/dist/runtime/index.js +6 -0
- package/dist/tui/App.js +6 -0
- package/package.json +3 -2
- package/stack.release.json +6 -4
- package/stack.release.schema.json +89 -18
package/dist/lib/exe-daemon.js
CHANGED
|
@@ -5790,6 +5790,12 @@ var init_platform_procedures = __esm({
|
|
|
5790
5790
|
priority: "p0",
|
|
5791
5791
|
content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
|
|
5792
5792
|
},
|
|
5793
|
+
{
|
|
5794
|
+
title: "Code context first for repository orientation",
|
|
5795
|
+
domain: "workflow",
|
|
5796
|
+
priority: "p1",
|
|
5797
|
+
content: "Before broad repo exploration, symbol tracing, blast-radius review, or codebase Q&A, agents should use the consolidated code_context MCP tool instead of manual grep/read loops. Use action=index or stats to refresh/check the index; action=search with query, limit, offset, languages, paths, refresh_index for fresh multi-language code/doc search; action=trace for symbol imports/dependents; action=blast_radius for impact analysis before edits. CLI parity exists via exe-os code-context init|index|status|stats|search|doctor. Keep code_context separate from durable employee memory: promote only validated decisions, procedures, or lessons into store_memory/commit_memory."
|
|
5798
|
+
},
|
|
5793
5799
|
{
|
|
5794
5800
|
title: "Commit discipline \u2014 never leave verified work floating",
|
|
5795
5801
|
domain: "workflow",
|
|
@@ -19020,13 +19026,25 @@ var init_export_graph = __esm({
|
|
|
19020
19026
|
|
|
19021
19027
|
// src/lib/code-chunker.ts
|
|
19022
19028
|
import ts from "typescript";
|
|
19029
|
+
function languageForFile(filePath) {
|
|
19030
|
+
const base = filePath.split(/[\\/]/).pop()?.toLowerCase() ?? "";
|
|
19031
|
+
if (["dockerfile", "makefile", "rakefile", "gemfile"].includes(base)) return base;
|
|
19032
|
+
const ext = base.includes(".") ? base.split(".").pop() : void 0;
|
|
19033
|
+
return ext ? LANGUAGE_BY_EXTENSION[ext] : void 0;
|
|
19034
|
+
}
|
|
19023
19035
|
function chunkSourceFile(source, fileName = "file.ts") {
|
|
19036
|
+
const language = languageForFile(fileName);
|
|
19037
|
+
if (language === "typescript" || language === "javascript") {
|
|
19038
|
+
return chunkTypeScriptLike(source, fileName);
|
|
19039
|
+
}
|
|
19040
|
+
return chunkGenericSource(source, fileName, language);
|
|
19041
|
+
}
|
|
19042
|
+
function chunkTypeScriptLike(source, fileName) {
|
|
19024
19043
|
const sourceFile = ts.createSourceFile(
|
|
19025
19044
|
fileName,
|
|
19026
19045
|
source,
|
|
19027
19046
|
ts.ScriptTarget.Latest,
|
|
19028
19047
|
true,
|
|
19029
|
-
// setParentNodes
|
|
19030
19048
|
fileName.endsWith(".tsx") || fileName.endsWith(".jsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS
|
|
19031
19049
|
);
|
|
19032
19050
|
const chunks = [];
|
|
@@ -19048,144 +19066,117 @@ function chunkSourceFile(source, fileName = "file.ts") {
|
|
|
19048
19066
|
if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) {
|
|
19049
19067
|
return node.name?.getText(sourceFile) ?? "(anonymous)";
|
|
19050
19068
|
}
|
|
19051
|
-
if (ts.isClassDeclaration(node))
|
|
19052
|
-
|
|
19053
|
-
|
|
19054
|
-
if (ts.
|
|
19055
|
-
|
|
19056
|
-
|
|
19057
|
-
if (ts.isTypeAliasDeclaration(node)) {
|
|
19058
|
-
return node.name.getText(sourceFile);
|
|
19059
|
-
}
|
|
19060
|
-
if (ts.isEnumDeclaration(node)) {
|
|
19061
|
-
return node.name.getText(sourceFile);
|
|
19062
|
-
}
|
|
19063
|
-
if (ts.isVariableStatement(node)) {
|
|
19064
|
-
const decls = node.declarationList.declarations;
|
|
19065
|
-
return decls.map((d) => d.name.getText(sourceFile)).join(", ");
|
|
19066
|
-
}
|
|
19067
|
-
if (ts.isExportAssignment(node)) {
|
|
19068
|
-
return "default export";
|
|
19069
|
-
}
|
|
19069
|
+
if (ts.isClassDeclaration(node)) return node.name?.getText(sourceFile) ?? "(anonymous class)";
|
|
19070
|
+
if (ts.isInterfaceDeclaration(node)) return node.name.getText(sourceFile);
|
|
19071
|
+
if (ts.isTypeAliasDeclaration(node)) return node.name.getText(sourceFile);
|
|
19072
|
+
if (ts.isEnumDeclaration(node)) return node.name.getText(sourceFile);
|
|
19073
|
+
if (ts.isVariableStatement(node)) return node.declarationList.declarations.map((d) => d.name.getText(sourceFile)).join(", ");
|
|
19074
|
+
if (ts.isExportAssignment(node)) return "default export";
|
|
19070
19075
|
return "(unknown)";
|
|
19071
19076
|
}
|
|
19072
19077
|
function visitTopLevel(node) {
|
|
19073
19078
|
if (ts.isImportDeclaration(node)) {
|
|
19074
|
-
importLines.push({
|
|
19075
|
-
start: getLineNumber(node.getStart(sourceFile)),
|
|
19076
|
-
end: getLineNumber(node.getEnd())
|
|
19077
|
-
});
|
|
19079
|
+
importLines.push({ start: getLineNumber(node.getStart(sourceFile)), end: getLineNumber(node.getEnd()) });
|
|
19078
19080
|
return;
|
|
19079
19081
|
}
|
|
19080
19082
|
if (ts.isFunctionDeclaration(node)) {
|
|
19081
|
-
chunks.push({
|
|
19082
|
-
kind: "function",
|
|
19083
|
-
name: getName(node),
|
|
19084
|
-
text: getNodeText(node),
|
|
19085
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
19086
|
-
endLine: getLineNumber(node.getEnd()),
|
|
19087
|
-
comment: getLeadingComment(node)
|
|
19088
|
-
});
|
|
19083
|
+
chunks.push({ kind: "function", name: getName(node), text: getNodeText(node), startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()), comment: getLeadingComment(node) });
|
|
19089
19084
|
return;
|
|
19090
19085
|
}
|
|
19091
19086
|
if (ts.isClassDeclaration(node)) {
|
|
19092
|
-
chunks.push({
|
|
19093
|
-
kind: "class",
|
|
19094
|
-
name: getName(node),
|
|
19095
|
-
text: getNodeText(node),
|
|
19096
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
19097
|
-
endLine: getLineNumber(node.getEnd()),
|
|
19098
|
-
comment: getLeadingComment(node)
|
|
19099
|
-
});
|
|
19100
|
-
return;
|
|
19101
|
-
}
|
|
19102
|
-
if (ts.isInterfaceDeclaration(node)) {
|
|
19103
|
-
chunks.push({
|
|
19104
|
-
kind: "type",
|
|
19105
|
-
name: getName(node),
|
|
19106
|
-
text: getNodeText(node),
|
|
19107
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
19108
|
-
endLine: getLineNumber(node.getEnd()),
|
|
19109
|
-
comment: getLeadingComment(node)
|
|
19110
|
-
});
|
|
19087
|
+
chunks.push({ kind: "class", name: getName(node), text: getNodeText(node), startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()), comment: getLeadingComment(node) });
|
|
19111
19088
|
return;
|
|
19112
19089
|
}
|
|
19113
|
-
if (ts.isTypeAliasDeclaration(node)) {
|
|
19114
|
-
chunks.push({
|
|
19115
|
-
kind: "type",
|
|
19116
|
-
name: getName(node),
|
|
19117
|
-
text: getNodeText(node),
|
|
19118
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
19119
|
-
endLine: getLineNumber(node.getEnd()),
|
|
19120
|
-
comment: getLeadingComment(node)
|
|
19121
|
-
});
|
|
19122
|
-
return;
|
|
19123
|
-
}
|
|
19124
|
-
if (ts.isEnumDeclaration(node)) {
|
|
19125
|
-
chunks.push({
|
|
19126
|
-
kind: "type",
|
|
19127
|
-
name: getName(node),
|
|
19128
|
-
text: getNodeText(node),
|
|
19129
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
19130
|
-
endLine: getLineNumber(node.getEnd()),
|
|
19131
|
-
comment: getLeadingComment(node)
|
|
19132
|
-
});
|
|
19090
|
+
if (ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isEnumDeclaration(node)) {
|
|
19091
|
+
chunks.push({ kind: "type", name: getName(node), text: getNodeText(node), startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()), comment: getLeadingComment(node) });
|
|
19133
19092
|
return;
|
|
19134
19093
|
}
|
|
19135
19094
|
if (ts.isVariableStatement(node)) {
|
|
19136
|
-
const
|
|
19137
|
-
|
|
19138
|
-
(d) => d.initializer && (ts.isArrowFunction(d.initializer) || ts.isFunctionExpression(d.initializer))
|
|
19139
|
-
);
|
|
19140
|
-
chunks.push({
|
|
19141
|
-
kind: isFnLike ? "function" : "variable",
|
|
19142
|
-
name: getName(node),
|
|
19143
|
-
text: getNodeText(node),
|
|
19144
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
19145
|
-
endLine: getLineNumber(node.getEnd()),
|
|
19146
|
-
comment: getLeadingComment(node)
|
|
19147
|
-
});
|
|
19095
|
+
const isFnLike = node.declarationList.declarations.some((d) => d.initializer && (ts.isArrowFunction(d.initializer) || ts.isFunctionExpression(d.initializer)));
|
|
19096
|
+
chunks.push({ kind: isFnLike ? "function" : "variable", name: getName(node), text: getNodeText(node), startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()), comment: getLeadingComment(node) });
|
|
19148
19097
|
return;
|
|
19149
19098
|
}
|
|
19150
19099
|
if (ts.isExportAssignment(node)) {
|
|
19151
|
-
chunks.push({
|
|
19152
|
-
kind: "export",
|
|
19153
|
-
name: "default export",
|
|
19154
|
-
text: getNodeText(node),
|
|
19155
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
19156
|
-
endLine: getLineNumber(node.getEnd()),
|
|
19157
|
-
comment: getLeadingComment(node)
|
|
19158
|
-
});
|
|
19100
|
+
chunks.push({ kind: "export", name: "default export", text: getNodeText(node), startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()), comment: getLeadingComment(node) });
|
|
19159
19101
|
return;
|
|
19160
19102
|
}
|
|
19161
19103
|
if (ts.isExpressionStatement(node)) {
|
|
19162
19104
|
const text3 = getNodeText(node);
|
|
19163
|
-
if (text3.length > 10) {
|
|
19164
|
-
chunks.push({
|
|
19165
|
-
kind: "other",
|
|
19166
|
-
name: text3.slice(0, 40).replace(/\n/g, " "),
|
|
19167
|
-
text: text3,
|
|
19168
|
-
startLine: getLineNumber(node.getStart(sourceFile)),
|
|
19169
|
-
endLine: getLineNumber(node.getEnd())
|
|
19170
|
-
});
|
|
19171
|
-
}
|
|
19172
|
-
return;
|
|
19105
|
+
if (text3.length > 10) chunks.push({ kind: "other", name: text3.slice(0, 40).replace(/\n/g, " "), text: text3, startLine: getLineNumber(node.getStart(sourceFile)), endLine: getLineNumber(node.getEnd()) });
|
|
19173
19106
|
}
|
|
19174
19107
|
}
|
|
19175
19108
|
sourceFile.statements.forEach(visitTopLevel);
|
|
19176
19109
|
if (importLines.length > 0) {
|
|
19177
19110
|
const startLine = importLines[0].start;
|
|
19178
19111
|
const endLine = importLines[importLines.length - 1].end;
|
|
19179
|
-
|
|
19180
|
-
|
|
19181
|
-
|
|
19182
|
-
|
|
19183
|
-
|
|
19184
|
-
|
|
19112
|
+
chunks.unshift({ kind: "import", name: `${importLines.length} imports`, text: lines.slice(startLine - 1, endLine).join("\n"), startLine, endLine });
|
|
19113
|
+
}
|
|
19114
|
+
chunks.sort((a, b) => a.startLine - b.startLine);
|
|
19115
|
+
return chunks.length > 0 ? chunks : chunkByWindows(source, 80);
|
|
19116
|
+
}
|
|
19117
|
+
function chunkGenericSource(source, _fileName, language) {
|
|
19118
|
+
const lines = source.split("\n");
|
|
19119
|
+
if (source.trim().length === 0) return [];
|
|
19120
|
+
if (language && TEXT_LIKE_LANGUAGES.has(language)) return chunkTextLike(lines, language);
|
|
19121
|
+
const chunks = [];
|
|
19122
|
+
const patterns = [
|
|
19123
|
+
{ kind: "function", regex: /^\s*(?:async\s+)?def\s+([A-Za-z_][\w]*)\s*\(/, name: (m) => m[1] },
|
|
19124
|
+
{ kind: "class", regex: /^\s*class\s+([A-Za-z_][\w]*)\b/, name: (m) => m[1] },
|
|
19125
|
+
{ kind: "function", regex: /^\s*(?:pub\s+)?fn\s+([A-Za-z_][\w]*)\s*[<(]/, name: (m) => m[1] },
|
|
19126
|
+
{ kind: "class", regex: /^\s*(?:pub\s+)?(?:struct|enum|trait)\s+([A-Za-z_][\w]*)\b/, name: (m) => m[1] },
|
|
19127
|
+
{ kind: "function", regex: /^\s*func\s+(?:\([^)]*\)\s*)?([A-Za-z_][\w]*)\s*\(/, name: (m) => m[1] },
|
|
19128
|
+
{ kind: "function", regex: /^\s*(?:public|private|protected|static|final|suspend|fun|override|open|internal|export|async|func|function|subroutine)\s+.*?([A-Za-z_][\w]*)\s*\(/, name: (m) => m[1] },
|
|
19129
|
+
{ kind: "function", regex: /^\s*function\s+([A-Za-z_][\w]*)\s*\(/, name: (m) => m[1] },
|
|
19130
|
+
{ kind: "type", regex: /^\s*(?:interface|type|enum|record|data\s+class|case\s+class|contract|library)\s+([A-Za-z_][\w]*)\b/, name: (m) => m[1] },
|
|
19131
|
+
{ kind: "section", regex: /^\s{0,3}#{1,6}\s+(.+)$/, name: (m) => m[1].trim() }
|
|
19132
|
+
];
|
|
19133
|
+
const starts = [];
|
|
19134
|
+
for (let i = 0; i < lines.length; i++) {
|
|
19135
|
+
const line = lines[i];
|
|
19136
|
+
for (const pattern of patterns) {
|
|
19137
|
+
const match = line.match(pattern.regex);
|
|
19138
|
+
if (match) {
|
|
19139
|
+
starts.push({ line: i + 1, kind: pattern.kind, name: pattern.name(match) });
|
|
19140
|
+
break;
|
|
19141
|
+
}
|
|
19142
|
+
}
|
|
19143
|
+
}
|
|
19144
|
+
if (starts.length === 0) return chunkByWindows(source, 80);
|
|
19145
|
+
for (let i = 0; i < starts.length; i++) {
|
|
19146
|
+
const start = starts[i];
|
|
19147
|
+
const next = starts[i + 1]?.line ?? lines.length + 1;
|
|
19148
|
+
const endLine = Math.max(start.line, next - 1);
|
|
19149
|
+
chunks.push({
|
|
19150
|
+
kind: start.kind,
|
|
19151
|
+
name: start.name,
|
|
19152
|
+
text: lines.slice(start.line - 1, endLine).join("\n"),
|
|
19153
|
+
startLine: start.line,
|
|
19185
19154
|
endLine
|
|
19186
19155
|
});
|
|
19187
19156
|
}
|
|
19188
|
-
chunks
|
|
19157
|
+
return chunks;
|
|
19158
|
+
}
|
|
19159
|
+
function chunkTextLike(lines, language) {
|
|
19160
|
+
if (language === "markdown" || language === "mdx") {
|
|
19161
|
+
const starts = lines.map((line, i) => ({ line, i })).filter(({ line }) => /^\s{0,3}#{1,6}\s+/.test(line));
|
|
19162
|
+
if (starts.length > 0) {
|
|
19163
|
+
return starts.map((start, idx) => {
|
|
19164
|
+
const end = starts[idx + 1]?.i ?? lines.length;
|
|
19165
|
+
const title = start.line.replace(/^\s{0,3}#{1,6}\s+/, "").trim();
|
|
19166
|
+
return { kind: "section", name: title, text: lines.slice(start.i, end).join("\n"), startLine: start.i + 1, endLine: end };
|
|
19167
|
+
});
|
|
19168
|
+
}
|
|
19169
|
+
}
|
|
19170
|
+
return chunkByWindows(lines.join("\n"), 80);
|
|
19171
|
+
}
|
|
19172
|
+
function chunkByWindows(source, windowLines) {
|
|
19173
|
+
const lines = source.split("\n");
|
|
19174
|
+
const chunks = [];
|
|
19175
|
+
for (let i = 0; i < lines.length; i += windowLines) {
|
|
19176
|
+
const end = Math.min(lines.length, i + windowLines);
|
|
19177
|
+
const text3 = lines.slice(i, end).join("\n");
|
|
19178
|
+
if (text3.trim()) chunks.push({ kind: "other", name: `lines ${i + 1}-${end}`, text: text3, startLine: i + 1, endLine: end });
|
|
19179
|
+
}
|
|
19189
19180
|
return chunks;
|
|
19190
19181
|
}
|
|
19191
19182
|
function summarizeChunk(chunk, filePath) {
|
|
@@ -19204,17 +19195,69 @@ function summarizeChunk(chunk, filePath) {
|
|
|
19204
19195
|
return `Variable ${chunk.name} in ${location}`;
|
|
19205
19196
|
case "export":
|
|
19206
19197
|
return `Default export in ${location}`;
|
|
19198
|
+
case "section":
|
|
19199
|
+
return `Section ${chunk.name} in ${location}`;
|
|
19207
19200
|
default:
|
|
19208
19201
|
return `${chunk.kind} in ${location}`;
|
|
19209
19202
|
}
|
|
19210
19203
|
}
|
|
19211
19204
|
function isChunkable(filePath) {
|
|
19212
|
-
|
|
19213
|
-
return ext === "ts" || ext === "tsx" || ext === "js" || ext === "jsx";
|
|
19205
|
+
return Boolean(languageForFile(filePath));
|
|
19214
19206
|
}
|
|
19207
|
+
var LANGUAGE_BY_EXTENSION, TEXT_LIKE_LANGUAGES;
|
|
19215
19208
|
var init_code_chunker = __esm({
|
|
19216
19209
|
"src/lib/code-chunker.ts"() {
|
|
19217
19210
|
"use strict";
|
|
19211
|
+
LANGUAGE_BY_EXTENSION = {
|
|
19212
|
+
c: "c",
|
|
19213
|
+
cc: "cpp",
|
|
19214
|
+
cpp: "cpp",
|
|
19215
|
+
cxx: "cpp",
|
|
19216
|
+
h: "c",
|
|
19217
|
+
hh: "cpp",
|
|
19218
|
+
hpp: "cpp",
|
|
19219
|
+
cs: "csharp",
|
|
19220
|
+
css: "css",
|
|
19221
|
+
scss: "scss",
|
|
19222
|
+
f: "fortran",
|
|
19223
|
+
f90: "fortran",
|
|
19224
|
+
f95: "fortran",
|
|
19225
|
+
go: "go",
|
|
19226
|
+
html: "html",
|
|
19227
|
+
htm: "html",
|
|
19228
|
+
java: "java",
|
|
19229
|
+
js: "javascript",
|
|
19230
|
+
jsx: "javascript",
|
|
19231
|
+
json: "json",
|
|
19232
|
+
kt: "kotlin",
|
|
19233
|
+
kts: "kotlin",
|
|
19234
|
+
lua: "lua",
|
|
19235
|
+
md: "markdown",
|
|
19236
|
+
mdx: "mdx",
|
|
19237
|
+
pas: "pascal",
|
|
19238
|
+
php: "php",
|
|
19239
|
+
py: "python",
|
|
19240
|
+
r: "r",
|
|
19241
|
+
rb: "ruby",
|
|
19242
|
+
rs: "rust",
|
|
19243
|
+
scala: "scala",
|
|
19244
|
+
sc: "scala",
|
|
19245
|
+
sol: "solidity",
|
|
19246
|
+
sql: "sql",
|
|
19247
|
+
svelte: "svelte",
|
|
19248
|
+
swift: "swift",
|
|
19249
|
+
toml: "toml",
|
|
19250
|
+
ts: "typescript",
|
|
19251
|
+
tsx: "typescript",
|
|
19252
|
+
vue: "vue",
|
|
19253
|
+
xml: "xml",
|
|
19254
|
+
yaml: "yaml",
|
|
19255
|
+
yml: "yaml",
|
|
19256
|
+
sh: "shell",
|
|
19257
|
+
bash: "shell",
|
|
19258
|
+
zsh: "shell"
|
|
19259
|
+
};
|
|
19260
|
+
TEXT_LIKE_LANGUAGES = /* @__PURE__ */ new Set(["json", "markdown", "mdx", "toml", "yaml", "xml", "html", "css", "scss", "sql"]);
|
|
19218
19261
|
}
|
|
19219
19262
|
});
|
|
19220
19263
|
|
|
@@ -29989,7 +30032,7 @@ var init_create_bug_report = __esm({
|
|
|
29989
30032
|
// src/lib/code-context-index.ts
|
|
29990
30033
|
import crypto20 from "crypto";
|
|
29991
30034
|
import path54 from "path";
|
|
29992
|
-
import { existsSync as existsSync43, mkdirSync as mkdirSync21, readFileSync as readFileSync35, statSync as statSync10, writeFileSync as writeFileSync24 } from "fs";
|
|
30035
|
+
import { existsSync as existsSync43, mkdirSync as mkdirSync21, readFileSync as readFileSync35, readdirSync as readdirSync14, statSync as statSync10, writeFileSync as writeFileSync24 } from "fs";
|
|
29993
30036
|
import { spawnSync } from "child_process";
|
|
29994
30037
|
function normalizeProjectRoot(projectRoot) {
|
|
29995
30038
|
return path54.resolve(projectRoot || process.cwd());
|
|
@@ -30008,78 +30051,53 @@ function getCodeContextIndexPath(projectRoot) {
|
|
|
30008
30051
|
return path54.join(indexDir(), `${rootHash}.json`);
|
|
30009
30052
|
}
|
|
30010
30053
|
function currentBranch(projectRoot) {
|
|
30011
|
-
const result2 = spawnSync("git", ["branch", "--show-current"], {
|
|
30012
|
-
cwd: projectRoot,
|
|
30013
|
-
encoding: "utf8",
|
|
30014
|
-
timeout: 2e3
|
|
30015
|
-
});
|
|
30054
|
+
const result2 = spawnSync("git", ["branch", "--show-current"], { cwd: projectRoot, encoding: "utf8", timeout: 2e3 });
|
|
30016
30055
|
const branch = result2.status === 0 ? result2.stdout.trim() : "";
|
|
30017
30056
|
return branch || "detached-or-unknown";
|
|
30018
30057
|
}
|
|
30019
30058
|
function shouldIgnore(relPath) {
|
|
30020
|
-
const parts = relPath.split(
|
|
30059
|
+
const parts = relPath.split(/[\\/]/);
|
|
30021
30060
|
return parts.some((part) => IGNORE_SEGMENTS.has(part));
|
|
30022
30061
|
}
|
|
30023
|
-
function
|
|
30024
|
-
|
|
30062
|
+
function listRecursive(projectRoot, dir = projectRoot, out = []) {
|
|
30063
|
+
for (const entry of readdirSync14(dir, { withFileTypes: true })) {
|
|
30064
|
+
const abs = path54.join(dir, entry.name);
|
|
30065
|
+
const rel = path54.relative(projectRoot, abs).replaceAll(path54.sep, "/");
|
|
30066
|
+
if (shouldIgnore(rel)) continue;
|
|
30067
|
+
if (entry.isDirectory()) listRecursive(projectRoot, abs, out);
|
|
30068
|
+
else if (entry.isFile()) out.push(rel);
|
|
30069
|
+
}
|
|
30070
|
+
return out;
|
|
30025
30071
|
}
|
|
30026
30072
|
function listCodeFiles(projectRoot, maxFiles) {
|
|
30027
|
-
const git = spawnSync("git", ["ls-files",
|
|
30028
|
-
cwd: projectRoot,
|
|
30029
|
-
encoding: "utf8",
|
|
30030
|
-
timeout: 5e3,
|
|
30031
|
-
maxBuffer: 1024 * 1024 * 8
|
|
30032
|
-
});
|
|
30073
|
+
const git = spawnSync("git", ["ls-files"], { cwd: projectRoot, encoding: "utf8", timeout: 5e3, maxBuffer: 1024 * 1024 * 16 });
|
|
30033
30074
|
let files = [];
|
|
30034
30075
|
if (git.status === 0 && git.stdout.trim()) {
|
|
30035
30076
|
files = git.stdout.split("\n").map((s) => s.trim()).filter(Boolean);
|
|
30036
30077
|
} else {
|
|
30037
|
-
const rg = spawnSync("rg", ["--files",
|
|
30038
|
-
|
|
30039
|
-
encoding: "utf8",
|
|
30040
|
-
timeout: 5e3,
|
|
30041
|
-
maxBuffer: 1024 * 1024 * 8
|
|
30042
|
-
});
|
|
30043
|
-
if (rg.status === 0 && rg.stdout.trim()) {
|
|
30044
|
-
files = rg.stdout.split("\n").map((s) => s.trim()).filter(Boolean);
|
|
30045
|
-
}
|
|
30078
|
+
const rg = spawnSync("rg", ["--files"], { cwd: projectRoot, encoding: "utf8", timeout: 5e3, maxBuffer: 1024 * 1024 * 16 });
|
|
30079
|
+
files = rg.status === 0 && rg.stdout.trim() ? rg.stdout.split("\n").map((s) => s.trim()).filter(Boolean) : listRecursive(projectRoot);
|
|
30046
30080
|
}
|
|
30047
|
-
return files.filter((file) =>
|
|
30081
|
+
return files.map((file) => file.replaceAll(path54.sep, "/")).filter((file) => isChunkable(file) && !shouldIgnore(file)).slice(0, maxFiles).sort();
|
|
30048
30082
|
}
|
|
30049
30083
|
function parseImportPaths2(importText) {
|
|
30050
30084
|
const paths = [];
|
|
30051
|
-
const
|
|
30052
|
-
|
|
30053
|
-
|
|
30054
|
-
|
|
30055
|
-
while ((match = bareRegex.exec(importText)) !== null) {
|
|
30056
|
-
if (!paths.includes(match[1])) paths.push(match[1]);
|
|
30057
|
-
}
|
|
30058
|
-
const requireRegex = /require\(["']([^"']+)["']\)/g;
|
|
30059
|
-
while ((match = requireRegex.exec(importText)) !== null) {
|
|
30060
|
-
if (!paths.includes(match[1])) paths.push(match[1]);
|
|
30085
|
+
const patterns = [/from\s+["']([^"']+)["']/g, /^import\s+["']([^"']+)["']/gm, /require\(["']([^"']+)["']\)/g, /use\s+([A-Za-z0-9_:]+)::/g, /#include\s+[<"]([^>"]+)[>"]/g];
|
|
30086
|
+
for (const regex of patterns) {
|
|
30087
|
+
let match;
|
|
30088
|
+
while ((match = regex.exec(importText)) !== null) if (!paths.includes(match[1])) paths.push(match[1]);
|
|
30061
30089
|
}
|
|
30062
30090
|
return paths;
|
|
30063
30091
|
}
|
|
30064
30092
|
function resolveImport(fromFile, importPath, allFiles) {
|
|
30065
30093
|
if (!importPath.startsWith(".")) return null;
|
|
30066
30094
|
const base = path54.posix.normalize(path54.posix.join(path54.posix.dirname(fromFile.replaceAll(path54.sep, "/")), importPath));
|
|
30067
|
-
const withoutKnownExt = base.replace(/\.(?:
|
|
30068
|
-
const candidates = [
|
|
30069
|
-
|
|
30070
|
-
`${withoutKnownExt}
|
|
30071
|
-
|
|
30072
|
-
|
|
30073
|
-
`${withoutKnownExt}.jsx`,
|
|
30074
|
-
`${base}.ts`,
|
|
30075
|
-
`${base}.tsx`,
|
|
30076
|
-
`${base}.js`,
|
|
30077
|
-
`${base}.jsx`,
|
|
30078
|
-
path54.posix.join(base, "index.ts"),
|
|
30079
|
-
path54.posix.join(base, "index.tsx"),
|
|
30080
|
-
path54.posix.join(base, "index.js"),
|
|
30081
|
-
path54.posix.join(base, "index.jsx")
|
|
30082
|
-
];
|
|
30095
|
+
const withoutKnownExt = base.replace(/\.(?:[a-z0-9]+)$/i, "");
|
|
30096
|
+
const candidates = [base];
|
|
30097
|
+
for (const ext of ["ts", "tsx", "js", "jsx", "py", "rs", "go", "java", "cs", "cpp", "c", "rb", "php", "swift", "kt", "scala", "sql", "md", "json", "yaml", "yml"]) {
|
|
30098
|
+
candidates.push(`${withoutKnownExt}.${ext}`, `${base}.${ext}`);
|
|
30099
|
+
}
|
|
30100
|
+
for (const indexName of ["index.ts", "index.tsx", "index.js", "mod.rs", "__init__.py"]) candidates.push(path54.posix.join(base, indexName));
|
|
30083
30101
|
return candidates.find((candidate) => allFiles.has(candidate)) ?? null;
|
|
30084
30102
|
}
|
|
30085
30103
|
function symbolId(filePath, chunk) {
|
|
@@ -30105,39 +30123,32 @@ function buildFileRecord(projectRoot, relPath, allFiles, previous) {
|
|
|
30105
30123
|
try {
|
|
30106
30124
|
stat = statSync10(absPath);
|
|
30107
30125
|
} catch {
|
|
30108
|
-
return null;
|
|
30126
|
+
return { record: null, reused: false };
|
|
30109
30127
|
}
|
|
30110
|
-
if (!stat.isFile()) return null;
|
|
30128
|
+
if (!stat.isFile()) return { record: null, reused: false };
|
|
30129
|
+
const language = languageForFile(relPath);
|
|
30130
|
+
if (!language || !isChunkable(relPath)) return { record: null, reused: false };
|
|
30111
30131
|
const source = readFileSync35(absPath, "utf8");
|
|
30112
30132
|
const hash = hashText(source);
|
|
30113
|
-
if (previous && previous.hash === hash && previous.mtimeMs === stat.mtimeMs && previous.size === stat.size) {
|
|
30114
|
-
return previous;
|
|
30133
|
+
if (previous && previous.hash === hash && previous.mtimeMs === stat.mtimeMs && previous.size === stat.size && previous.language === language) {
|
|
30134
|
+
return { record: previous, reused: true };
|
|
30115
30135
|
}
|
|
30116
|
-
if (!isChunkable(relPath)) return null;
|
|
30117
30136
|
const chunks = chunkSourceFile(source, relPath);
|
|
30118
30137
|
const imports = chunks.filter((chunk) => chunk.kind === "import").flatMap((chunk) => parseImportPaths2(chunk.text));
|
|
30119
30138
|
const resolvedImports = imports.map((importPath) => resolveImport(relPath, importPath, allFiles)).filter((file) => Boolean(file));
|
|
30120
|
-
const symbols = chunks.filter((chunk) => chunk.
|
|
30139
|
+
const symbols = chunks.filter((chunk) => chunk.name !== "(unknown)").map((chunk) => ({
|
|
30121
30140
|
id: symbolId(relPath, chunk),
|
|
30122
30141
|
name: chunk.name,
|
|
30123
30142
|
kind: chunk.kind,
|
|
30124
30143
|
filePath: relPath,
|
|
30144
|
+
language,
|
|
30125
30145
|
startLine: chunk.startLine,
|
|
30126
30146
|
endLine: chunk.endLine,
|
|
30127
30147
|
summary: summarizeChunk(chunk, relPath),
|
|
30128
|
-
text: chunk.text.slice(0,
|
|
30148
|
+
text: chunk.text.slice(0, 8e3),
|
|
30129
30149
|
comment: chunk.comment
|
|
30130
30150
|
}));
|
|
30131
|
-
return {
|
|
30132
|
-
path: relPath,
|
|
30133
|
-
absPath,
|
|
30134
|
-
hash,
|
|
30135
|
-
mtimeMs: stat.mtimeMs,
|
|
30136
|
-
size: stat.size,
|
|
30137
|
-
imports,
|
|
30138
|
-
resolvedImports,
|
|
30139
|
-
symbols
|
|
30140
|
-
};
|
|
30151
|
+
return { record: { path: relPath, absPath, language, hash, mtimeMs: stat.mtimeMs, size: stat.size, imports, resolvedImports, symbols }, reused: false };
|
|
30141
30152
|
}
|
|
30142
30153
|
function buildCodeContextIndex(options = {}) {
|
|
30143
30154
|
const projectRoot = normalizeProjectRoot(options.projectRoot);
|
|
@@ -30147,17 +30158,27 @@ function buildCodeContextIndex(options = {}) {
|
|
|
30147
30158
|
const files = listCodeFiles(projectRoot, maxFiles);
|
|
30148
30159
|
const allFiles = new Set(files.map((file) => file.replaceAll(path54.sep, "/")));
|
|
30149
30160
|
const fileRecords = {};
|
|
30161
|
+
let rebuiltFiles = 0;
|
|
30162
|
+
let reusedFiles = 0;
|
|
30163
|
+
let skippedFiles = 0;
|
|
30150
30164
|
for (const rel of files) {
|
|
30151
30165
|
const normalized = rel.replaceAll(path54.sep, "/");
|
|
30152
|
-
const record = buildFileRecord(projectRoot, normalized, allFiles, previous?.files[normalized]);
|
|
30153
|
-
if (record)
|
|
30154
|
-
|
|
30166
|
+
const { record, reused } = buildFileRecord(projectRoot, normalized, allFiles, previous?.files[normalized]);
|
|
30167
|
+
if (record) {
|
|
30168
|
+
fileRecords[normalized] = record;
|
|
30169
|
+
if (reused) reusedFiles++;
|
|
30170
|
+
else rebuiltFiles++;
|
|
30171
|
+
} else skippedFiles++;
|
|
30172
|
+
}
|
|
30173
|
+
const languageBreakdown = {};
|
|
30174
|
+
for (const file of Object.values(fileRecords)) languageBreakdown[file.language] = (languageBreakdown[file.language] ?? 0) + 1;
|
|
30155
30175
|
const index = {
|
|
30156
30176
|
version: INDEX_VERSION,
|
|
30157
30177
|
projectRoot,
|
|
30158
30178
|
rootHash: hashText(projectRoot).slice(0, 16),
|
|
30159
30179
|
branch,
|
|
30160
30180
|
indexedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
30181
|
+
stats: { filesSeen: files.length, filesIndexed: Object.keys(fileRecords).length, rebuiltFiles, reusedFiles, skippedFiles, languageBreakdown },
|
|
30161
30182
|
files: fileRecords
|
|
30162
30183
|
};
|
|
30163
30184
|
saveIndex(index);
|
|
@@ -30185,13 +30206,60 @@ function loadOrBuildCodeContextIndex(options = {}) {
|
|
|
30185
30206
|
}
|
|
30186
30207
|
return buildCodeContextIndex(options);
|
|
30187
30208
|
}
|
|
30209
|
+
function normalizeLanguage(language) {
|
|
30210
|
+
return language.toLowerCase().replace(/^c\+\+$/, "cpp").replace(/^c#$/, "csharp").replace(/^js$/, "javascript").replace(/^ts$/, "typescript");
|
|
30211
|
+
}
|
|
30188
30212
|
function tokenize(query) {
|
|
30189
|
-
|
|
30213
|
+
const raw = query.toLowerCase().replace(/([a-z])([A-Z])/g, "$1 $2").split(/[^a-z0-9_.$/-]+/).map((s) => s.trim()).filter((s) => s.length >= 2);
|
|
30214
|
+
const expanded = /* @__PURE__ */ new Set();
|
|
30215
|
+
for (const term of raw) {
|
|
30216
|
+
expanded.add(term);
|
|
30217
|
+
for (const part of term.split(/[_.$/-]+/)) if (part.length >= 2) expanded.add(part);
|
|
30218
|
+
const dashed = term.replace(/[_.$/]+/g, "-");
|
|
30219
|
+
if (dashed.length >= 2) expanded.add(dashed);
|
|
30220
|
+
if (!term.includes("-")) expanded.add(`${term}s`);
|
|
30221
|
+
if (term.endsWith("s") && term.length > 3) expanded.add(term.slice(0, -1));
|
|
30222
|
+
}
|
|
30223
|
+
return [...expanded];
|
|
30224
|
+
}
|
|
30225
|
+
function ngrams(terms) {
|
|
30226
|
+
const grams = [...terms];
|
|
30227
|
+
for (let i = 0; i < terms.length - 1; i++) grams.push(`${terms[i]} ${terms[i + 1]}`);
|
|
30228
|
+
return grams;
|
|
30229
|
+
}
|
|
30230
|
+
function globToRegex(pattern) {
|
|
30231
|
+
let out = "";
|
|
30232
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
30233
|
+
const ch = pattern[i];
|
|
30234
|
+
const next = pattern[i + 1];
|
|
30235
|
+
if (ch === "*" && next === "*") {
|
|
30236
|
+
out += ".*";
|
|
30237
|
+
i++;
|
|
30238
|
+
continue;
|
|
30239
|
+
}
|
|
30240
|
+
if (ch === "*") {
|
|
30241
|
+
out += "[^/]*";
|
|
30242
|
+
continue;
|
|
30243
|
+
}
|
|
30244
|
+
if (".+^${}()|[]\\".includes(ch)) out += `\\${ch}`;
|
|
30245
|
+
else out += ch;
|
|
30246
|
+
}
|
|
30247
|
+
return new RegExp(`^${out}$`);
|
|
30248
|
+
}
|
|
30249
|
+
function matchesPath(filePath, patterns) {
|
|
30250
|
+
if (!patterns || patterns.length === 0) return true;
|
|
30251
|
+
const normalized = filePath.replaceAll(path54.sep, "/");
|
|
30252
|
+
return patterns.some((pattern) => {
|
|
30253
|
+
const p = pattern.replaceAll(path54.sep, "/").replace(/^\.\//, "");
|
|
30254
|
+
return normalized === p || normalized.startsWith(`${p}/`) || normalized.endsWith(p) || globToRegex(p).test(normalized);
|
|
30255
|
+
});
|
|
30190
30256
|
}
|
|
30191
30257
|
function scoreSymbol(symbol, terms) {
|
|
30258
|
+
const grams = ngrams(terms);
|
|
30192
30259
|
const haystacks = {
|
|
30193
30260
|
name: symbol.name.toLowerCase(),
|
|
30194
30261
|
path: symbol.filePath.toLowerCase(),
|
|
30262
|
+
language: symbol.language.toLowerCase(),
|
|
30195
30263
|
summary: symbol.summary.toLowerCase(),
|
|
30196
30264
|
text: symbol.text.toLowerCase()
|
|
30197
30265
|
};
|
|
@@ -30199,41 +30267,73 @@ function scoreSymbol(symbol, terms) {
|
|
|
30199
30267
|
const matches = [];
|
|
30200
30268
|
for (const term of terms) {
|
|
30201
30269
|
if (haystacks.name === term) {
|
|
30202
|
-
score +=
|
|
30270
|
+
score += 100;
|
|
30203
30271
|
matches.push(`name=${term}`);
|
|
30204
30272
|
continue;
|
|
30205
30273
|
}
|
|
30206
30274
|
if (haystacks.name.includes(term)) {
|
|
30207
|
-
score +=
|
|
30275
|
+
score += 45;
|
|
30208
30276
|
matches.push(`name~${term}`);
|
|
30209
30277
|
}
|
|
30210
30278
|
if (haystacks.path.includes(term)) {
|
|
30211
|
-
score +=
|
|
30279
|
+
score += 18;
|
|
30212
30280
|
matches.push(`path~${term}`);
|
|
30213
30281
|
}
|
|
30282
|
+
if (haystacks.language === term) {
|
|
30283
|
+
score += 18;
|
|
30284
|
+
matches.push(`language=${term}`);
|
|
30285
|
+
}
|
|
30214
30286
|
if (haystacks.summary.includes(term)) {
|
|
30215
|
-
score +=
|
|
30287
|
+
score += 16;
|
|
30216
30288
|
matches.push(`summary~${term}`);
|
|
30217
30289
|
}
|
|
30218
30290
|
if (haystacks.text.includes(term)) {
|
|
30219
|
-
score +=
|
|
30291
|
+
score += 5;
|
|
30220
30292
|
matches.push(`text~${term}`);
|
|
30221
30293
|
}
|
|
30222
30294
|
}
|
|
30295
|
+
for (const gram of grams.filter((g) => g.includes(" "))) {
|
|
30296
|
+
if (haystacks.text.includes(gram) || haystacks.summary.includes(gram)) {
|
|
30297
|
+
score += 20;
|
|
30298
|
+
matches.push(`phrase~${gram}`);
|
|
30299
|
+
}
|
|
30300
|
+
}
|
|
30301
|
+
const uniqueMatches = new Set(matches.map((m) => m.replace(/^[^=~]+[=~]/, ""))).size;
|
|
30302
|
+
score += uniqueMatches * 3;
|
|
30223
30303
|
return { score, matches };
|
|
30224
30304
|
}
|
|
30305
|
+
function filteredFiles(index, options = {}) {
|
|
30306
|
+
const languages = options.languages?.map(normalizeLanguage).filter(Boolean);
|
|
30307
|
+
return Object.values(index.files).filter((file) => {
|
|
30308
|
+
if (languages && languages.length > 0 && !languages.includes(normalizeLanguage(file.language))) return false;
|
|
30309
|
+
return matchesPath(file.path, options.paths);
|
|
30310
|
+
});
|
|
30311
|
+
}
|
|
30225
30312
|
function searchCodeContext(query, options = {}) {
|
|
30226
30313
|
const terms = tokenize(query);
|
|
30227
30314
|
if (terms.length === 0) return [];
|
|
30228
|
-
const index = loadOrBuildCodeContextIndex(options);
|
|
30315
|
+
const index = loadOrBuildCodeContextIndex({ projectRoot: options.projectRoot, force: options.force || options.refreshIndex, maxFiles: options.maxFiles });
|
|
30229
30316
|
const results = [];
|
|
30230
|
-
for (const file of
|
|
30317
|
+
for (const file of filteredFiles(index, options)) {
|
|
30231
30318
|
for (const symbol of file.symbols) {
|
|
30232
30319
|
const scored = scoreSymbol(symbol, terms);
|
|
30233
|
-
if (scored.score > 0)
|
|
30320
|
+
if (scored.score > 0) {
|
|
30321
|
+
results.push({
|
|
30322
|
+
symbol,
|
|
30323
|
+
score: scored.score,
|
|
30324
|
+
matches: scored.matches,
|
|
30325
|
+
filePath: symbol.filePath,
|
|
30326
|
+
language: symbol.language,
|
|
30327
|
+
content: symbol.text,
|
|
30328
|
+
startLine: symbol.startLine,
|
|
30329
|
+
endLine: symbol.endLine
|
|
30330
|
+
});
|
|
30331
|
+
}
|
|
30234
30332
|
}
|
|
30235
30333
|
}
|
|
30236
|
-
|
|
30334
|
+
const offset = Math.max(0, options.offset ?? 0);
|
|
30335
|
+
const limit = options.limit ?? 20;
|
|
30336
|
+
return results.sort((a, b) => b.score - a.score || a.filePath.localeCompare(b.filePath)).slice(offset, offset + limit);
|
|
30237
30337
|
}
|
|
30238
30338
|
function dependentsMap(index) {
|
|
30239
30339
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -30261,19 +30361,10 @@ function traceCodeSymbol(symbolName, options = {}) {
|
|
|
30261
30361
|
const index = loadOrBuildCodeContextIndex(options);
|
|
30262
30362
|
const matches = findSymbols(index, symbolName, options.limit ?? 20);
|
|
30263
30363
|
const dependents = dependentsMap(index);
|
|
30264
|
-
return {
|
|
30265
|
-
|
|
30266
|
-
|
|
30267
|
-
|
|
30268
|
-
const file = index.files[symbol.filePath];
|
|
30269
|
-
return {
|
|
30270
|
-
symbol,
|
|
30271
|
-
imports: file.resolvedImports,
|
|
30272
|
-
dependents: [...dependents.get(symbol.filePath) ?? /* @__PURE__ */ new Set()].sort(),
|
|
30273
|
-
relatedSymbols: file.symbols.filter((s) => s.id !== symbol.id).slice(0, 20)
|
|
30274
|
-
};
|
|
30275
|
-
})
|
|
30276
|
-
};
|
|
30364
|
+
return { query: symbolName, matches, definitions: matches.map((symbol) => {
|
|
30365
|
+
const file = index.files[symbol.filePath];
|
|
30366
|
+
return { symbol, imports: file.resolvedImports, dependents: [...dependents.get(symbol.filePath) ?? /* @__PURE__ */ new Set()].sort(), relatedSymbols: file.symbols.filter((s) => s.id !== symbol.id).slice(0, 20) };
|
|
30367
|
+
}) };
|
|
30277
30368
|
}
|
|
30278
30369
|
function resolveTargetFile(index, input) {
|
|
30279
30370
|
if (input.filePath) {
|
|
@@ -30313,20 +30404,10 @@ function analyzeBlastRadius(input) {
|
|
|
30313
30404
|
const lower = file.toLowerCase();
|
|
30314
30405
|
return (lower.includes("test") || lower.includes("spec")) && (lower.includes(targetBase) || (symbolLower ? index.files[file].symbols.some((s) => s.text.toLowerCase().includes(symbolLower)) : false));
|
|
30315
30406
|
});
|
|
30316
|
-
for (const test of tests) {
|
|
30317
|
-
if (!impacted.has(test)) impacted.set(test, { distance: 1, reason: "related test/spec" });
|
|
30318
|
-
}
|
|
30407
|
+
for (const test of tests) if (!impacted.has(test)) impacted.set(test, { distance: 1, reason: "related test/spec" });
|
|
30319
30408
|
const impactedFiles = [...impacted.entries()].map(([filePath, value]) => ({ filePath, distance: value.distance, reason: value.reason })).sort((a, b) => a.distance - b.distance || a.filePath.localeCompare(b.filePath));
|
|
30320
30409
|
const nonTestImpacted = impactedFiles.filter((f) => !f.filePath.match(/(test|spec)\./i)).length;
|
|
30321
|
-
|
|
30322
|
-
return {
|
|
30323
|
-
target: target.target,
|
|
30324
|
-
targetFile: target.filePath,
|
|
30325
|
-
impactedFiles,
|
|
30326
|
-
tests,
|
|
30327
|
-
symbolsInTarget: index.files[target.filePath]?.symbols ?? [],
|
|
30328
|
-
riskLevel
|
|
30329
|
-
};
|
|
30410
|
+
return { target: target.target, targetFile: target.filePath, impactedFiles, tests, symbolsInTarget: index.files[target.filePath]?.symbols ?? [], riskLevel: nonTestImpacted >= 8 ? "high" : nonTestImpacted >= 4 ? "medium" : "low" };
|
|
30330
30411
|
}
|
|
30331
30412
|
function getCodeContextStats(options = {}) {
|
|
30332
30413
|
const index = loadOrBuildCodeContextIndex(options);
|
|
@@ -30334,22 +30415,26 @@ function getCodeContextStats(options = {}) {
|
|
|
30334
30415
|
projectRoot: index.projectRoot,
|
|
30335
30416
|
branch: index.branch,
|
|
30336
30417
|
indexedAt: index.indexedAt,
|
|
30418
|
+
indexAgeMs: Math.max(0, Date.now() - Date.parse(index.indexedAt)),
|
|
30337
30419
|
files: Object.keys(index.files).length,
|
|
30338
30420
|
symbols: Object.values(index.files).reduce((sum, file) => sum + file.symbols.length, 0),
|
|
30339
30421
|
imports: Object.values(index.files).reduce((sum, file) => sum + file.resolvedImports.length, 0),
|
|
30422
|
+
languageBreakdown: index.stats.languageBreakdown,
|
|
30423
|
+
rebuiltFiles: index.stats.rebuiltFiles,
|
|
30424
|
+
reusedFiles: index.stats.reusedFiles,
|
|
30425
|
+
skippedFiles: index.stats.skippedFiles,
|
|
30340
30426
|
indexPath: getCodeContextIndexPath(index.projectRoot)
|
|
30341
30427
|
};
|
|
30342
30428
|
}
|
|
30343
|
-
var INDEX_VERSION, DEFAULT_MAX_FILES,
|
|
30429
|
+
var INDEX_VERSION, DEFAULT_MAX_FILES, IGNORE_SEGMENTS;
|
|
30344
30430
|
var init_code_context_index = __esm({
|
|
30345
30431
|
"src/lib/code-context-index.ts"() {
|
|
30346
30432
|
"use strict";
|
|
30347
30433
|
init_config();
|
|
30348
30434
|
init_code_chunker();
|
|
30349
|
-
INDEX_VERSION =
|
|
30350
|
-
DEFAULT_MAX_FILES =
|
|
30351
|
-
|
|
30352
|
-
IGNORE_SEGMENTS = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", "coverage", ".worktrees", ".next", "build"]);
|
|
30435
|
+
INDEX_VERSION = 2;
|
|
30436
|
+
DEFAULT_MAX_FILES = 5e3;
|
|
30437
|
+
IGNORE_SEGMENTS = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", "coverage", ".worktrees", ".next", "build", "target", "vendor"]);
|
|
30353
30438
|
}
|
|
30354
30439
|
});
|
|
30355
30440
|
|
|
@@ -30373,10 +30458,14 @@ function registerCodeContext(server) {
|
|
|
30373
30458
|
file_path: z88.string().optional().describe("File path for blast_radius"),
|
|
30374
30459
|
force: z88.boolean().optional().describe("Force rebuild before answering"),
|
|
30375
30460
|
limit: z88.coerce.number().int().min(1).max(100).optional().describe("Max results"),
|
|
30461
|
+
offset: z88.coerce.number().int().min(0).optional().describe("Search pagination offset"),
|
|
30462
|
+
refresh_index: z88.boolean().optional().describe("Refresh/rebuild index before searching"),
|
|
30463
|
+
languages: z88.array(z88.string()).optional().describe('Language filters, e.g. ["python", "typescript"]'),
|
|
30464
|
+
paths: z88.array(z88.string()).optional().describe("Path/glob filters"),
|
|
30376
30465
|
depth: z88.coerce.number().int().min(1).max(5).optional().describe("Dependent traversal depth for blast_radius"),
|
|
30377
30466
|
max_files: z88.coerce.number().int().min(1).max(1e4).optional().describe("Max code files to index")
|
|
30378
30467
|
}
|
|
30379
|
-
}, async ({ action, project_root, query, symbol, file_path, force, limit, depth, max_files }) => {
|
|
30468
|
+
}, async ({ action, project_root, query, symbol, file_path, force, limit, offset, refresh_index, languages, paths, depth, max_files }) => {
|
|
30380
30469
|
const opts = { projectRoot: project_root, force, maxFiles: max_files };
|
|
30381
30470
|
if (action === "index") {
|
|
30382
30471
|
const index = buildCodeContextIndex(opts);
|
|
@@ -30394,7 +30483,15 @@ function registerCodeContext(server) {
|
|
|
30394
30483
|
}
|
|
30395
30484
|
if (action === "search") {
|
|
30396
30485
|
if (!query) return errorResult10('code_context action "search" requires query');
|
|
30397
|
-
return jsonResult({
|
|
30486
|
+
return jsonResult({
|
|
30487
|
+
query,
|
|
30488
|
+
limit: limit ?? 20,
|
|
30489
|
+
offset: offset ?? 0,
|
|
30490
|
+
refresh_index: refresh_index ?? false,
|
|
30491
|
+
languages: languages ?? [],
|
|
30492
|
+
paths: paths ?? [],
|
|
30493
|
+
results: searchCodeContext(query, { ...opts, limit, offset, refreshIndex: refresh_index, languages, paths })
|
|
30494
|
+
});
|
|
30398
30495
|
}
|
|
30399
30496
|
if (action === "trace") {
|
|
30400
30497
|
if (!symbol) return errorResult10('code_context action "trace" requires symbol');
|
|
@@ -32139,6 +32236,7 @@ var DAEMON_TOKEN_ENV2 = "EXE_DAEMON_TOKEN";
|
|
|
32139
32236
|
var _context = null;
|
|
32140
32237
|
var _model = null;
|
|
32141
32238
|
var _llama = null;
|
|
32239
|
+
var _shuttingDown = false;
|
|
32142
32240
|
var _daemonToken = "";
|
|
32143
32241
|
var MAX_QUEUE_SIZE = 1e3;
|
|
32144
32242
|
var highQueue = [];
|
|
@@ -32240,6 +32338,8 @@ function checkIdle() {
|
|
|
32240
32338
|
}
|
|
32241
32339
|
}
|
|
32242
32340
|
async function shutdown() {
|
|
32341
|
+
if (_shuttingDown) return;
|
|
32342
|
+
_shuttingDown = true;
|
|
32243
32343
|
resetIdleTimer2();
|
|
32244
32344
|
flushToDisk();
|
|
32245
32345
|
try {
|
|
@@ -32252,6 +32352,19 @@ async function shutdown() {
|
|
|
32252
32352
|
disposeShards2();
|
|
32253
32353
|
} catch {
|
|
32254
32354
|
}
|
|
32355
|
+
if (process.platform === "darwin" && _llama) {
|
|
32356
|
+
try {
|
|
32357
|
+
unlinkSync14(SOCKET_PATH2);
|
|
32358
|
+
} catch {
|
|
32359
|
+
}
|
|
32360
|
+
try {
|
|
32361
|
+
unlinkSync14(PID_PATH4);
|
|
32362
|
+
} catch {
|
|
32363
|
+
}
|
|
32364
|
+
process.stderr.write("[exed] Shutdown complete (darwin fast native exit).\n");
|
|
32365
|
+
process.kill(process.pid, "SIGKILL");
|
|
32366
|
+
process.exit(0);
|
|
32367
|
+
}
|
|
32255
32368
|
if (_context) {
|
|
32256
32369
|
try {
|
|
32257
32370
|
await _context.dispose();
|
|
@@ -32266,7 +32379,13 @@ async function shutdown() {
|
|
|
32266
32379
|
}
|
|
32267
32380
|
_model = null;
|
|
32268
32381
|
}
|
|
32269
|
-
_llama
|
|
32382
|
+
if (_llama) {
|
|
32383
|
+
try {
|
|
32384
|
+
await _llama.dispose();
|
|
32385
|
+
} catch {
|
|
32386
|
+
}
|
|
32387
|
+
_llama = null;
|
|
32388
|
+
}
|
|
32270
32389
|
try {
|
|
32271
32390
|
unlinkSync14(SOCKET_PATH2);
|
|
32272
32391
|
} catch {
|
|
@@ -32745,16 +32864,22 @@ async function startMcpHttpServer() {
|
|
|
32745
32864
|
for (const [sid, lastSeen] of sessionLastSeen.entries()) {
|
|
32746
32865
|
if (now2 - lastSeen > MCP_SESSION_TTL_MS) closeMcpSession2(sid, "session_expired");
|
|
32747
32866
|
}
|
|
32748
|
-
},
|
|
32867
|
+
}, getJsonRpcId2 = function(body) {
|
|
32868
|
+
if (body && typeof body === "object" && !Array.isArray(body) && "id" in body) {
|
|
32869
|
+
const id = body.id;
|
|
32870
|
+
if (typeof id === "string" || typeof id === "number") return id;
|
|
32871
|
+
}
|
|
32872
|
+
return "unknown";
|
|
32873
|
+
}, sendJsonRpcError2 = function(res, status, message, id, extra) {
|
|
32749
32874
|
res.writeHead(status, { "Content-Type": "application/json" });
|
|
32750
32875
|
res.end(JSON.stringify({
|
|
32751
32876
|
jsonrpc: "2.0",
|
|
32752
32877
|
error: { code: -32e3, message },
|
|
32753
|
-
id
|
|
32878
|
+
id
|
|
32754
32879
|
}));
|
|
32755
32880
|
recordMcpHttpEvent({ level: "warn", message, status, ...extra });
|
|
32756
32881
|
};
|
|
32757
|
-
var parseDurationMs = parseDurationMs2, closeMcpSession = closeMcpSession2, sweepStaleMcpSessions = sweepStaleMcpSessions2, sendJsonRpcError = sendJsonRpcError2;
|
|
32882
|
+
var parseDurationMs = parseDurationMs2, closeMcpSession = closeMcpSession2, sweepStaleMcpSessions = sweepStaleMcpSessions2, getJsonRpcId = getJsonRpcId2, sendJsonRpcError = sendJsonRpcError2;
|
|
32758
32883
|
const { McpServer } = await import("@modelcontextprotocol/sdk/server/mcp.js");
|
|
32759
32884
|
const { StreamableHTTPServerTransport } = await import("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
32760
32885
|
const { isInitializeRequest } = await import("@modelcontextprotocol/sdk/types.js");
|
|
@@ -32783,14 +32908,14 @@ async function startMcpHttpServer() {
|
|
|
32783
32908
|
const url = new URL(req.url || "/", `http://127.0.0.1:${MCP_HTTP_PORT}`);
|
|
32784
32909
|
const authHeader = req.headers.authorization;
|
|
32785
32910
|
if (!authHeader || authHeader !== `Bearer ${_daemonToken}`) {
|
|
32786
|
-
sendJsonRpcError2(res, 401, "Unauthorized: invalid or missing daemon token", {
|
|
32911
|
+
sendJsonRpcError2(res, 401, "Unauthorized: invalid or missing daemon token", "unknown", {
|
|
32787
32912
|
method: req.method,
|
|
32788
32913
|
path: url.pathname
|
|
32789
32914
|
});
|
|
32790
32915
|
return;
|
|
32791
32916
|
}
|
|
32792
32917
|
if (url.pathname !== "/mcp") {
|
|
32793
|
-
sendJsonRpcError2(res, 404, "Not Found: MCP endpoint is /mcp", {
|
|
32918
|
+
sendJsonRpcError2(res, 404, "Not Found: MCP endpoint is /mcp", "unknown", {
|
|
32794
32919
|
method: req.method,
|
|
32795
32920
|
path: url.pathname
|
|
32796
32921
|
});
|
|
@@ -32814,7 +32939,7 @@ async function startMcpHttpServer() {
|
|
|
32814
32939
|
});
|
|
32815
32940
|
parsedBody = body ? JSON.parse(body) : void 0;
|
|
32816
32941
|
} catch (err) {
|
|
32817
|
-
sendJsonRpcError2(res, 400, "Bad Request: invalid JSON body", {
|
|
32942
|
+
sendJsonRpcError2(res, 400, "Bad Request: invalid JSON body", "unknown", {
|
|
32818
32943
|
method: req.method,
|
|
32819
32944
|
agentId,
|
|
32820
32945
|
agentRole,
|
|
@@ -32855,7 +32980,7 @@ async function startMcpHttpServer() {
|
|
|
32855
32980
|
await sessionMcp.connect(transport);
|
|
32856
32981
|
} else {
|
|
32857
32982
|
const message = sessionId ? "Bad Request: MCP session is stale or unknown; reconnect MCP client" : "Bad Request: missing MCP session; initialize before tool calls";
|
|
32858
|
-
sendJsonRpcError2(res, 400, message, {
|
|
32983
|
+
sendJsonRpcError2(res, 400, message, getJsonRpcId2(parsedBody), {
|
|
32859
32984
|
method: req.method,
|
|
32860
32985
|
hasSessionId: Boolean(sessionId),
|
|
32861
32986
|
sessionId,
|
|
@@ -32914,7 +33039,7 @@ async function startMcpHttpServer() {
|
|
|
32914
33039
|
error: err instanceof Error ? err.message : String(err)
|
|
32915
33040
|
});
|
|
32916
33041
|
if (!res.headersSent) {
|
|
32917
|
-
sendJsonRpcError2(res, 500, "Internal Server Error: MCP request failed", {
|
|
33042
|
+
sendJsonRpcError2(res, 500, "Internal Server Error: MCP request failed", getJsonRpcId2(parsedBody), {
|
|
32918
33043
|
method: req.method,
|
|
32919
33044
|
sessionId,
|
|
32920
33045
|
agentId,
|
|
@@ -33582,8 +33707,31 @@ function startBackgroundJobGuardrails() {
|
|
|
33582
33707
|
timer.unref();
|
|
33583
33708
|
process.stderr.write("[exed] Background job guardrails started (every 60s)\n");
|
|
33584
33709
|
}
|
|
33585
|
-
|
|
33586
|
-
process.
|
|
33710
|
+
function handleSignalShutdown() {
|
|
33711
|
+
if (process.platform === "darwin" && _llama) {
|
|
33712
|
+
if (_shuttingDown) return;
|
|
33713
|
+
_shuttingDown = true;
|
|
33714
|
+
resetIdleTimer2();
|
|
33715
|
+
try {
|
|
33716
|
+
flushToDisk();
|
|
33717
|
+
} catch {
|
|
33718
|
+
}
|
|
33719
|
+
try {
|
|
33720
|
+
unlinkSync14(SOCKET_PATH2);
|
|
33721
|
+
} catch {
|
|
33722
|
+
}
|
|
33723
|
+
try {
|
|
33724
|
+
unlinkSync14(PID_PATH4);
|
|
33725
|
+
} catch {
|
|
33726
|
+
}
|
|
33727
|
+
process.stderr.write("[exed] Shutdown complete (darwin signal fast native exit).\n");
|
|
33728
|
+
process.kill(process.pid, "SIGKILL");
|
|
33729
|
+
process.exit(0);
|
|
33730
|
+
}
|
|
33731
|
+
void shutdown();
|
|
33732
|
+
}
|
|
33733
|
+
process.on("SIGINT", handleSignalShutdown);
|
|
33734
|
+
process.on("SIGTERM", handleSignalShutdown);
|
|
33587
33735
|
function checkExistingDaemon() {
|
|
33588
33736
|
try {
|
|
33589
33737
|
if (!existsSync46(PID_PATH4)) return false;
|