waymark-engine 1.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/LICENSE +21 -0
- package/README.md +96 -0
- package/bin/waymark-ask.mjs +4 -0
- package/bin/waymark-chart.mjs +4 -0
- package/bin/waymark-discover.mjs +4 -0
- package/dist/src/astExtractor.d.ts +45 -0
- package/dist/src/astExtractor.js +388 -0
- package/dist/src/astExtractor.js.map +1 -0
- package/dist/src/capnAdapter.d.ts +16 -0
- package/dist/src/capnAdapter.js +149 -0
- package/dist/src/capnAdapter.js.map +1 -0
- package/dist/src/cli.d.ts +7 -0
- package/dist/src/cli.js +149 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/discoveryRouter.d.ts +13 -0
- package/dist/src/discoveryRouter.js +137 -0
- package/dist/src/discoveryRouter.js.map +1 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/integrity.d.ts +10 -0
- package/dist/src/integrity.js +93 -0
- package/dist/src/integrity.js.map +1 -0
- package/dist/src/mcp/capnIndex.d.ts +2 -0
- package/dist/src/mcp/capnIndex.js +15 -0
- package/dist/src/mcp/capnIndex.js.map +1 -0
- package/dist/src/mcp/capnTools.d.ts +5 -0
- package/dist/src/mcp/capnTools.js +190 -0
- package/dist/src/mcp/capnTools.js.map +1 -0
- package/dist/src/mcp/server.d.ts +22 -0
- package/dist/src/mcp/server.js +241 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/types.d.ts +80 -0
- package/dist/src/mcp/types.js +2 -0
- package/dist/src/mcp/types.js.map +1 -0
- package/dist/src/paths.d.ts +39 -0
- package/dist/src/paths.js +134 -0
- package/dist/src/paths.js.map +1 -0
- package/dist/src/types.d.ts +44 -0
- package/dist/src/types.js +11 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { execFile, execFileSync } from "node:child_process";
|
|
3
|
+
import { promisify } from "node:util";
|
|
4
|
+
import { WaymarkError } from "./types.js";
|
|
5
|
+
import { detectAstIntent, queryWasmAst } from "./discoveryRouter.js";
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
const MAX_OUTPUT = 2000;
|
|
8
|
+
function digestOutput(value) {
|
|
9
|
+
return value.length <= MAX_OUTPUT ? value : `${value.slice(0, MAX_OUTPUT)}…`;
|
|
10
|
+
}
|
|
11
|
+
function uniqueFiles(files) {
|
|
12
|
+
const selected = [...new Set(files)].sort();
|
|
13
|
+
if (selected.some((file) => file.includes(",")))
|
|
14
|
+
throw new WaymarkError("CAPN_UNSAFE_PATH", "Capn's public CLI cannot encode a file path containing a comma");
|
|
15
|
+
return selected;
|
|
16
|
+
}
|
|
17
|
+
function quoteCmdArgument(value) {
|
|
18
|
+
if (value.length === 0)
|
|
19
|
+
return '""';
|
|
20
|
+
if (/[\r\n%"]/u.test(value))
|
|
21
|
+
throw new WaymarkError("CAPN_UNSAFE_ARGUMENT", "Capn batch adapters reject percent signs, quotes, and newlines; use a direct executable for those values");
|
|
22
|
+
if (/^[A-Za-z0-9_./\\:@+=,-]+$/u.test(value))
|
|
23
|
+
return value;
|
|
24
|
+
return `"${value.replace(/["^&|<>]/gu, "^$&")}"`;
|
|
25
|
+
}
|
|
26
|
+
export function resolveWindowsExecutable(executable) {
|
|
27
|
+
if (path.extname(executable).toLowerCase() === ".cmd" || path.extname(executable).toLowerCase() === ".bat")
|
|
28
|
+
return executable;
|
|
29
|
+
try {
|
|
30
|
+
const output = execFileSync("where.exe", [executable], { encoding: "utf8", windowsHide: true, timeout: 5000 });
|
|
31
|
+
const candidates = output.split(/\r?\n/u).map((line) => line.trim()).filter(Boolean);
|
|
32
|
+
const executableHit = candidates.find((c) => {
|
|
33
|
+
const ext = path.extname(c).toLowerCase();
|
|
34
|
+
return ext === ".cmd" || ext === ".bat" || ext === ".exe";
|
|
35
|
+
});
|
|
36
|
+
return executableHit ?? candidates[0] ?? executable;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return executable;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function commandSpec(executable, args) {
|
|
43
|
+
if (process.platform !== "win32")
|
|
44
|
+
return { file: executable, args: [...args] };
|
|
45
|
+
const resolved = resolveWindowsExecutable(executable);
|
|
46
|
+
const extension = path.extname(resolved).toLowerCase();
|
|
47
|
+
if (extension !== ".cmd" && extension !== ".bat")
|
|
48
|
+
return { file: resolved, args: [...args] };
|
|
49
|
+
const commandLine = [resolved, ...args].map(quoteCmdArgument).join(" ");
|
|
50
|
+
return { file: process.env.ComSpec || "cmd.exe", args: ["/d", "/v:off", "/s", "/c", commandLine] };
|
|
51
|
+
}
|
|
52
|
+
async function execute(root, executable, args) {
|
|
53
|
+
const spec = commandSpec(executable, args);
|
|
54
|
+
return await execFileAsync(spec.file, spec.args, {
|
|
55
|
+
cwd: root,
|
|
56
|
+
windowsHide: true,
|
|
57
|
+
shell: false,
|
|
58
|
+
timeout: 15_000,
|
|
59
|
+
maxBuffer: 64 * 1024,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
export function capnChartArgs(question, answer, files) {
|
|
63
|
+
// capn-hook >= 0.2: the answer moved from a positional to --details.
|
|
64
|
+
return ["chart", question, ...uniqueFiles(files).flatMap((file) => ["--files", file]), "--details", answer];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Chart a question + answer (+ optional file references) into Capn memory.
|
|
68
|
+
* Profile "none" disables publication (deterministic no-op for tests and
|
|
69
|
+
* offline use); "capn-cli" invokes the real capn-hook CLI.
|
|
70
|
+
*/
|
|
71
|
+
export async function publish(root, profile, executable, question, answer, files) {
|
|
72
|
+
const selectedFiles = uniqueFiles(files);
|
|
73
|
+
if (profile === "none")
|
|
74
|
+
return { published: false, adapter: profile, output: "publication disabled" };
|
|
75
|
+
if (!executable || executable.includes("\0"))
|
|
76
|
+
throw new WaymarkError("CAPN_CONFIG_INVALID", "Capn executable is invalid");
|
|
77
|
+
const args = capnChartArgs(question, answer, selectedFiles);
|
|
78
|
+
try {
|
|
79
|
+
const result = await execute(root, executable, args);
|
|
80
|
+
return { published: true, adapter: profile, output: digestOutput(result.stdout || result.stderr || "capn chart completed") };
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (error instanceof WaymarkError) {
|
|
84
|
+
return { published: false, adapter: profile, output: "", error: `${error.code}: ${error.message}` };
|
|
85
|
+
}
|
|
86
|
+
const candidate = error;
|
|
87
|
+
const detail = candidate.stderr || candidate.stdout || candidate.message || "Capn publication failed";
|
|
88
|
+
return {
|
|
89
|
+
published: false,
|
|
90
|
+
adapter: profile,
|
|
91
|
+
output: "",
|
|
92
|
+
error: digestOutput(`${candidate.code ?? "CAPN_ERROR"}: ${detail}`),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* The two-phase discovery router: structural questions (who calls / where is /
|
|
98
|
+
* entrypoints) are answered by the in-process Tree-sitter WASM AST; everything
|
|
99
|
+
* else falls through to Capn's charted semantic memory. A clean miss is a miss —
|
|
100
|
+
* the router never guesses.
|
|
101
|
+
*/
|
|
102
|
+
export async function ask(root, profile, executable, question) {
|
|
103
|
+
if (profile === "none")
|
|
104
|
+
return { waymark: 1, kind: "ask", provider: "none", status: "miss", matches: [] };
|
|
105
|
+
const intent = detectAstIntent(question);
|
|
106
|
+
// Structural AST query -> in-process Tree-sitter WASM, no external process.
|
|
107
|
+
if (intent.requiresParser) {
|
|
108
|
+
const astResult = await queryWasmAst(intent, root);
|
|
109
|
+
if (astResult.hit) {
|
|
110
|
+
return {
|
|
111
|
+
waymark: 1,
|
|
112
|
+
kind: "ask",
|
|
113
|
+
provider: "wasm-ast",
|
|
114
|
+
status: "hit",
|
|
115
|
+
result: digestOutput(astResult.output),
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// Semantic fallback: Capn charted memory via executable.
|
|
120
|
+
try {
|
|
121
|
+
const result = await execute(root, executable, ["ask", question]);
|
|
122
|
+
const stdout = (result.stdout || "").trim();
|
|
123
|
+
if (stdout && !stdout.startsWith("No charted answer.")) {
|
|
124
|
+
try {
|
|
125
|
+
const parsed = JSON.parse(stdout);
|
|
126
|
+
return { waymark: 1, kind: "ask", provider: "capn-cli", status: "hit", result: parsed };
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return { waymark: 1, kind: "ask", provider: "capn-cli", status: "hit", result: digestOutput(stdout) };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return { waymark: 1, kind: "ask", provider: "capn-cli", status: "miss", matches: [] };
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
const candidate = error;
|
|
136
|
+
const combined = `${candidate.stdout || ""}\n${candidate.stderr || ""}`;
|
|
137
|
+
if (combined.includes("No charted answer.")) {
|
|
138
|
+
return { waymark: 1, kind: "ask", provider: "capn-cli", status: "miss", matches: [] };
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
waymark: 1,
|
|
142
|
+
kind: "ask",
|
|
143
|
+
provider: "capn-cli",
|
|
144
|
+
status: "error",
|
|
145
|
+
error: digestOutput(`${candidate.code ?? "CAPN_ERROR"}: ${candidate.stderr || candidate.message || "Capn ask failed"}`),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=capnAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capnAdapter.js","sourceRoot":"","sources":["../../src/capnAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Run one CLI command with its raw argv and exit with the command's status code.
|
|
4
|
+
* Exported for the explicit wrapper bins (waymark-ask / waymark-discover /
|
|
5
|
+
* waymark-chart) so each action is one process without subcommand parsing.
|
|
6
|
+
*/
|
|
7
|
+
export declare function runCli(command: string, args: readonly string[]): Promise<void>;
|
package/dist/src/cli.js
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { WaymarkError } from "./types.js";
|
|
7
|
+
import { repoRoot } from "./paths.js";
|
|
8
|
+
import { ask as capnAsk, publish } from "./capnAdapter.js";
|
|
9
|
+
import { discoverSymbolsInFile } from "./astExtractor.js";
|
|
10
|
+
const VALUE_FLAGS = new Set(["profile", "path", "language", "capn-executable", "question", "answer", "files"]);
|
|
11
|
+
function parseArgs(args) {
|
|
12
|
+
const positionals = [];
|
|
13
|
+
const values = new Map();
|
|
14
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
15
|
+
const current = args[index];
|
|
16
|
+
if (!current?.startsWith("--")) {
|
|
17
|
+
if (current !== undefined)
|
|
18
|
+
positionals.push(current);
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const flag = current.slice(2);
|
|
22
|
+
if (!VALUE_FLAGS.has(flag))
|
|
23
|
+
throw new WaymarkError("UNKNOWN_OPTION", `Unknown option --${flag}`);
|
|
24
|
+
const value = args[index + 1];
|
|
25
|
+
if (!value || value.startsWith("--"))
|
|
26
|
+
throw new WaymarkError("MISSING_OPTION_VALUE", `Option --${flag} requires a value`);
|
|
27
|
+
values.set(flag, value);
|
|
28
|
+
index += 1;
|
|
29
|
+
}
|
|
30
|
+
return { positionals, values };
|
|
31
|
+
}
|
|
32
|
+
function requiredValue(parsed, name) {
|
|
33
|
+
const value = parsed.values.get(name);
|
|
34
|
+
if (!value)
|
|
35
|
+
throw new WaymarkError("MISSING_ARGUMENT", `Missing --${name}`);
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
function boundedText(value, maximum, label, allowEmpty = false) {
|
|
39
|
+
if ((!allowEmpty && value.length === 0) || Array.from(value).length > maximum) {
|
|
40
|
+
throw new WaymarkError("TEXT_LIMIT", `${label} must contain ${allowEmpty ? "at most" : "1 to"} ${maximum} characters`);
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
function writeAllSync(fd, payload) {
|
|
45
|
+
let offset = 0;
|
|
46
|
+
while (offset < payload.length) {
|
|
47
|
+
offset += fs.writeSync(fd, payload, offset, payload.length - offset);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function output(value) {
|
|
51
|
+
try {
|
|
52
|
+
writeAllSync(1, Buffer.from(`${JSON.stringify(value)}\n`, "utf8"));
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
process.stdout.write(`${JSON.stringify(value)}\n`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function errorOutput(error) {
|
|
59
|
+
if (error instanceof WaymarkError) {
|
|
60
|
+
return { value: { waymark: 1, kind: "error", ok: false, code: error.code, message: error.message }, exitCode: error.exitCode };
|
|
61
|
+
}
|
|
62
|
+
const message = error instanceof Error ? error.message : "Unexpected error";
|
|
63
|
+
return { value: { waymark: 1, kind: "error", ok: false, code: "UNEXPECTED_ERROR", message }, exitCode: 1 };
|
|
64
|
+
}
|
|
65
|
+
function resolveProfile(parsed) {
|
|
66
|
+
const value = parsed.values.get("profile") ?? process.env.WAYMARK_CAPN_PROFILE ?? "capn-cli";
|
|
67
|
+
return value === "none" ? "none" : "capn-cli";
|
|
68
|
+
}
|
|
69
|
+
function resolveCapnExecutable(parsed) {
|
|
70
|
+
return parsed.values.get("capn-executable") ?? process.env.WAYMARK_CAPN_EXECUTABLE ?? "capn";
|
|
71
|
+
}
|
|
72
|
+
async function runCommand(command, rawArgs) {
|
|
73
|
+
const suppression = process.env.WAYMARK_HOOK_DISABLED === "1"
|
|
74
|
+
? "WAYMARK_HOOK_DISABLED"
|
|
75
|
+
: process.env.WAYMARK_HOOK_DEPTH === "1"
|
|
76
|
+
? "WAYMARK_HOOK_DEPTH"
|
|
77
|
+
: undefined;
|
|
78
|
+
if (suppression)
|
|
79
|
+
return { value: { waymark: 1, kind: "suppressed", ok: true, reason: suppression } };
|
|
80
|
+
const parsed = parseArgs(rawArgs);
|
|
81
|
+
const root = repoRoot();
|
|
82
|
+
if (command === "help" || command === "--help" || command === "-h") {
|
|
83
|
+
return {
|
|
84
|
+
value: [
|
|
85
|
+
"Waymark discovery engine (symbolic + semantic routing)",
|
|
86
|
+
" discover-symbols --path <repository-relative-file> [--language typescript|python]",
|
|
87
|
+
" ask <question> [--profile capn-cli|none] [--capn-executable <path>]",
|
|
88
|
+
" chart --question <q> --answer <a> --files <a,b> [--profile capn-cli|none] [--capn-executable <path>]",
|
|
89
|
+
" mcp (starts the stdio MCP discovery server)",
|
|
90
|
+
"",
|
|
91
|
+
"Explicit wrappers (same engine, one command per action):",
|
|
92
|
+
" waymark-ask <question> | waymark-discover --path <f> | waymark-chart ... | waymark-mcp",
|
|
93
|
+
"",
|
|
94
|
+
"Env: WAYMARK_CAPN_PROFILE (capn-cli|none, default capn-cli), WAYMARK_CAPN_EXECUTABLE (default 'capn')",
|
|
95
|
+
].join("\n"),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (command === "discover-symbols") {
|
|
99
|
+
const storedPath = requiredValue(parsed, "path");
|
|
100
|
+
return { value: await discoverSymbolsInFile(root, storedPath, parsed.values.get("language")) };
|
|
101
|
+
}
|
|
102
|
+
if (command === "ask") {
|
|
103
|
+
const question = boundedText(parsed.positionals.join(" "), 240, "question");
|
|
104
|
+
return { value: await capnAsk(root, resolveProfile(parsed), resolveCapnExecutable(parsed), question) };
|
|
105
|
+
}
|
|
106
|
+
if (command === "chart") {
|
|
107
|
+
const question = boundedText(requiredValue(parsed, "question"), 240, "question");
|
|
108
|
+
const answer = boundedText(requiredValue(parsed, "answer"), 4000, "answer");
|
|
109
|
+
const files = (parsed.values.get("files") ?? "").split(",").map((file) => file.trim()).filter(Boolean);
|
|
110
|
+
const profile = resolveProfile(parsed);
|
|
111
|
+
const result = await publish(root, profile, resolveCapnExecutable(parsed), question, answer, files);
|
|
112
|
+
return { value: result, exitCode: result.published === false && profile === "capn-cli" ? 3 : 0 };
|
|
113
|
+
}
|
|
114
|
+
if (command === "mcp") {
|
|
115
|
+
const { McpServer } = await import("./mcp/server.js");
|
|
116
|
+
const server = new McpServer();
|
|
117
|
+
await server.runStdio();
|
|
118
|
+
return { value: null };
|
|
119
|
+
}
|
|
120
|
+
throw new WaymarkError("UNKNOWN_COMMAND", `Unknown command: ${command}`);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Run one CLI command with its raw argv and exit with the command's status code.
|
|
124
|
+
* Exported for the explicit wrapper bins (waymark-ask / waymark-discover /
|
|
125
|
+
* waymark-chart) so each action is one process without subcommand parsing.
|
|
126
|
+
*/
|
|
127
|
+
export async function runCli(command, args) {
|
|
128
|
+
try {
|
|
129
|
+
const result = await runCommand(command, args);
|
|
130
|
+
if (result.value !== null)
|
|
131
|
+
output(result.value);
|
|
132
|
+
// web-tree-sitter's Emscripten runtime leaves teardown hooks on the event loop
|
|
133
|
+
// after any parse; a graceful drain adds seconds of 0%-CPU latency per one-shot
|
|
134
|
+
// CLI call. All output is flushed synchronously by this point, so hard-exit
|
|
135
|
+
// with the intended code.
|
|
136
|
+
process.exit(result.exitCode ?? 0);
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
const result = errorOutput(error);
|
|
140
|
+
output(result.value);
|
|
141
|
+
process.exit(result.exitCode ?? 1);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async function main() {
|
|
145
|
+
await runCli(process.argv[2] ?? "help", process.argv.slice(3));
|
|
146
|
+
}
|
|
147
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === path.resolve(fileURLToPath(import.meta.url)))
|
|
148
|
+
await main();
|
|
149
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type AstExtractionResult } from "./astExtractor.js";
|
|
2
|
+
export interface AstIntent {
|
|
3
|
+
requiresParser: boolean;
|
|
4
|
+
tool: "trace_path" | "search_graph" | "get_architecture";
|
|
5
|
+
functionName?: string;
|
|
6
|
+
query?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function detectAstIntent(question: string): AstIntent;
|
|
9
|
+
export declare function getOrRefreshAst(root: string, maxAgeMs?: number): Promise<AstExtractionResult>;
|
|
10
|
+
export declare function queryWasmAst(intent: AstIntent, root: string): Promise<{
|
|
11
|
+
hit: boolean;
|
|
12
|
+
output: string;
|
|
13
|
+
}>;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { extractAstFromRepo } from "./astExtractor.js";
|
|
2
|
+
export function detectAstIntent(question) {
|
|
3
|
+
const q = question.trim();
|
|
4
|
+
const lower = q.toLowerCase();
|
|
5
|
+
// 1. Architecture / Entrypoints intent
|
|
6
|
+
if (lower.includes("entrypoint") ||
|
|
7
|
+
lower.includes("entry point") ||
|
|
8
|
+
lower.includes("architecture") ||
|
|
9
|
+
lower.includes("hotspots") ||
|
|
10
|
+
lower.includes("high-level structure") ||
|
|
11
|
+
lower.includes("overview of the repo") ||
|
|
12
|
+
lower.includes("project topology")) {
|
|
13
|
+
return { requiresParser: true, tool: "get_architecture" };
|
|
14
|
+
}
|
|
15
|
+
// 2. Call-graph / Tracing intent
|
|
16
|
+
const traceMatch = lower.includes("who calls") ||
|
|
17
|
+
lower.includes("callers of") ||
|
|
18
|
+
lower.includes("callees of") ||
|
|
19
|
+
lower.includes("trace path") ||
|
|
20
|
+
lower.includes("trace ") ||
|
|
21
|
+
lower.includes("what calls") ||
|
|
22
|
+
lower.includes("which functions call") ||
|
|
23
|
+
lower.includes("call hierarchy");
|
|
24
|
+
if (traceMatch) {
|
|
25
|
+
const tokens = q.match(/[A-Za-z0-9_]+(?:\.[A-Za-z0-9_]+)*/g) || [];
|
|
26
|
+
const stopWords = new Set([
|
|
27
|
+
"who", "calls", "call", "what", "which", "functions", "trace", "path",
|
|
28
|
+
"of", "in", "to", "the", "and", "is", "where", "function", "method"
|
|
29
|
+
]);
|
|
30
|
+
const candidates = tokens.filter(t => !stopWords.has(t.toLowerCase()) && t.length > 1);
|
|
31
|
+
const rawTarget = candidates[candidates.length - 1] ?? candidates[0] ?? q;
|
|
32
|
+
const functionName = rawTarget.replace(/[?().]+$/g, "").replace(/^.*\.([A-Za-z0-9_]+)$/, "$1");
|
|
33
|
+
return {
|
|
34
|
+
requiresParser: true,
|
|
35
|
+
tool: "trace_path",
|
|
36
|
+
functionName,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
// 3. Symbol / Definition / Line range intent
|
|
40
|
+
const symbolMatch = lower.includes("where is method") ||
|
|
41
|
+
lower.includes("where is function") ||
|
|
42
|
+
lower.includes("where is class") ||
|
|
43
|
+
lower.includes("where is interface") ||
|
|
44
|
+
lower.includes("definition of") ||
|
|
45
|
+
lower.includes("declared in") ||
|
|
46
|
+
lower.includes("line numbers of") ||
|
|
47
|
+
lower.includes("ast node") ||
|
|
48
|
+
lower.includes("method signature") ||
|
|
49
|
+
lower.includes("find symbol") ||
|
|
50
|
+
lower.includes("locate symbol");
|
|
51
|
+
if (symbolMatch) {
|
|
52
|
+
const tokens = q.match(/[A-Za-z0-9_]+(?:\.[A-Za-z0-9_]+)*/g) || [];
|
|
53
|
+
const stopWords = new Set([
|
|
54
|
+
"where", "is", "method", "function", "class", "interface", "definition",
|
|
55
|
+
"of", "declared", "in", "the", "find", "symbol", "lines", "numbers", "locate"
|
|
56
|
+
]);
|
|
57
|
+
const candidates = tokens.filter(t => !stopWords.has(t.toLowerCase()) && t.length > 1);
|
|
58
|
+
const queryTerm = candidates[0] ?? q;
|
|
59
|
+
return {
|
|
60
|
+
requiresParser: true,
|
|
61
|
+
tool: "search_graph",
|
|
62
|
+
query: queryTerm.replace(/[?().]+$/g, ""),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// 4. Bare identifier or method syntax (e.g. "computeSha256", "EventStore.verifyChain")
|
|
66
|
+
if (/^[A-Za-z0-9_]+(?:\.[A-Za-z0-9_]+)?(?:\(\))?\??$/.test(q)) {
|
|
67
|
+
return {
|
|
68
|
+
requiresParser: true,
|
|
69
|
+
tool: "search_graph",
|
|
70
|
+
query: q.replace(/[?().]+$/g, ""),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return { requiresParser: false, tool: "search_graph" };
|
|
74
|
+
}
|
|
75
|
+
let cachedAst = null;
|
|
76
|
+
let lastAstScanTime = 0;
|
|
77
|
+
let lastCachedRoot = "";
|
|
78
|
+
export async function getOrRefreshAst(root, maxAgeMs = 30_000) {
|
|
79
|
+
const now = Date.now();
|
|
80
|
+
if (!cachedAst || lastCachedRoot !== root || now - lastAstScanTime > maxAgeMs) {
|
|
81
|
+
cachedAst = await extractAstFromRepo(root);
|
|
82
|
+
lastAstScanTime = now;
|
|
83
|
+
lastCachedRoot = root;
|
|
84
|
+
}
|
|
85
|
+
return cachedAst;
|
|
86
|
+
}
|
|
87
|
+
export async function queryWasmAst(intent, root) {
|
|
88
|
+
try {
|
|
89
|
+
const ast = await getOrRefreshAst(root);
|
|
90
|
+
if (intent.tool === "get_architecture") {
|
|
91
|
+
const entrypoints = ast.symbols.filter(s => {
|
|
92
|
+
const callers = ast.callersMap.get(s.name) || [];
|
|
93
|
+
return callers.length === 0 && (s.kind === "Function" || s.kind === "Method");
|
|
94
|
+
});
|
|
95
|
+
let out = `total_nodes: ${ast.symbols.length}\n`;
|
|
96
|
+
out += `entry_points: ${entrypoints.length}\n`;
|
|
97
|
+
for (const ep of entrypoints) {
|
|
98
|
+
out += ` ${ep.qualifiedName} ${ep.kind} ${ep.file}:${ep.startLine}-${ep.endLine}\n`;
|
|
99
|
+
}
|
|
100
|
+
return { hit: true, output: out.trim() };
|
|
101
|
+
}
|
|
102
|
+
if (intent.tool === "trace_path") {
|
|
103
|
+
const fn = intent.functionName || "";
|
|
104
|
+
const callers = ast.callersMap.get(fn) || [];
|
|
105
|
+
const callees = ast.calleesMap.get(fn) || [];
|
|
106
|
+
if (callers.length === 0 && callees.length === 0) {
|
|
107
|
+
const sym = ast.symbols.find(s => s.name.toLowerCase() === fn.toLowerCase());
|
|
108
|
+
if (!sym) {
|
|
109
|
+
return { hit: false, output: `Function or method "${fn}" not found in AST.` };
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
let out = `function: ${fn}\n`;
|
|
113
|
+
out += `direction: both\n`;
|
|
114
|
+
out += `callees_total: ${callees.length}\n`;
|
|
115
|
+
out += `callees: ${callees.length > 0 ? callees.join(", ") : "None"}\n`;
|
|
116
|
+
out += `callers_total: ${callers.length}\n`;
|
|
117
|
+
out += `callers: ${callers.length > 0 ? callers.join(", ") : "None"}\n`;
|
|
118
|
+
return { hit: true, output: out.trim() };
|
|
119
|
+
}
|
|
120
|
+
// Symbol Search
|
|
121
|
+
const queryTerm = (intent.query || "").toLowerCase();
|
|
122
|
+
const matched = ast.symbols.filter(s => s.name.toLowerCase().includes(queryTerm) ||
|
|
123
|
+
s.qualifiedName.toLowerCase().includes(queryTerm));
|
|
124
|
+
if (matched.length === 0) {
|
|
125
|
+
return { hit: false, output: `results: 0` };
|
|
126
|
+
}
|
|
127
|
+
let out = `total: ${matched.length}\nresults: ${matched.length} (cols: qn label file lines)\n`;
|
|
128
|
+
for (const m of matched) {
|
|
129
|
+
out += ` ${m.qualifiedName} ${m.kind} ${m.file} ${m.startLine}-${m.endLine}\n`;
|
|
130
|
+
}
|
|
131
|
+
return { hit: true, output: out.trim() };
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
return { hit: false, output: error instanceof Error ? error.message : String(error) };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=discoveryRouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discoveryRouter.js","sourceRoot":"","sources":["../../src/discoveryRouter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { ask, publish, capnChartArgs, resolveWindowsExecutable } from "./capnAdapter.js";
|
|
2
|
+
export { detectAstIntent, queryWasmAst, getOrRefreshAst, type AstIntent } from "./discoveryRouter.js";
|
|
3
|
+
export { discoverSymbolsInFile, extractAstFromRepo, type SymbolDiscoveryResult, type StructuredSymbol } from "./astExtractor.js";
|
|
4
|
+
export { verifyHop } from "./integrity.js";
|
|
5
|
+
export { anchorForRange, repoRoot, sha256, structuralSignature, normalizeSpan } from "./paths.js";
|
|
6
|
+
export { WaymarkError, type AdapterProfile, type HopRecord, type PublicationResult, type HopCheck } from "./types.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Public library API of the Waymark Engine.
|
|
2
|
+
// One import surface for consumers: `import { ask, discoverSymbolsInFile, verifyHop } from "waymark-engine";`
|
|
3
|
+
export { ask, publish, capnChartArgs, resolveWindowsExecutable } from "./capnAdapter.js";
|
|
4
|
+
export { detectAstIntent, queryWasmAst, getOrRefreshAst } from "./discoveryRouter.js";
|
|
5
|
+
export { discoverSymbolsInFile, extractAstFromRepo } from "./astExtractor.js";
|
|
6
|
+
export { verifyHop } from "./integrity.js";
|
|
7
|
+
export { anchorForRange, repoRoot, sha256, structuralSignature, normalizeSpan } from "./paths.js";
|
|
8
|
+
export { WaymarkError } from "./types.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,8GAA8G;AAE9G,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,eAAe,EAAkB,MAAM,sBAAsB,CAAC;AACtG,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAqD,MAAM,mBAAmB,CAAC;AACjI,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAClG,OAAO,EAAE,YAAY,EAA8E,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { HopCheck, HopRecord } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Verify one recorded span anchor against the current working tree.
|
|
4
|
+
* Returns FRESH (unchanged), MOVED (span relocated, new range resolved), or
|
|
5
|
+
* STALE (deleted/changed/ambiguous — the caller must re-verify or discard).
|
|
6
|
+
*
|
|
7
|
+
* This is the standalone integrity primitive retained from the continuity
|
|
8
|
+
* ledger: hash-pinned span verification without any trajectory state.
|
|
9
|
+
*/
|
|
10
|
+
export declare function verifyHop(root: string, hop: HopRecord, maxWindows: number): HopCheck;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { extractRange, normalizedLines, normalizeSpan, readFileText, resolveRepositoryFile, sha256, structuralSignature, } from "./paths.js";
|
|
2
|
+
function snapshot(root, storedPath) {
|
|
3
|
+
const file = readFileText(root, storedPath);
|
|
4
|
+
return { bytes: file.bytes, lines: normalizedLines(file.text), hash: sha256(file.bytes) };
|
|
5
|
+
}
|
|
6
|
+
function sameSignature(left, right) {
|
|
7
|
+
return left.firstHash === right.firstHash && left.lastHash === right.lastHash;
|
|
8
|
+
}
|
|
9
|
+
function windows(totalLines, spanLineCount, original, limit) {
|
|
10
|
+
const total = totalLines - spanLineCount + 1;
|
|
11
|
+
if (total <= 0 || limit <= 0)
|
|
12
|
+
return [];
|
|
13
|
+
const count = Math.min(total, limit);
|
|
14
|
+
const starts = [];
|
|
15
|
+
const add = (value) => {
|
|
16
|
+
if (value >= 1 && value <= total && !starts.includes(value))
|
|
17
|
+
starts.push(value);
|
|
18
|
+
};
|
|
19
|
+
add(original.start);
|
|
20
|
+
if (count === 1)
|
|
21
|
+
return starts;
|
|
22
|
+
for (let index = 0; index < count; index += 1) {
|
|
23
|
+
add(1 + Math.floor((index * (total - 1)) / (count - 1)));
|
|
24
|
+
}
|
|
25
|
+
return starts.slice(0, limit);
|
|
26
|
+
}
|
|
27
|
+
function rangeFits(lines, range) {
|
|
28
|
+
return range.start >= 1 && range.end >= range.start && range.end <= lines.length;
|
|
29
|
+
}
|
|
30
|
+
function staleCheck(hop, reason, currentFileSha256) {
|
|
31
|
+
return {
|
|
32
|
+
index: hop.index,
|
|
33
|
+
path: hop.path,
|
|
34
|
+
status: "STALE",
|
|
35
|
+
originalRange: hop.range,
|
|
36
|
+
reason,
|
|
37
|
+
...(currentFileSha256 ? { currentFileSha256 } : {}),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Verify one recorded span anchor against the current working tree.
|
|
42
|
+
* Returns FRESH (unchanged), MOVED (span relocated, new range resolved), or
|
|
43
|
+
* STALE (deleted/changed/ambiguous — the caller must re-verify or discard).
|
|
44
|
+
*
|
|
45
|
+
* This is the standalone integrity primitive retained from the continuity
|
|
46
|
+
* ledger: hash-pinned span verification without any trajectory state.
|
|
47
|
+
*/
|
|
48
|
+
export function verifyHop(root, hop, maxWindows) {
|
|
49
|
+
let file;
|
|
50
|
+
try {
|
|
51
|
+
resolveRepositoryFile(root, hop.path);
|
|
52
|
+
file = snapshot(root, hop.path);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
const reason = error instanceof Error ? error.message : "file unavailable";
|
|
56
|
+
return staleCheck(hop, reason);
|
|
57
|
+
}
|
|
58
|
+
if (file.hash === hop.fileSha256) {
|
|
59
|
+
return { index: hop.index, path: hop.path, status: "FRESH", originalRange: hop.range, resolvedRange: hop.range, currentFileSha256: file.hash };
|
|
60
|
+
}
|
|
61
|
+
if (rangeFits(file.lines, hop.range)) {
|
|
62
|
+
const current = normalizeSpan(extractRange(file.lines, hop.range));
|
|
63
|
+
if (sha256(Buffer.from(current, "utf8")) === hop.normalizedSpanHash) {
|
|
64
|
+
return { index: hop.index, path: hop.path, status: "FRESH", originalRange: hop.range, resolvedRange: hop.range, currentFileSha256: file.hash };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const lineCount = hop.spanLineCount;
|
|
68
|
+
const starts = windows(file.lines.length, lineCount, hop.range, maxWindows);
|
|
69
|
+
const exact = [];
|
|
70
|
+
const signatureHits = [];
|
|
71
|
+
const scanLimited = file.lines.length - lineCount + 1 > starts.length;
|
|
72
|
+
for (const start of starts) {
|
|
73
|
+
const range = { start, end: start + lineCount - 1 };
|
|
74
|
+
const normalized = normalizeSpan(extractRange(file.lines, range));
|
|
75
|
+
const candidateHash = sha256(Buffer.from(normalized, "utf8"));
|
|
76
|
+
if (candidateHash === hop.normalizedSpanHash)
|
|
77
|
+
exact.push(range);
|
|
78
|
+
if (sameSignature(structuralSignature(normalized), hop.structuralSignature))
|
|
79
|
+
signatureHits.push(range);
|
|
80
|
+
}
|
|
81
|
+
// A bounded scan cannot establish uniqueness beyond the windows it visited.
|
|
82
|
+
if (scanLimited)
|
|
83
|
+
return staleCheck(hop, `relocation scan limited to ${maxWindows} windows`, file.hash);
|
|
84
|
+
if (exact.length === 1) {
|
|
85
|
+
return { index: hop.index, path: hop.path, status: "MOVED", originalRange: hop.range, resolvedRange: exact[0], currentFileSha256: file.hash };
|
|
86
|
+
}
|
|
87
|
+
if (exact.length > 1)
|
|
88
|
+
return staleCheck(hop, "ambiguous exact span relocation", file.hash);
|
|
89
|
+
if (signatureHits.length > 0)
|
|
90
|
+
return staleCheck(hop, "signature-only candidate; exact span is not trustworthy", file.hash);
|
|
91
|
+
return staleCheck(hop, "recorded span was deleted or changed", file.hash);
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=integrity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integrity.js","sourceRoot":"","sources":["../../src/integrity.ts"],"names":[],"mappings":"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"}
|