@shanepadgett/tau-agent 0.33.1 → 0.34.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/docs/context.md +29 -20
- package/docs/extending-tau-agent.md +63 -24
- package/extensions/appshot/index.ts +112 -111
- package/extensions/aside/README.md +7 -0
- package/extensions/aside/index.ts +168 -0
- package/extensions/aside/panel.ts +83 -0
- package/extensions/branch/index.ts +38 -21
- package/extensions/cache-diagnostics/index.ts +70 -58
- package/extensions/checkpoint/README.md +9 -0
- package/extensions/checkpoint/checkpoint-budget.ts +79 -0
- package/extensions/checkpoint/checkpoint.ts +277 -0
- package/extensions/checkpoint/index.ts +102 -0
- package/extensions/checkpoint/messages.ts +169 -0
- package/extensions/checkpoint/prompt.ts +24 -0
- package/extensions/checkpoint/settings.ts +27 -0
- package/extensions/commit/commit-effort.ts +3 -3
- package/extensions/context/README.md +12 -8
- package/extensions/context/definitions.ts +178 -55
- package/extensions/context/index.ts +192 -160
- package/extensions/context/panel.ts +57 -37
- package/extensions/context/sync.ts +139 -89
- package/extensions/context/validation.ts +37 -25
- package/extensions/effort/README.md +1 -1
- package/extensions/effort/index.ts +3 -3
- package/extensions/effort/state.ts +3 -18
- package/extensions/explore/guidance.ts +6 -47
- package/extensions/explore/index.ts +38 -53
- package/extensions/explore/{ast/read → read}/hook.ts +12 -7
- package/extensions/explore/{ast/tools → tools}/ast-search.ts +15 -19
- package/extensions/explore/{ast/tools → tools}/context.ts +16 -23
- package/extensions/explore/{ast/tools → tools}/deps.ts +11 -15
- package/extensions/explore/{ast/tools → tools}/discover.ts +15 -17
- package/extensions/explore/{ast/tools → tools}/impact.ts +20 -23
- package/extensions/explore/{ast/tools → tools}/outline.ts +21 -24
- package/extensions/explore/{ast/tools → tools}/relationships.ts +23 -32
- package/extensions/explore/{ast/tools → tools}/render.ts +1 -1
- package/extensions/explore/{ast/tools → tools}/reverse-deps.ts +11 -15
- package/extensions/explore/{ast/tools → tools}/show.ts +16 -19
- package/extensions/explore/tools/target-params.ts +9 -0
- package/extensions/footer/index.ts +75 -56
- package/extensions/handoff/index.ts +8 -30
- package/extensions/image-gen/index.ts +46 -40
- package/extensions/patch/executor.ts +190 -135
- package/extensions/patch/matcher.ts +82 -48
- package/extensions/patch/parser.ts +149 -105
- package/extensions/patch/render.ts +32 -39
- package/extensions/patch/summary.ts +30 -26
- package/extensions/ready/README.md +7 -0
- package/extensions/ready/index.ts +58 -0
- package/extensions/ready/model.ts +128 -0
- package/extensions/ready/packs.ts +272 -0
- package/extensions/ready/render.ts +445 -0
- package/extensions/ready/scan.ts +760 -0
- package/extensions/reference/panel.ts +28 -16
- package/extensions/review/index.ts +63 -51
- package/extensions/review/panel.ts +5 -34
- package/extensions/runtime-context/context.ts +30 -26
- package/extensions/script-runner/README.md +2 -2
- package/extensions/script-runner/index.ts +122 -82
- package/extensions/silent-command-runner/index.ts +38 -23
- package/extensions/subagent/agents/context-sync.md +185 -33
- package/extensions/subagent/agents/scout.md +2 -2
- package/extensions/subagent/agents.ts +137 -84
- package/extensions/subagent/cmux-dashboard.ts +39 -30
- package/extensions/subagent/index.ts +79 -59
- package/extensions/subagent/resume.ts +1 -1
- package/extensions/subagent/run.ts +304 -193
- package/extensions/subagent/runtime.ts +781 -343
- package/extensions/tau/index.ts +47 -38
- package/extensions/tau-help/help.md +14 -6
- package/extensions/tool-loader/README.md +4 -2
- package/extensions/tool-loader/index.ts +77 -52
- package/extensions/web/index.ts +6 -3
- package/extensions/web/webfetch.ts +114 -86
- package/package.json +3 -3
- package/schemas/tau.schema.json +20 -33
- package/shared/bounded-text-result.ts +1 -0
- package/shared/checkpoint-visibility.ts +9 -0
- package/shared/events.ts +28 -10
- package/shared/isolated-session.ts +71 -29
- package/shared/model-effort.ts +9 -19
- package/shared/model-fallback/index.ts +66 -41
- package/shared/settings/load.ts +45 -38
- package/shared/temporary-output-store.ts +16 -10
- package/{extensions/explore → src}/ast/adapter.ts +11 -2
- package/{extensions/explore → src}/ast/engine.ts +54 -38
- package/{extensions/explore → src}/ast/format/ast-search.ts +15 -6
- package/{extensions/explore → src}/ast/format/context.ts +3 -6
- package/src/ast/format/deps.ts +94 -0
- package/{extensions/explore → src}/ast/format/discover.ts +2 -2
- package/{extensions/explore → src}/ast/format/impact.ts +9 -11
- package/{extensions/explore → src}/ast/format/outline.ts +2 -2
- package/{extensions/explore → src}/ast/format/relationships.ts +11 -7
- package/{extensions/explore → src}/ast/format/show.ts +1 -1
- package/src/ast/format/targeted-result.ts +20 -0
- package/src/ast/grammars/c_sharp.wasm +0 -0
- package/{extensions/explore → src}/ast/grammars/manifest.json +9 -12
- package/{extensions/explore → src}/ast/grammars/manifest.ts +0 -4
- package/{extensions/explore → src}/ast/graph/file-graph.ts +210 -98
- package/{extensions/explore → src}/ast/graph/relationships.ts +285 -72
- package/{extensions/explore → src}/ast/ir.ts +6 -0
- package/src/ast/languages/csharp-file-deps.ts +90 -0
- package/{extensions/explore → src}/ast/languages/csharp.ts +9 -40
- package/src/ast/languages/dotted-index.ts +131 -0
- package/{extensions/explore → src}/ast/languages/file-dep-util.ts +22 -13
- package/src/ast/languages/fixtures/sample.cs +53 -0
- package/src/ast/languages/fixtures/sample.cs.expected.json +156 -0
- package/src/ast/languages/fixtures/sample.go +37 -0
- package/src/ast/languages/fixtures/sample.go.expected.json +96 -0
- package/src/ast/languages/fixtures/sample.java +40 -0
- package/src/ast/languages/fixtures/sample.java.expected.json +126 -0
- package/src/ast/languages/fixtures/sample.kt +31 -0
- package/src/ast/languages/fixtures/sample.kt.expected.json +134 -0
- package/src/ast/languages/fixtures/sample.md +23 -0
- package/src/ast/languages/fixtures/sample.md.expected.json +44 -0
- package/src/ast/languages/fixtures/sample.rs +54 -0
- package/src/ast/languages/fixtures/sample.rs.expected.json +178 -0
- package/src/ast/languages/fixtures/sample.swift +45 -0
- package/src/ast/languages/fixtures/sample.swift.expected.json +147 -0
- package/src/ast/languages/fixtures/sample.ts +45 -0
- package/src/ast/languages/fixtures/sample.ts.expected.json +141 -0
- package/src/ast/languages/fixtures/sample.tsx +36 -0
- package/src/ast/languages/fixtures/sample.tsx.expected.json +59 -0
- package/{extensions/explore → src}/ast/languages/go-file-deps.ts +6 -0
- package/{extensions/explore → src}/ast/languages/go.ts +21 -3
- package/{extensions/explore → src}/ast/languages/java.ts +5 -38
- package/src/ast/languages/jvm-file-deps.ts +135 -0
- package/{extensions/explore → src}/ast/languages/kotlin.ts +5 -39
- package/{extensions/explore → src}/ast/languages/rust-file-deps.ts +3 -3
- package/{extensions/explore → src}/ast/languages/rust.ts +21 -13
- package/{extensions/explore → src}/ast/languages/swift-file-deps.ts +22 -15
- package/{extensions/explore → src}/ast/languages/swift.ts +9 -39
- package/{extensions/explore → src}/ast/languages/tree.ts +47 -0
- package/{extensions/explore → src}/ast/languages/typescript-file-deps.ts +108 -0
- package/{extensions/explore → src}/ast/languages/typescript-package-surface.ts +4 -3
- package/{extensions/explore → src}/ast/languages/typescript.ts +3 -5
- package/{extensions/explore → src}/ast/markdown.ts +72 -47
- package/{extensions/explore → src}/ast/queries/ast-search.ts +164 -146
- package/{extensions/explore → src}/ast/queries/composite-target.ts +1 -1
- package/{extensions/explore → src}/ast/queries/context.ts +116 -80
- package/{extensions/explore → src}/ast/queries/discover.ts +154 -105
- package/src/ast/queries/impact.ts +291 -0
- package/{extensions/explore → src}/ast/queries/outline.ts +4 -2
- package/{extensions/explore → src}/ast/queries/show.ts +46 -42
- package/{extensions/explore → src}/ast/query.ts +1 -1
- package/{extensions/explore → src}/ast/registry.ts +1 -2
- package/{extensions/explore → src}/ast/scan.ts +1 -1
- package/src/ast/session.ts +50 -0
- package/{extensions/explore → src}/ast/slice.ts +8 -0
- package/{extensions/explore → src/ast}/traverse.ts +32 -20
- package/src/file-injection/index.ts +547 -0
- package/src/image-generation/client.ts +50 -31
- package/src/image-generation/index.ts +177 -134
- package/src/index.ts +2 -0
- package/src/tool-loading/index.ts +58 -0
- package/extensions/context/evidence.ts +0 -517
- package/extensions/context/projection.ts +0 -141
- package/extensions/context/state.ts +0 -30
- package/extensions/context/write-scope.ts +0 -109
- package/extensions/explore/ast/format/deps.ts +0 -86
- package/extensions/explore/ast/grammars/odin.wasm +0 -0
- package/extensions/explore/ast/languages/csharp-file-deps.ts +0 -189
- package/extensions/explore/ast/languages/fixtures/sample.cs +0 -17
- package/extensions/explore/ast/languages/fixtures/sample.java +0 -21
- package/extensions/explore/ast/languages/fixtures/sample.kt +0 -15
- package/extensions/explore/ast/languages/fixtures/sample.odin +0 -28
- package/extensions/explore/ast/languages/fixtures/sample.rs +0 -31
- package/extensions/explore/ast/languages/fixtures/sample.swift +0 -25
- package/extensions/explore/ast/languages/jvm-file-deps.ts +0 -217
- package/extensions/explore/ast/languages/odin-file-deps.ts +0 -175
- package/extensions/explore/ast/languages/odin.ts +0 -407
- package/extensions/explore/ast/queries/impact.ts +0 -250
- package/extensions/explore/outline-injection.ts +0 -151
- package/extensions/explore/read/autoread.ts +0 -118
- package/extensions/working-memory/README.md +0 -17
- package/extensions/working-memory/checkpoint.ts +0 -242
- package/extensions/working-memory/index.ts +0 -341
- package/extensions/working-memory/memory.ts +0 -235
- package/extensions/working-memory/render.ts +0 -185
- package/extensions/working-memory/settings.ts +0 -38
- package/extensions/working-memory/state.ts +0 -158
- package/shared/autoread.ts +0 -234
- package/shared/context-messages.ts +0 -19
- package/shared/outline-injection.ts +0 -56
- /package/{extensions/explore → src}/ast/format/composite.ts +0 -0
- /package/{extensions/explore → src}/ast/grammars/kotlin.wasm +0 -0
- /package/{extensions/explore → src}/ast/grammars/swift.wasm +0 -0
- /package/{extensions/explore → src}/ast/identity.ts +0 -0
- /package/{extensions/explore → src}/ast/package-surface.ts +0 -0
- /package/{extensions/explore/ast/read/policy.ts → src/ast/read-policy.ts} +0 -0
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
import { mkdir, readFile, unlink, writeFile } from "node:fs/promises";
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
3
|
-
import type { GitRunner } from "../../shared/git.ts";
|
|
4
|
-
|
|
5
|
-
export type OutsidePathSnapshot = Map<string, Buffer | null>;
|
|
6
|
-
|
|
7
|
-
export function isContextCatalogPath(path: string): boolean {
|
|
8
|
-
const normalized = path.replaceAll("\\", "/");
|
|
9
|
-
return normalized === ".pi/contexts" || normalized.startsWith(".pi/contexts/");
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export async function snapshotOutsideContext(git: GitRunner, root: string): Promise<OutsidePathSnapshot> {
|
|
13
|
-
const snapshot: OutsidePathSnapshot = new Map();
|
|
14
|
-
for (const path of await listDirtyPaths(git, root)) {
|
|
15
|
-
if (isContextCatalogPath(path)) continue;
|
|
16
|
-
snapshot.set(path, await readPathContent(root, path));
|
|
17
|
-
}
|
|
18
|
-
return snapshot;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export async function restoreOutsideContextMutations(
|
|
22
|
-
git: GitRunner,
|
|
23
|
-
root: string,
|
|
24
|
-
before: OutsidePathSnapshot,
|
|
25
|
-
): Promise<string[]> {
|
|
26
|
-
const afterDirty = await listDirtyPaths(git, root);
|
|
27
|
-
const candidates = new Set([...before.keys(), ...afterDirty.filter((path) => !isContextCatalogPath(path))]);
|
|
28
|
-
const violations: string[] = [];
|
|
29
|
-
for (const path of [...candidates].sort((left, right) => left.localeCompare(right))) {
|
|
30
|
-
if (isContextCatalogPath(path)) continue;
|
|
31
|
-
const prior = before.has(path) ? before.get(path) : undefined;
|
|
32
|
-
const current = await readPathContent(root, path);
|
|
33
|
-
if (sameContent(prior, current)) continue;
|
|
34
|
-
violations.push(path);
|
|
35
|
-
await restorePath(git, root, path, prior);
|
|
36
|
-
}
|
|
37
|
-
return violations;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async function listDirtyPaths(git: GitRunner, root: string): Promise<string[]> {
|
|
41
|
-
const raw = await git.run(["status", "--porcelain=v2", "-z", "--untracked-files=all"], { cwd: root });
|
|
42
|
-
const parts = raw.split("\0").filter(Boolean);
|
|
43
|
-
const paths = new Set<string>();
|
|
44
|
-
for (let index = 0; index < parts.length; index++) {
|
|
45
|
-
const record = parts[index];
|
|
46
|
-
if (!record) continue;
|
|
47
|
-
if (record[0] === "?") {
|
|
48
|
-
paths.add(record.slice(2).replaceAll("\\", "/"));
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
const fields = record.split(" ");
|
|
52
|
-
if (record[0] === "1") {
|
|
53
|
-
const path = fields.slice(8).join(" ").replaceAll("\\", "/");
|
|
54
|
-
if (path) paths.add(path);
|
|
55
|
-
} else if (record[0] === "2") {
|
|
56
|
-
const path = fields.slice(9).join(" ").replaceAll("\\", "/");
|
|
57
|
-
const oldPath = parts[index + 1]?.replaceAll("\\", "/");
|
|
58
|
-
if (path) paths.add(path);
|
|
59
|
-
if (oldPath) paths.add(oldPath);
|
|
60
|
-
index++;
|
|
61
|
-
} else if (record[0] === "u") {
|
|
62
|
-
const path = fields.slice(10).join(" ").replaceAll("\\", "/");
|
|
63
|
-
if (path) paths.add(path);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
return [...paths].sort((left, right) => left.localeCompare(right));
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async function readPathContent(root: string, path: string): Promise<Buffer | null> {
|
|
70
|
-
try {
|
|
71
|
-
return await readFile(join(root, path));
|
|
72
|
-
} catch {
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function sameContent(left: Buffer | null | undefined, right: Buffer | null): boolean {
|
|
78
|
-
if (left === undefined) return false;
|
|
79
|
-
if (left === null || right === null) return left === right;
|
|
80
|
-
return left.equals(right);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
async function restorePath(
|
|
84
|
-
git: GitRunner,
|
|
85
|
-
root: string,
|
|
86
|
-
path: string,
|
|
87
|
-
prior: Buffer | null | undefined,
|
|
88
|
-
): Promise<void> {
|
|
89
|
-
const absolute = join(root, path);
|
|
90
|
-
if (prior === undefined) {
|
|
91
|
-
// Was clean before the run: restore tracked paths from HEAD, delete new untracked paths.
|
|
92
|
-
const tracked = await git.run(["ls-files", "--error-unmatch", "--", path], {
|
|
93
|
-
cwd: root,
|
|
94
|
-
optional: true,
|
|
95
|
-
});
|
|
96
|
-
if (tracked) {
|
|
97
|
-
await git.run(["restore", "--worktree", "--source=HEAD", "--", path], { cwd: root });
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
await unlink(absolute).catch(() => {});
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
if (prior === null) {
|
|
104
|
-
await unlink(absolute).catch(() => {});
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
await mkdir(dirname(absolute), { recursive: true });
|
|
108
|
-
await writeFile(absolute, prior);
|
|
109
|
-
}
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import type { FileDepHit, FileDepQueryResult } from "../graph/file-graph.ts";
|
|
2
|
-
import { formatPathForDisplay } from "../../traverse.ts";
|
|
3
|
-
|
|
4
|
-
function depthPrefix(depth: number, showDepth: boolean): string {
|
|
5
|
-
return showDepth ? `d${depth} ` : "";
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/** Factor shared directory prefixes into a small indent tree. */
|
|
9
|
-
function formatInternalTree(
|
|
10
|
-
paths: readonly { depth: number; path: string }[],
|
|
11
|
-
cwd: string,
|
|
12
|
-
showDepth: boolean,
|
|
13
|
-
): string[] {
|
|
14
|
-
if (paths.length === 0) return [];
|
|
15
|
-
const rows = paths.map((hit) => ({
|
|
16
|
-
depth: hit.depth,
|
|
17
|
-
display: formatPathForDisplay(hit.path, cwd),
|
|
18
|
-
}));
|
|
19
|
-
|
|
20
|
-
// Common directory prefix across displays (posix-ish split on /).
|
|
21
|
-
const split = rows.map((row) => row.display.split("/"));
|
|
22
|
-
let common = 0;
|
|
23
|
-
const first = split[0];
|
|
24
|
-
if (first !== undefined && split.length > 1) {
|
|
25
|
-
while (common < first.length - 1) {
|
|
26
|
-
const part = first[common];
|
|
27
|
-
if (part === undefined) break;
|
|
28
|
-
if (!split.every((parts) => parts[common] === part)) break;
|
|
29
|
-
common += 1;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const lines: string[] = [];
|
|
34
|
-
if (common > 0 && first !== undefined) {
|
|
35
|
-
lines.push(first.slice(0, common).join("/"));
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
for (let i = 0; i < rows.length; i += 1) {
|
|
39
|
-
const row = rows[i];
|
|
40
|
-
const parts = split[i];
|
|
41
|
-
if (row === undefined || parts === undefined) continue;
|
|
42
|
-
const leaf = common > 0 ? parts.slice(common).join("/") : row.display;
|
|
43
|
-
const indent = common > 0 ? " " : "";
|
|
44
|
-
lines.push(`${indent}${depthPrefix(row.depth, showDepth)}${leaf}`);
|
|
45
|
-
}
|
|
46
|
-
return lines;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function formatDepsResult(result: FileDepQueryResult, cwd: string, emptyLabel: string): string {
|
|
50
|
-
const showDepth = result.depth > 1;
|
|
51
|
-
const internal = result.hits
|
|
52
|
-
.filter((hit): hit is FileDepHit & { path: string } => hit.path !== undefined)
|
|
53
|
-
.map((hit) => ({ depth: hit.depth, path: hit.path }));
|
|
54
|
-
const external = result.hits
|
|
55
|
-
.filter((hit): hit is FileDepHit & { externalId: string } => hit.externalId !== undefined)
|
|
56
|
-
.map((hit) => ({ depth: hit.depth, id: hit.externalId }));
|
|
57
|
-
|
|
58
|
-
if (internal.length === 0 && external.length === 0) {
|
|
59
|
-
return emptyLabel;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const lines: string[] = [];
|
|
63
|
-
lines.push(...formatInternalTree(internal, cwd, showDepth));
|
|
64
|
-
|
|
65
|
-
if (external.length > 0) {
|
|
66
|
-
if (lines.length > 0) lines.push("external:");
|
|
67
|
-
else lines.push("external:");
|
|
68
|
-
for (const hit of external) {
|
|
69
|
-
lines.push(` ${depthPrefix(hit.depth, showDepth)}${hit.id}`);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (result.resultLimitReached) {
|
|
74
|
-
lines.push(`omitted (result limit ${result.resultLimit})`);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return lines.join("\n");
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function formatDepsEmpty(): string {
|
|
81
|
-
return "No file dependencies";
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export function formatReverseDepsEmpty(): string {
|
|
85
|
-
return "No reverse file dependencies";
|
|
86
|
-
}
|
|
Binary file
|
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
import { relative, resolve, sep } from "node:path";
|
|
3
|
-
import type { FileDepHost, FileDepResolver } from "../adapter.ts";
|
|
4
|
-
import { collectFilesWithExtensions, externalId, internalPaths, isWithin } from "./file-dep-util.ts";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* C# file deps — ast-bro style.
|
|
8
|
-
*
|
|
9
|
-
* Index path suffixes + `namespace.Type` FQNs. Each `using` resolves to at most
|
|
10
|
-
* one internal file (`pickClosest` on ties). Bare namespace usings that don't
|
|
11
|
-
* match a type/path become external ids — never "every file in the namespace".
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
type CsharpIndex = {
|
|
15
|
-
/** slash-key → absolute paths */
|
|
16
|
-
bySuffix: Map<string, string[]>;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
/** BCL / engine — never treat polyfills as project file edges. */
|
|
20
|
-
function isFrameworkNamespace(ns: string): boolean {
|
|
21
|
-
if (ns === "System" || ns.startsWith("System.")) return true;
|
|
22
|
-
if (ns === "Microsoft" || ns.startsWith("Microsoft.")) return true;
|
|
23
|
-
if (ns === "Windows" || ns.startsWith("Windows.")) return true;
|
|
24
|
-
if (ns === "UnityEngine" || ns.startsWith("UnityEngine.")) return true;
|
|
25
|
-
if (ns === "UnityEditor" || ns.startsWith("UnityEditor.")) return true;
|
|
26
|
-
if (ns === "Godot" || ns.startsWith("Godot.")) return true;
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function normalizeUsing(specifier: string): string {
|
|
31
|
-
let s = specifier.trim().replace(/;$/u, "").trim();
|
|
32
|
-
s = s.replace(/^global\s+/iu, "").trim();
|
|
33
|
-
s = s.replace(/^static\s+/iu, "").trim();
|
|
34
|
-
// Alias: using A = X.Y.Z → resolve the target.
|
|
35
|
-
const eq = s.indexOf("=");
|
|
36
|
-
if (eq !== -1) s = s.slice(eq + 1).trim();
|
|
37
|
-
return s;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const TYPE_KEYWORDS = ["class ", "struct ", "interface ", "record ", "enum ", "delegate "] as const;
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Scan source for namespace + type pairs (sequential — types bind to the
|
|
44
|
-
* nearest preceding namespace declaration).
|
|
45
|
-
*/
|
|
46
|
-
function typesByNamespace(head: string): { ns: string; typeName: string }[] {
|
|
47
|
-
const out: { ns: string; typeName: string }[] = [];
|
|
48
|
-
let currentNs: string | undefined;
|
|
49
|
-
for (const raw of head.split("\n")) {
|
|
50
|
-
const line = raw.trim();
|
|
51
|
-
if (line.length === 0 || line.startsWith("//")) continue;
|
|
52
|
-
|
|
53
|
-
// file-scoped `namespace X;`, block `namespace X {`, or `namespace X` + brace next line
|
|
54
|
-
const nsMatch =
|
|
55
|
-
/^(?:internal\s+)?namespace\s+([A-Za-z_][\w.]*)\s*[;{]?\s*$/u.exec(line) ??
|
|
56
|
-
/^(?:internal\s+)?namespace\s+([A-Za-z_][\w.]*)\s*[{/]/u.exec(line);
|
|
57
|
-
if (nsMatch?.[1] !== undefined) {
|
|
58
|
-
currentNs = nsMatch[1];
|
|
59
|
-
continue;
|
|
60
|
-
}
|
|
61
|
-
if (currentNs === undefined) continue;
|
|
62
|
-
|
|
63
|
-
for (const kw of TYPE_KEYWORDS) {
|
|
64
|
-
const idx = line.indexOf(kw);
|
|
65
|
-
if (idx === -1) continue;
|
|
66
|
-
if (idx > 0 && /[A-Za-z0-9_]/u.test(line.charAt(idx - 1))) continue;
|
|
67
|
-
const rest = line.slice(idx + kw.length).trimStart();
|
|
68
|
-
const name = /^([A-Za-z_][\w]*)/u.exec(rest)?.[1];
|
|
69
|
-
if (name !== undefined) out.push({ ns: currentNs, typeName: name });
|
|
70
|
-
break;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return out;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function pushSuffix(map: Map<string, string[]>, key: string, file: string): void {
|
|
77
|
-
if (key.length === 0) return;
|
|
78
|
-
const list = map.get(key);
|
|
79
|
-
if (list === undefined) map.set(key, [file]);
|
|
80
|
-
else if (!list.includes(file)) list.push(file);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/** Index every slash-suffix of a stem path: a/b/c → a/b/c, b/c, c */
|
|
84
|
-
function indexPathSuffixes(map: Map<string, string[]>, file: string, stemRelPosix: string): void {
|
|
85
|
-
const parts = stemRelPosix.split("/").filter((part) => part.length > 0);
|
|
86
|
-
for (let i = 0; i < parts.length; i += 1) {
|
|
87
|
-
pushSuffix(map, parts.slice(i).join("/"), file);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function toPosixRel(scopeRoot: string, file: string): string | undefined {
|
|
92
|
-
const rel = relative(resolve(scopeRoot), resolve(file));
|
|
93
|
-
if (rel.startsWith(`..${sep}`) || rel === ".." || rel.length === 0) return undefined;
|
|
94
|
-
return rel.split(sep).join("/");
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
async function buildIndex(host: FileDepHost, signal: AbortSignal): Promise<CsharpIndex> {
|
|
98
|
-
const key = `csharp-suffix:${host.scopeRoot}`;
|
|
99
|
-
const cached = host.memo.get(key);
|
|
100
|
-
if (cached !== undefined) return cached as CsharpIndex;
|
|
101
|
-
|
|
102
|
-
const bySuffix = new Map<string, string[]>();
|
|
103
|
-
const files = await collectFilesWithExtensions(host, host.scopeRoot, [".cs"], signal);
|
|
104
|
-
|
|
105
|
-
for (const file of files) {
|
|
106
|
-
signal.throwIfAborted();
|
|
107
|
-
const rel = toPosixRel(host.scopeRoot, file);
|
|
108
|
-
if (rel === undefined) continue;
|
|
109
|
-
|
|
110
|
-
const dot = rel.lastIndexOf(".");
|
|
111
|
-
const stem = dot >= 0 ? rel.slice(0, dot) : rel;
|
|
112
|
-
indexPathSuffixes(bySuffix, file, stem);
|
|
113
|
-
|
|
114
|
-
let text: string;
|
|
115
|
-
try {
|
|
116
|
-
text = await readFile(file, "utf8");
|
|
117
|
-
} catch {
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
const head = text.slice(0, 12000);
|
|
121
|
-
// FQN only — bare type names are too ambiguous (Platform, View, …).
|
|
122
|
-
for (const { ns, typeName } of typesByNamespace(head)) {
|
|
123
|
-
const fqn = `${ns}.${typeName}`.replace(/\./gu, "/");
|
|
124
|
-
pushSuffix(bySuffix, fqn, file);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
for (const [, list] of bySuffix) list.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
129
|
-
const index: CsharpIndex = { bySuffix };
|
|
130
|
-
host.memo.set(key, index);
|
|
131
|
-
return index;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/** Prefer the candidate sharing the most path prefix with the importer. */
|
|
135
|
-
function pickClosest(candidates: readonly string[], fromPath: string): string | undefined {
|
|
136
|
-
if (candidates.length === 0) return undefined;
|
|
137
|
-
if (candidates.length === 1) return candidates[0];
|
|
138
|
-
|
|
139
|
-
const fromSegs = resolve(fromPath).split(sep);
|
|
140
|
-
let best: string | undefined;
|
|
141
|
-
let bestCommon = -1;
|
|
142
|
-
for (const candidate of candidates) {
|
|
143
|
-
const segs = resolve(candidate).split(sep);
|
|
144
|
-
let common = 0;
|
|
145
|
-
const n = Math.min(fromSegs.length, segs.length);
|
|
146
|
-
while (common < n && fromSegs[common] === segs[common]) common += 1;
|
|
147
|
-
if (best === undefined || common > bestCommon || (common === bestCommon && candidate < best)) {
|
|
148
|
-
best = candidate;
|
|
149
|
-
bestCommon = common;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return best;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function lookup(index: CsharpIndex, key: string): readonly string[] | undefined {
|
|
156
|
-
const list = index.bySuffix.get(key);
|
|
157
|
-
if (list === undefined || list.length === 0) return undefined;
|
|
158
|
-
return list;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function resolveKey(index: CsharpIndex, fromPath: string, dotted: string): string | undefined {
|
|
162
|
-
const key = dotted.replace(/\./gu, "/");
|
|
163
|
-
const hit = pickClosest(lookup(index, key) ?? [], fromPath);
|
|
164
|
-
if (hit !== undefined) return hit;
|
|
165
|
-
|
|
166
|
-
// Nested type: Foo.Bar.Inner → try Foo.Bar file.
|
|
167
|
-
const slash = key.lastIndexOf("/");
|
|
168
|
-
if (slash <= 0) return undefined;
|
|
169
|
-
const parent = key.slice(0, slash);
|
|
170
|
-
return pickClosest(lookup(index, parent) ?? [], fromPath);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
export const resolveCsharpFileDep: FileDepResolver = async (fromPath, specifier, host, signal) => {
|
|
174
|
-
signal.throwIfAborted();
|
|
175
|
-
const dotted = normalizeUsing(specifier);
|
|
176
|
-
if (dotted.length === 0) return { kind: "unresolved" };
|
|
177
|
-
|
|
178
|
-
if (isFrameworkNamespace(dotted)) return externalId(dotted);
|
|
179
|
-
|
|
180
|
-
const index = await buildIndex(host, signal);
|
|
181
|
-
const file = resolveKey(index, fromPath, dotted);
|
|
182
|
-
if (file === undefined) return externalId(dotted);
|
|
183
|
-
if (!isWithin(host.scopeRoot, file) && resolve(file) !== resolve(host.scopeRoot)) {
|
|
184
|
-
return externalId(dotted);
|
|
185
|
-
}
|
|
186
|
-
if (!host.ownsPath(file)) return externalId(dotted);
|
|
187
|
-
if (resolve(file) === resolve(fromPath)) return { kind: "unresolved" };
|
|
188
|
-
return internalPaths([file]);
|
|
189
|
-
};
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
using System;
|
|
2
|
-
|
|
3
|
-
namespace Demo;
|
|
4
|
-
|
|
5
|
-
/// <summary>Greeter</summary>
|
|
6
|
-
public class Greeter {
|
|
7
|
-
private int count;
|
|
8
|
-
public string Name { get; set; }
|
|
9
|
-
public Greeter() {}
|
|
10
|
-
public void Hello() {}
|
|
11
|
-
public event EventHandler Done;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
internal struct Box {}
|
|
15
|
-
public interface IGreeter { void Hello(); }
|
|
16
|
-
public enum Color { Red, Green }
|
|
17
|
-
public record Person(string Name);
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
package com.demo;
|
|
2
|
-
|
|
3
|
-
import java.util.List;
|
|
4
|
-
|
|
5
|
-
/** Greeter type. */
|
|
6
|
-
public class Greeter {
|
|
7
|
-
private int count;
|
|
8
|
-
public Greeter() {}
|
|
9
|
-
public void hello() {}
|
|
10
|
-
public static final int MAX = 10;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface Named {
|
|
14
|
-
void name();
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
enum Color {
|
|
18
|
-
RED,
|
|
19
|
-
GREEN;
|
|
20
|
-
void paint() {}
|
|
21
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
package demo
|
|
2
|
-
|
|
3
|
-
import "core:fmt"
|
|
4
|
-
|
|
5
|
-
// Add two ints
|
|
6
|
-
add :: proc(a: int, b: int) -> int {
|
|
7
|
-
return a + b
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
Point :: struct {
|
|
11
|
-
x: int,
|
|
12
|
-
y: int,
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
Color :: enum {
|
|
16
|
-
Red,
|
|
17
|
-
Green,
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
Value :: union {
|
|
21
|
-
int,
|
|
22
|
-
f32,
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
PI :: 3.14
|
|
26
|
-
|
|
27
|
-
@(private)
|
|
28
|
-
secret :: proc() {}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/// Point in 2D.
|
|
2
|
-
#[derive(Debug, Clone)]
|
|
3
|
-
pub struct Point {
|
|
4
|
-
pub x: i32,
|
|
5
|
-
y: i32,
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/// Drawable.
|
|
9
|
-
pub trait Draw {
|
|
10
|
-
fn draw(&self);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
impl Point {
|
|
14
|
-
/// Origin.
|
|
15
|
-
pub fn origin() -> Self {
|
|
16
|
-
Self { x: 0, y: 0 }
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
impl Draw for Point {
|
|
21
|
-
fn draw(&self) {}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
pub mod nested {
|
|
25
|
-
pub fn inner() {}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
pub const MAX: i32 = 10;
|
|
29
|
-
pub type Alias = i32;
|
|
30
|
-
|
|
31
|
-
fn private_fn() {}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
|
|
3
|
-
/// Greeter type
|
|
4
|
-
public class Greeter {
|
|
5
|
-
public var name: String = ""
|
|
6
|
-
public init() {}
|
|
7
|
-
public func hello() {}
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
extension Greeter {
|
|
11
|
-
public func shout() {}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
public protocol Named {
|
|
15
|
-
func name()
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
internal struct Box {
|
|
19
|
-
var value: Int
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
private enum Color {
|
|
23
|
-
case red
|
|
24
|
-
case green
|
|
25
|
-
}
|