@akira-tl/forgerelay 0.3.7 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/capabilities/code-intelligence/GUIDE.md +11 -0
- package/dist/capabilities.js +6 -0
- package/dist/capability-registry.js +20 -0
- package/dist/config.js +1 -0
- package/dist/lsp/code-intelligence-error.js +8 -0
- package/dist/lsp/code-intelligence-types.js +1 -0
- package/dist/lsp/code-intelligence.js +595 -0
- package/dist/lsp/language-server-config.js +313 -0
- package/dist/lsp/normalization/hover.js +29 -0
- package/dist/lsp/position-encoding.js +88 -0
- package/dist/server.js +22 -2
- package/docs/configuration.md +65 -0
- package/docs/roadmap.md +15 -0
- package/package.json +4 -2
- package/scripts/debug/accept.mjs +15 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,36 @@ All notable ForgeRelay changes are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.4.1] - 2026-08-11
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Added `code.intelligence` `hover` support through the same shared Language-service and filesystem synchronization path as definition lookup.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Hover responses now normalize Markdown/plaintext `MarkupContent` and supported legacy `MarkedString` payloads into a stable Agent-facing `contents` value with optional language and normalized range metadata.
|
|
16
|
+
- Language Servers that do not advertise hover return `code.operation_unsupported` without invalidating the shared Language service.
|
|
17
|
+
|
|
18
|
+
## [0.4.0] - 2026-08-11
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- Added `code.intelligence` as a Capability Gateway-only LSP code-intelligence surface. ForgeRelay 0.4.0 ships the first complete `definition` tracer bullet without changing the canonical nine Core MCP tools.
|
|
23
|
+
- Added Language-server definitions with project (`.forgerelay/language-servers.json`), global (`~/.forgerelay/config.json`), and built-in discovery precedence. Common built-ins cover TypeScript/JavaScript, Pyright, rust-analyzer, gopls, and clangd when those executables are already installed.
|
|
24
|
+
- Added a deterministic child-process fake LSP server and MCP-level regression seam covering initialize/shutdown, document synchronization, definition normalization, shared Language-service identity, capacity limits, and server-initiated edit rejection.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Code-intelligence positions use ForgeRelay's 1-based line and Unicode code-point column contract and are converted internally to the position encoding negotiated with the Language Server.
|
|
29
|
+
- Language services are shared by canonical Language project root plus effective server-definition fingerprint rather than logical workspace ID, remain capacity/idle bounded, and use structured no-shell process launch over Microsoft's `vscode-jsonrpc` / `vscode-languageserver-protocol` substrate.
|
|
30
|
+
- Language-server configuration can explicitly disable built-in discovery; nested Language projects resolve by walking ancestors of the requested source path instead of recursively scanning the Workspace.
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- External LSP definition targets are marked as informational external locations without expanding ForgeRelay file-read authority, including symlink-escape protection and canonical Workspace-root handling.
|
|
35
|
+
- Language-server startup failure/timeout, unsupported operations, invalid positions, configuration ambiguity, capacity exhaustion, and other policy failures now use stable ForgeRelay `code.*` errors instead of leaking raw JSON-RPC failures.
|
|
36
|
+
|
|
7
37
|
## [0.3.7] - 2026-08-10
|
|
8
38
|
|
|
9
39
|
### Added
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Code Intelligence
|
|
2
|
+
|
|
3
|
+
Use the `code.intelligence` Capability for read-only semantic code navigation backed by Language servers that are already installed on the user's machine or explicitly configured for the project.
|
|
4
|
+
|
|
5
|
+
ForgeRelay does not install Language servers. It discovers supported executables when available and accepts explicit definitions from the global ForgeRelay config or `<workspace>/.forgerelay/language-servers.json`. Project definitions override global definitions, and global definitions override built-in discovery. An explicit definition may disable discovery with `enabled: false`.
|
|
6
|
+
|
|
7
|
+
ForgeRelay 0.4.1 supports `definition` and `hover`. Both position-based operations accept a workspace-relative source `path` plus 1-based `line` and `column` values. Columns are Unicode code-point positions; ForgeRelay converts them to the position encoding negotiated with the Language server.
|
|
8
|
+
|
|
9
|
+
Code-intelligence results use ForgeRelay-owned shapes rather than raw LSP wire types. Definition returns normalized locations. Hover returns one `contents` string, an optional legacy `language`, and an optional ForgeRelay-normalized `range`; plaintext, Markdown `MarkupContent`, and supported legacy `MarkedString` payloads are normalized before reaching the Agent. A definition may identify an External code location outside the Workspace, but that does not expand ForgeRelay's allowed roots or grant the file tools permission to read that path.
|
|
10
|
+
|
|
11
|
+
Language-server definitions use structured process configuration rather than shell command strings. A project configuration entry may contain `command`, `args`, `env`, `languages`, `extensions`, `languageIdByExtension`, `projectMarkers`, and `enabled` fields. Use `languageIdByExtension` when one server definition covers multiple language IDs whose extensions do not map one-to-one by array position. The server command is launched directly without a shell.
|
package/dist/capabilities.js
CHANGED
|
@@ -34,6 +34,11 @@ const CAPABILITY_GUIDE_DEFINITIONS = [
|
|
|
34
34
|
description: "Long-running bash processes, processId interaction, PTY, and platform edges.",
|
|
35
35
|
whenToRead: "Read for running or interactive command issues.",
|
|
36
36
|
},
|
|
37
|
+
{
|
|
38
|
+
name: "code-intelligence",
|
|
39
|
+
description: "Read-only semantic code navigation backed by external Language servers.",
|
|
40
|
+
whenToRead: "Read before using code.intelligence or configuring Language servers.",
|
|
41
|
+
},
|
|
37
42
|
];
|
|
38
43
|
function capabilityGuidesDir() {
|
|
39
44
|
return fileURLToPath(new URL("../capabilities", import.meta.url));
|
|
@@ -75,6 +80,7 @@ export function buildCapabilityFingerprint(config, version, context = {}) {
|
|
|
75
80
|
"process.lifecycle",
|
|
76
81
|
"hooks.lifecycle",
|
|
77
82
|
"capability-guides.read",
|
|
83
|
+
"code.intelligence",
|
|
78
84
|
];
|
|
79
85
|
if (config.subagents) {
|
|
80
86
|
capabilities.push("subagent.profiles");
|
|
@@ -115,6 +115,12 @@ export class CapabilityRegistry {
|
|
|
115
115
|
}
|
|
116
116
|
export function createCapabilityRegistry(dependencies) {
|
|
117
117
|
const hooksCheckInput = z.object({}).strict();
|
|
118
|
+
const codeIntelligenceInput = z.object({
|
|
119
|
+
operation: z.enum(["definition", "hover"]),
|
|
120
|
+
path: z.string().min(1),
|
|
121
|
+
line: z.number().int(),
|
|
122
|
+
column: z.number().int(),
|
|
123
|
+
}).strict();
|
|
118
124
|
return new CapabilityRegistry([
|
|
119
125
|
{
|
|
120
126
|
name: "hooks.check",
|
|
@@ -144,6 +150,20 @@ export function createCapabilityRegistry(dependencies) {
|
|
|
144
150
|
run: async (_input, context) => dependencies.reviewChanges.run(context),
|
|
145
151
|
}]
|
|
146
152
|
: []),
|
|
153
|
+
...(dependencies.codeIntelligence
|
|
154
|
+
? [{
|
|
155
|
+
name: "code.intelligence",
|
|
156
|
+
description: "Read semantic code information through an available Language server without changing the Workspace.",
|
|
157
|
+
guideName: "code-intelligence",
|
|
158
|
+
readGuideBeforeFirstUse: true,
|
|
159
|
+
inputSchema: codeIntelligenceInput,
|
|
160
|
+
availability: () => ({
|
|
161
|
+
available: dependencies.codeIntelligence?.available ?? false,
|
|
162
|
+
reason: dependencies.codeIntelligence?.unavailableReason,
|
|
163
|
+
}),
|
|
164
|
+
run: async (input, context) => dependencies.codeIntelligence.run(input, context),
|
|
165
|
+
}]
|
|
166
|
+
: []),
|
|
147
167
|
...(dependencies.downloadArtifact
|
|
148
168
|
? [{
|
|
149
169
|
name: "artifact.download",
|
package/dist/config.js
CHANGED
|
@@ -223,6 +223,7 @@ export function loadConfig(env = process.env) {
|
|
|
223
223
|
subagents: productEnv(env, "SUBAGENTS") === undefined
|
|
224
224
|
? files.config.subagents === true
|
|
225
225
|
: parseBoolean(productEnv(env, "SUBAGENTS")),
|
|
226
|
+
languageServers: files.config.languageServers ?? {},
|
|
226
227
|
agentDir: resolve(expandHomePath(productEnv(env, "AGENT_DIR") ?? files.config.agentDir ?? defaultAgentDir())),
|
|
227
228
|
systemInstructionsPath: parseSystemInstructionsPath(productEnv(env, "SYSTEM_INSTRUCTIONS_PATH") ?? files.config.systemInstructionsPath),
|
|
228
229
|
hooks: mergeHookConfigs(parseHookConfig(files.config.hooks), parseHookConfig(files.hooks), files.hookFiles),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|