forge-server 0.1.0 → 0.1.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.
Files changed (119) hide show
  1. package/bin/setup-forge.sh +1 -1
  2. package/bin/setup.js +99 -0
  3. package/dist/cli.js +37 -37
  4. package/dist/cli.js.map +1 -1
  5. package/dist/index.js +4 -4
  6. package/dist/index.js.map +1 -1
  7. package/dist/storage/schema.js +113 -113
  8. package/dist/storage/schema.js.map +1 -1
  9. package/dist/storage/sqlite.js +1 -1
  10. package/dist/storage/sqlite.js.map +1 -1
  11. package/dist/util/logger.d.ts +1 -1
  12. package/dist/util/logger.js +1 -1
  13. package/dist/util/types.js +1 -1
  14. package/dist/util/types.js.map +1 -1
  15. package/package.json +8 -2
  16. package/plugin/.mcp.json +1 -1
  17. package/.claude/hooks/worktree-create.sh +0 -64
  18. package/.claude/hooks/worktree-remove.sh +0 -57
  19. package/.claude/settings.local.json +0 -29
  20. package/.forge/knowledge/conventions.yaml +0 -1
  21. package/.forge/knowledge/decisions.yaml +0 -1
  22. package/.forge/knowledge/gotchas.yaml +0 -1
  23. package/.forge/knowledge/patterns.yaml +0 -1
  24. package/.forge/manifest.yaml +0 -6
  25. package/CLAUDE.md +0 -144
  26. package/docker-compose.yml +0 -20
  27. package/docs/plans/2026-02-27-swarm-coordination/architecture.md +0 -203
  28. package/docs/plans/2026-02-27-swarm-coordination/vision.md +0 -57
  29. package/docs/plans/completed/2026-02-26-forge-plugin-bundling/architecture.md +0 -1
  30. package/docs/plans/completed/2026-02-26-forge-plugin-bundling/vision.md +0 -300
  31. package/docs/plans/completed/2026-02-27-forge-swarm-learning/architecture.md +0 -480
  32. package/docs/plans/completed/2026-02-27-forge-swarm-learning/verification-checklist.md +0 -462
  33. package/docs/plans/completed/2026-02-27-git-history-atlassian/git-jira-plan.md +0 -181
  34. package/src/cli.ts +0 -655
  35. package/src/context/.gitkeep +0 -0
  36. package/src/context/codebase.ts +0 -393
  37. package/src/context/injector.ts +0 -797
  38. package/src/context/memory.ts +0 -187
  39. package/src/context/session-index.ts +0 -327
  40. package/src/context/session.ts +0 -152
  41. package/src/index.ts +0 -47
  42. package/src/ingestion/.gitkeep +0 -0
  43. package/src/ingestion/chunker.ts +0 -277
  44. package/src/ingestion/embedder.ts +0 -167
  45. package/src/ingestion/git-analyzer.ts +0 -545
  46. package/src/ingestion/indexer.ts +0 -984
  47. package/src/ingestion/markdown-chunker.ts +0 -337
  48. package/src/ingestion/markdown-knowledge.ts +0 -175
  49. package/src/ingestion/parser.ts +0 -475
  50. package/src/ingestion/watcher.ts +0 -182
  51. package/src/knowledge/.gitkeep +0 -0
  52. package/src/knowledge/hydrator.ts +0 -246
  53. package/src/knowledge/registry.ts +0 -463
  54. package/src/knowledge/search.ts +0 -565
  55. package/src/knowledge/store.ts +0 -262
  56. package/src/learning/.gitkeep +0 -0
  57. package/src/learning/confidence.ts +0 -193
  58. package/src/learning/patterns.ts +0 -360
  59. package/src/learning/trajectory.ts +0 -268
  60. package/src/memory/.gitkeep +0 -0
  61. package/src/memory/memory-compat.ts +0 -233
  62. package/src/memory/observation-store.ts +0 -224
  63. package/src/memory/session-tracker.ts +0 -332
  64. package/src/pipeline/.gitkeep +0 -0
  65. package/src/pipeline/engine.ts +0 -1139
  66. package/src/pipeline/events.ts +0 -253
  67. package/src/pipeline/parallel.ts +0 -394
  68. package/src/pipeline/state-machine.ts +0 -199
  69. package/src/query/.gitkeep +0 -0
  70. package/src/query/graph-queries.ts +0 -262
  71. package/src/query/hybrid-search.ts +0 -337
  72. package/src/query/intent-detector.ts +0 -131
  73. package/src/query/ranking.ts +0 -161
  74. package/src/server.ts +0 -352
  75. package/src/storage/.gitkeep +0 -0
  76. package/src/storage/falkordb-store.ts +0 -388
  77. package/src/storage/file-cache.ts +0 -141
  78. package/src/storage/interfaces.ts +0 -201
  79. package/src/storage/qdrant-store.ts +0 -557
  80. package/src/storage/schema.ts +0 -139
  81. package/src/storage/sqlite.ts +0 -168
  82. package/src/tools/.gitkeep +0 -0
  83. package/src/tools/collaboration-tools.ts +0 -208
  84. package/src/tools/context-tools.ts +0 -493
  85. package/src/tools/graph-tools.ts +0 -295
  86. package/src/tools/ingestion-tools.ts +0 -122
  87. package/src/tools/learning-tools.ts +0 -181
  88. package/src/tools/memory-tools.ts +0 -234
  89. package/src/tools/phase-tools.ts +0 -1452
  90. package/src/tools/pipeline-tools.ts +0 -188
  91. package/src/tools/registration-tools.ts +0 -450
  92. package/src/util/.gitkeep +0 -0
  93. package/src/util/circuit-breaker.ts +0 -193
  94. package/src/util/config.ts +0 -177
  95. package/src/util/logger.ts +0 -53
  96. package/src/util/token-counter.ts +0 -52
  97. package/src/util/types.ts +0 -710
  98. package/tests/context/.gitkeep +0 -0
  99. package/tests/integration/.gitkeep +0 -0
  100. package/tests/knowledge/.gitkeep +0 -0
  101. package/tests/learning/.gitkeep +0 -0
  102. package/tests/pipeline/.gitkeep +0 -0
  103. package/tests/tools/.gitkeep +0 -0
  104. package/tsconfig.json +0 -21
  105. package/vitest.config.ts +0 -10
  106. package/vscode-extension/.vscodeignore +0 -7
  107. package/vscode-extension/README.md +0 -43
  108. package/vscode-extension/out/edge-collector.js +0 -274
  109. package/vscode-extension/out/edge-collector.js.map +0 -1
  110. package/vscode-extension/out/extension.js +0 -264
  111. package/vscode-extension/out/extension.js.map +0 -1
  112. package/vscode-extension/out/forge-client.js +0 -318
  113. package/vscode-extension/out/forge-client.js.map +0 -1
  114. package/vscode-extension/package-lock.json +0 -59
  115. package/vscode-extension/package.json +0 -71
  116. package/vscode-extension/src/edge-collector.ts +0 -320
  117. package/vscode-extension/src/extension.ts +0 -269
  118. package/vscode-extension/src/forge-client.ts +0 -364
  119. package/vscode-extension/tsconfig.json +0 -19
@@ -1,364 +0,0 @@
1
- // forge-client.ts — Forge LSP Bridge
2
- // MCP stdio client that spawns the dk-forge-server as a child process and
3
- // communicates via JSON-RPC 2.0 over stdio with Content-Length framing.
4
- //
5
- // This client is purpose-built for submitting LSP edges via the
6
- // `submit_lsp_edges` tool. It lazily spawns the server on first use and
7
- // reuses the connection for subsequent calls.
8
-
9
- import { spawn, ChildProcess } from 'child_process';
10
- import * as path from 'path';
11
- import type { LspEdge } from './edge-collector';
12
-
13
- // ---------------------------------------------------------------------------
14
- // Types
15
- // ---------------------------------------------------------------------------
16
-
17
- interface JsonRpcRequest {
18
- jsonrpc: '2.0';
19
- id: number;
20
- method: string;
21
- params?: unknown;
22
- }
23
-
24
- interface JsonRpcResponse {
25
- jsonrpc: '2.0';
26
- id: number;
27
- result?: unknown;
28
- error?: { code: number; message: string; data?: unknown };
29
- }
30
-
31
- interface ToolCallResult {
32
- content?: Array<{ type: string; text: string }>;
33
- isError?: boolean;
34
- }
35
-
36
- interface SubmitLspEdgesResult {
37
- accepted: number;
38
- failed: number;
39
- errors?: string[];
40
- }
41
-
42
- // ---------------------------------------------------------------------------
43
- // ForgeClient
44
- // ---------------------------------------------------------------------------
45
-
46
- export class ForgeClient {
47
- private process: ChildProcess | undefined;
48
- private readonly serverPath: string;
49
- private nextId = 1;
50
- private responseBuffer = '';
51
- private pendingRequests = new Map<number, {
52
- resolve: (value: JsonRpcResponse) => void;
53
- reject: (reason: Error) => void;
54
- timer: ReturnType<typeof setTimeout>;
55
- }>();
56
- private initialized = false;
57
- private initializing: Promise<void> | undefined;
58
- private disposed = false;
59
-
60
- /**
61
- * @param serverPath Absolute path to the dk-forge-server entry point.
62
- * If empty, resolves to the bundled dist/index.js relative to this extension.
63
- */
64
- constructor(serverPath: string) {
65
- if (serverPath) {
66
- this.serverPath = serverPath;
67
- } else {
68
- // Default: assume forge-pipeline-server is a sibling or parent checkout
69
- // The extension is at vscode-extension/ inside the server repo, so:
70
- // ../dist/index.js is the compiled server entry
71
- this.serverPath = path.resolve(__dirname, '..', '..', 'dist', 'index.js');
72
- }
73
- }
74
-
75
- // -------------------------------------------------------------------------
76
- // Public API
77
- // -------------------------------------------------------------------------
78
-
79
- /**
80
- * Submit a batch of LSP edges to the forge server's submit_lsp_edges tool.
81
- */
82
- async submitLspEdges(
83
- repoId: string,
84
- edges: LspEdge[],
85
- ): Promise<SubmitLspEdgesResult | undefined> {
86
- if (this.disposed) {
87
- return undefined;
88
- }
89
-
90
- if (edges.length === 0) {
91
- return { accepted: 0, failed: 0 };
92
- }
93
-
94
- await this.ensureInitialized();
95
-
96
- // MCP tool call: tools/call with the tool name and arguments
97
- const response = await this.sendRequest('tools/call', {
98
- name: 'submit_lsp_edges',
99
- arguments: {
100
- repo_id: repoId,
101
- edges,
102
- },
103
- });
104
-
105
- if (response.error) {
106
- throw new Error(
107
- `MCP error ${response.error.code}: ${response.error.message}`,
108
- );
109
- }
110
-
111
- // Parse the tool result — MCP wraps tool output in content blocks
112
- const toolResult = response.result as ToolCallResult | undefined;
113
- if (toolResult?.content && toolResult.content.length > 0) {
114
- const firstContent = toolResult.content[0];
115
- if (firstContent && firstContent.type === 'text') {
116
- try {
117
- return JSON.parse(firstContent.text) as SubmitLspEdgesResult;
118
- } catch {
119
- return undefined;
120
- }
121
- }
122
- }
123
-
124
- return undefined;
125
- }
126
-
127
- /**
128
- * Dispose the client and kill the child process.
129
- */
130
- dispose(): void {
131
- this.disposed = true;
132
- this.clearAllPending('Client disposed');
133
- this.killProcess();
134
- }
135
-
136
- // -------------------------------------------------------------------------
137
- // Process lifecycle
138
- // -------------------------------------------------------------------------
139
-
140
- private async ensureInitialized(): Promise<void> {
141
- if (this.initialized && this.process && !this.process.killed) {
142
- return;
143
- }
144
-
145
- // Prevent concurrent initialization
146
- if (this.initializing) {
147
- await this.initializing;
148
- return;
149
- }
150
-
151
- this.initializing = this.doInitialize();
152
- try {
153
- await this.initializing;
154
- } finally {
155
- this.initializing = undefined;
156
- }
157
- }
158
-
159
- private async doInitialize(): Promise<void> {
160
- this.killProcess();
161
- this.initialized = false;
162
-
163
- // Spawn the forge server as a child process on stdio
164
- this.process = spawn('node', [this.serverPath], {
165
- stdio: ['pipe', 'pipe', 'pipe'],
166
- env: {
167
- ...process.env,
168
- // Prevent forge server from polluting stdout with log messages
169
- FORGE_LOG_LEVEL: 'warn',
170
- },
171
- windowsHide: true,
172
- });
173
-
174
- // Wire up stdout for JSON-RPC responses
175
- this.process.stdout?.on('data', (chunk: Buffer) => {
176
- this.onData(chunk.toString('utf8'));
177
- });
178
-
179
- // Log stderr but don't treat it as fatal
180
- this.process.stderr?.on('data', (chunk: Buffer) => {
181
- // stderr output from the forge server is informational
182
- void chunk; // suppress unused variable
183
- });
184
-
185
- this.process.on('error', (err) => {
186
- this.clearAllPending(`Process error: ${err.message}`);
187
- this.initialized = false;
188
- });
189
-
190
- this.process.on('exit', (code) => {
191
- this.clearAllPending(`Process exited with code ${String(code)}`);
192
- this.initialized = false;
193
- });
194
-
195
- // Send the MCP initialize handshake
196
- const initResponse = await this.sendRequest('initialize', {
197
- protocolVersion: '2024-11-05',
198
- capabilities: {},
199
- clientInfo: {
200
- name: 'forge-lsp-bridge',
201
- version: '0.1.0',
202
- },
203
- });
204
-
205
- if (initResponse.error) {
206
- throw new Error(
207
- `MCP initialize failed: ${initResponse.error.message}`,
208
- );
209
- }
210
-
211
- // Send initialized notification (no response expected)
212
- this.sendNotification('notifications/initialized', {});
213
-
214
- this.initialized = true;
215
- }
216
-
217
- private killProcess(): void {
218
- if (this.process) {
219
- try {
220
- this.process.kill('SIGTERM');
221
- } catch {
222
- // Process may already be dead
223
- }
224
- this.process = undefined;
225
- }
226
- }
227
-
228
- // -------------------------------------------------------------------------
229
- // JSON-RPC over stdio with Content-Length framing
230
- // -------------------------------------------------------------------------
231
-
232
- private sendRequest(method: string, params?: unknown): Promise<JsonRpcResponse> {
233
- return new Promise((resolve, reject) => {
234
- if (!this.process || !this.process.stdin || this.process.killed) {
235
- reject(new Error('Forge server process is not running'));
236
- return;
237
- }
238
-
239
- const id = this.nextId++;
240
- const request: JsonRpcRequest = {
241
- jsonrpc: '2.0',
242
- id,
243
- method,
244
- params,
245
- };
246
-
247
- const body = JSON.stringify(request);
248
- const header = `Content-Length: ${Buffer.byteLength(body, 'utf8')}\r\n\r\n`;
249
-
250
- // Timeout after 30 seconds
251
- const timer = setTimeout(() => {
252
- const pending = this.pendingRequests.get(id);
253
- if (pending) {
254
- this.pendingRequests.delete(id);
255
- pending.reject(new Error(`Request ${method} timed out after 30s`));
256
- }
257
- }, 30_000);
258
-
259
- this.pendingRequests.set(id, { resolve, reject, timer });
260
-
261
- try {
262
- this.process.stdin.write(header + body, 'utf8');
263
- } catch (err) {
264
- this.pendingRequests.delete(id);
265
- clearTimeout(timer);
266
- reject(new Error(`Failed to write to forge server: ${String(err)}`));
267
- }
268
- });
269
- }
270
-
271
- private sendNotification(method: string, params?: unknown): void {
272
- if (!this.process || !this.process.stdin || this.process.killed) {
273
- return;
274
- }
275
-
276
- const notification = {
277
- jsonrpc: '2.0' as const,
278
- method,
279
- params,
280
- };
281
-
282
- const body = JSON.stringify(notification);
283
- const header = `Content-Length: ${Buffer.byteLength(body, 'utf8')}\r\n\r\n`;
284
-
285
- try {
286
- this.process.stdin.write(header + body, 'utf8');
287
- } catch {
288
- // Notifications are fire-and-forget
289
- }
290
- }
291
-
292
- /**
293
- * Handle incoming data from the server's stdout.
294
- * Parses Content-Length framed JSON-RPC messages.
295
- */
296
- private onData(chunk: string): void {
297
- this.responseBuffer += chunk;
298
- this.processBuffer();
299
- }
300
-
301
- private processBuffer(): void {
302
- // eslint-disable-next-line no-constant-condition
303
- while (true) {
304
- // Look for Content-Length header
305
- const headerEnd = this.responseBuffer.indexOf('\r\n\r\n');
306
- if (headerEnd === -1) {
307
- break;
308
- }
309
-
310
- const headerSection = this.responseBuffer.substring(0, headerEnd);
311
- const contentLengthMatch = headerSection.match(/Content-Length:\s*(\d+)/i);
312
- if (!contentLengthMatch || !contentLengthMatch[1]) {
313
- // Malformed header — skip past the double CRLF and try again
314
- this.responseBuffer = this.responseBuffer.substring(headerEnd + 4);
315
- continue;
316
- }
317
-
318
- const contentLength = parseInt(contentLengthMatch[1], 10);
319
- const bodyStart = headerEnd + 4;
320
- const bodyEnd = bodyStart + contentLength;
321
-
322
- if (this.responseBuffer.length < bodyEnd) {
323
- // Not enough data yet — wait for more
324
- break;
325
- }
326
-
327
- const body = this.responseBuffer.substring(bodyStart, bodyEnd);
328
- this.responseBuffer = this.responseBuffer.substring(bodyEnd);
329
-
330
- try {
331
- const message = JSON.parse(body) as JsonRpcResponse;
332
- this.handleResponse(message);
333
- } catch {
334
- // Malformed JSON — skip this message
335
- }
336
- }
337
- }
338
-
339
- private handleResponse(message: JsonRpcResponse): void {
340
- // Only handle responses (messages with an id and no method)
341
- if (message.id === undefined || message.id === null) {
342
- // This is a notification from the server — ignore
343
- return;
344
- }
345
-
346
- const pending = this.pendingRequests.get(message.id);
347
- if (!pending) {
348
- // Response for an unknown or timed-out request — discard
349
- return;
350
- }
351
-
352
- this.pendingRequests.delete(message.id);
353
- clearTimeout(pending.timer);
354
- pending.resolve(message);
355
- }
356
-
357
- private clearAllPending(reason: string): void {
358
- for (const [id, pending] of this.pendingRequests) {
359
- clearTimeout(pending.timer);
360
- pending.reject(new Error(reason));
361
- this.pendingRequests.delete(id);
362
- }
363
- }
364
- }
@@ -1,19 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "commonjs",
5
- "lib": ["ES2022"],
6
- "outDir": "out",
7
- "rootDir": "src",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "resolveJsonModule": true,
13
- "sourceMap": true,
14
- "declaration": false,
15
- "noUncheckedIndexedAccess": true
16
- },
17
- "include": ["src"],
18
- "exclude": ["node_modules", "out"]
19
- }