@ddse/acm-aicoder 0.5.0 → 0.5.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 (43) hide show
  1. package/dist/src/capability-map.d.ts +4 -0
  2. package/dist/src/capability-map.d.ts.map +1 -0
  3. package/dist/src/capability-map.js +289 -0
  4. package/dist/src/capability-map.js.map +1 -0
  5. package/dist/tsconfig.tsbuildinfo +1 -1
  6. package/package.json +21 -7
  7. package/.aicoder/index.json +0 -304
  8. package/AICODER_IMPLEMENTATION_PLAN_PHASE2.md +0 -284
  9. package/bin/interactive.tsx +0 -232
  10. package/docs/AICODER.png +0 -0
  11. package/docs/INTERACTIVE_CLI_GUIDE.md +0 -201
  12. package/docs/TUI_MOCKUP.md +0 -180
  13. package/src/config/providers.ts +0 -174
  14. package/src/config/session.ts +0 -143
  15. package/src/context/bm25.ts +0 -173
  16. package/src/context/code-search.ts +0 -188
  17. package/src/context/context-pack.ts +0 -133
  18. package/src/context/dependency-mapper.ts +0 -72
  19. package/src/context/index.ts +0 -8
  20. package/src/context/symbol-extractor.ts +0 -149
  21. package/src/context/test-mapper.ts +0 -77
  22. package/src/context/types.ts +0 -69
  23. package/src/context/workspace-indexer.ts +0 -249
  24. package/src/index.ts +0 -5
  25. package/src/registries.ts +0 -118
  26. package/src/runtime/budget-manager.ts +0 -118
  27. package/src/runtime/interactive-runtime.ts +0 -423
  28. package/src/tasks-v2/analysis-tasks.ts +0 -311
  29. package/src/tasks-v2/developer-tasks.ts +0 -437
  30. package/src/tasks-v2/index.ts +0 -3
  31. package/src/tools-v2/edit-tools.ts +0 -153
  32. package/src/tools-v2/index.ts +0 -6
  33. package/src/tools-v2/read-tools.ts +0 -286
  34. package/src/tools-v2/search-tools.ts +0 -175
  35. package/src/tools-v2/test-tools.ts +0 -147
  36. package/src/tools-v2/workspace-context.ts +0 -428
  37. package/src/ui/App.tsx +0 -392
  38. package/src/ui/components/ChatPane.tsx +0 -84
  39. package/src/ui/components/EventsPane.tsx +0 -81
  40. package/src/ui/components/GoalsTasksPane.tsx +0 -149
  41. package/src/ui/store.ts +0 -362
  42. package/tests/integration.test.ts +0 -537
  43. package/tsconfig.json +0 -22
@@ -1,428 +0,0 @@
1
- // Workspace Context Retrieval Tool
2
- import { Tool, type ContextRetrievalArtifact } from '@ddse/acm-sdk';
3
- import * as fs from 'fs/promises';
4
- import * as path from 'path';
5
- import { CodeSearch, WorkspaceIndexer, type WorkspaceIndex } from '../context/index.js';
6
- import { GrepTool } from './search-tools.js';
7
-
8
- export type WorkspaceContextOperation =
9
- | {
10
- type: 'search';
11
- query: string;
12
- k?: number;
13
- includeContext?: boolean;
14
- contextLines?: number;
15
- preferTypes?: string[];
16
- rationale?: string;
17
- }
18
- | {
19
- type: 'symbol';
20
- symbol: string;
21
- k?: number;
22
- rationale?: string;
23
- }
24
- | {
25
- type: 'grep';
26
- pattern: string;
27
- regex?: boolean;
28
- caseInsensitive?: boolean;
29
- maxResults?: number;
30
- rationale?: string;
31
- }
32
- | {
33
- type: 'file';
34
- path: string;
35
- startLine?: number;
36
- endLine?: number;
37
- maxBytes?: number;
38
- rationale?: string;
39
- }
40
- | {
41
- type: 'recent';
42
- limit?: number;
43
- languages?: string[];
44
- rationale?: string;
45
- }
46
- | {
47
- type: 'metadata';
48
- summary?: boolean;
49
- languages?: string[];
50
- rationale?: string;
51
- };
52
-
53
- export interface WorkspaceContextRequest {
54
- directive?: string;
55
- goal?: string;
56
- operations?: WorkspaceContextOperation[];
57
- }
58
-
59
- const DEFAULT_MAX_BYTES = 16_000;
60
-
61
- export class WorkspaceContextRetrievalTool extends Tool<
62
- WorkspaceContextRequest,
63
- ContextRetrievalArtifact[]
64
- > {
65
- private rootPath: string;
66
- private codeSearch?: CodeSearch;
67
- private indexer: WorkspaceIndexer;
68
- private index?: WorkspaceIndex;
69
- private grepTool: GrepTool;
70
- private indexingPromise?: Promise<void>;
71
-
72
- constructor(rootPath: string = process.cwd()) {
73
- super();
74
- this.rootPath = path.resolve(rootPath);
75
- this.indexer = new WorkspaceIndexer(this.rootPath);
76
- this.grepTool = new GrepTool(this.rootPath);
77
- }
78
-
79
- name(): string {
80
- return 'workspace_context';
81
- }
82
-
83
- async call(request: WorkspaceContextRequest): Promise<ContextRetrievalArtifact[]> {
84
- const operations = request.operations && request.operations.length > 0
85
- ? request.operations
86
- : this.deriveOperationsFromDirective(request.directive);
87
-
88
- if (!operations || operations.length === 0) {
89
- return [];
90
- }
91
-
92
- await this.ensureSearchIndex();
93
-
94
- const artifacts: ContextRetrievalArtifact[] = [];
95
- const seen = new Set<string>();
96
-
97
- for (const operation of operations) {
98
- try {
99
- if (operation.type === 'search') {
100
- const searchArtifacts = await this.handleSearch(operation);
101
- this.pushArtifacts(searchArtifacts, artifacts, seen);
102
- } else if (operation.type === 'symbol') {
103
- const symbolArtifacts = await this.handleSymbol(operation);
104
- this.pushArtifacts(symbolArtifacts, artifacts, seen);
105
- } else if (operation.type === 'grep') {
106
- const grepArtifacts = await this.handleGrep(operation);
107
- this.pushArtifacts(grepArtifacts, artifacts, seen);
108
- } else if (operation.type === 'file') {
109
- const fileArtifact = await this.handleFile(operation);
110
- this.pushArtifacts(fileArtifact, artifacts, seen);
111
- } else if (operation.type === 'recent') {
112
- const recentArtifact = await this.handleRecent(operation);
113
- this.pushArtifacts(recentArtifact, artifacts, seen);
114
- } else if (operation.type === 'metadata') {
115
- const metadataArtifact = await this.handleMetadata(operation);
116
- this.pushArtifacts(metadataArtifact, artifacts, seen);
117
- }
118
- } catch (error) {
119
- // Skip failing operation but surface metadata for debugging
120
- this.pushArtifacts(
121
- {
122
- type: 'workspace.debug',
123
- content: {
124
- operation,
125
- error: error instanceof Error ? error.message : String(error),
126
- },
127
- promote: false,
128
- provenance: {
129
- tool: this.name(),
130
- stage: 'operation-error',
131
- },
132
- },
133
- artifacts,
134
- seen
135
- );
136
- }
137
- }
138
-
139
- return artifacts;
140
- }
141
-
142
- private async ensureSearchIndex(): Promise<void> {
143
- if (this.index && this.codeSearch) {
144
- return;
145
- }
146
-
147
- if (!this.indexingPromise) {
148
- this.indexingPromise = (async () => {
149
- this.index = await this.indexer.buildIndex({ useCache: true });
150
- this.codeSearch = new CodeSearch(this.rootPath);
151
- await this.codeSearch.indexFiles(this.index);
152
- })();
153
- }
154
-
155
- await this.indexingPromise;
156
- }
157
-
158
- private deriveOperationsFromDirective(directive?: string): WorkspaceContextOperation[] {
159
- if (!directive) {
160
- return [];
161
- }
162
-
163
- const separatorIndex = directive.indexOf(':');
164
- const payload = separatorIndex >= 0 ? directive.slice(separatorIndex + 1).trim() : '';
165
-
166
- if (payload.startsWith('{')) {
167
- try {
168
- const parsed = JSON.parse(payload);
169
- if (Array.isArray(parsed.operations)) {
170
- return parsed.operations as WorkspaceContextOperation[];
171
- }
172
- if (typeof parsed.query === 'string' && parsed.query.length > 0) {
173
- return [
174
- {
175
- type: 'search',
176
- query: parsed.query,
177
- k: parsed.k,
178
- includeContext: parsed.includeContext ?? true,
179
- rationale: parsed.rationale,
180
- },
181
- ];
182
- }
183
- } catch {
184
- // fall back to text parsing
185
- }
186
- }
187
-
188
- if (payload.length > 0) {
189
- return [
190
- {
191
- type: 'search',
192
- query: payload,
193
- includeContext: true,
194
- },
195
- {
196
- type: 'grep',
197
- pattern: payload,
198
- maxResults: 20,
199
- },
200
- ];
201
- }
202
-
203
- return [];
204
- }
205
-
206
- private pushArtifacts(
207
- artifact: ContextRetrievalArtifact | ContextRetrievalArtifact[] | null | undefined,
208
- collection: ContextRetrievalArtifact[],
209
- seen: Set<string>
210
- ): void {
211
- if (!artifact) return;
212
- const artifacts = Array.isArray(artifact) ? artifact : [artifact];
213
-
214
- for (const entry of artifacts) {
215
- if (!entry || typeof entry.type !== 'string') continue;
216
-
217
- const provenance = entry.provenance ?? { tool: this.name() };
218
- const keySource = JSON.stringify([
219
- entry.type,
220
- provenance.tool,
221
- (entry.content && (entry.content.path || entry.content.id || entry.content.key)) ??
222
- JSON.stringify(entry.content),
223
- ]);
224
-
225
- if (seen.has(keySource)) {
226
- continue;
227
- }
228
-
229
- seen.add(keySource);
230
- collection.push({
231
- ...entry,
232
- provenance,
233
- });
234
- }
235
- }
236
-
237
- private async handleSearch(operation: Extract<WorkspaceContextOperation, { type: 'search' }>): Promise<ContextRetrievalArtifact[]> {
238
- if (!this.codeSearch) {
239
- return [];
240
- }
241
-
242
- const results = await this.codeSearch.search(operation.query, {
243
- k: Math.min(operation.k ?? 8, 20),
244
- includeContext: operation.includeContext ?? true,
245
- contextLines: operation.contextLines ?? 2,
246
- preferTypes: operation.preferTypes,
247
- });
248
-
249
- return results.map(result => ({
250
- type: 'workspace.snippet',
251
- promote: true,
252
- content: {
253
- path: result.path,
254
- line: result.line,
255
- snippet: result.snippet,
256
- score: result.score,
257
- operation: 'bm25-search',
258
- query: operation.query,
259
- rationale: operation.rationale,
260
- },
261
- provenance: {
262
- tool: this.name(),
263
- operation: 'search',
264
- },
265
- }));
266
- }
267
-
268
- private async handleSymbol(operation: Extract<WorkspaceContextOperation, { type: 'symbol' }>): Promise<ContextRetrievalArtifact[]> {
269
- if (!this.codeSearch) {
270
- return [];
271
- }
272
-
273
- const results = await this.codeSearch.searchSymbol(operation.symbol);
274
- return results.slice(0, Math.min(operation.k ?? 5, 10)).map(result => ({
275
- type: 'workspace.snippet',
276
- promote: true,
277
- content: {
278
- path: result.path,
279
- line: result.line,
280
- snippet: result.snippet,
281
- score: result.score,
282
- operation: 'symbol-search',
283
- symbol: operation.symbol,
284
- rationale: operation.rationale,
285
- },
286
- provenance: {
287
- tool: this.name(),
288
- operation: 'symbol',
289
- },
290
- }));
291
- }
292
-
293
- private async handleGrep(operation: Extract<WorkspaceContextOperation, { type: 'grep' }>): Promise<ContextRetrievalArtifact[]> {
294
- const result = await this.grepTool.call({
295
- pattern: operation.pattern,
296
- regex: operation.regex,
297
- caseInsensitive: operation.caseInsensitive,
298
- maxResults: Math.min(operation.maxResults ?? 30, 100),
299
- });
300
-
301
- return result.matches.map(match => ({
302
- type: 'workspace.match',
303
- promote: true,
304
- content: {
305
- path: match.path,
306
- line: match.line,
307
- column: match.column,
308
- preview: match.preview,
309
- operation: 'grep',
310
- pattern: operation.pattern,
311
- rationale: operation.rationale,
312
- },
313
- provenance: {
314
- tool: this.name(),
315
- operation: 'grep',
316
- },
317
- }));
318
- }
319
-
320
- private async handleFile(operation: Extract<WorkspaceContextOperation, { type: 'file' }>): Promise<ContextRetrievalArtifact | null> {
321
- const absolutePath = path.isAbsolute(operation.path)
322
- ? operation.path
323
- : path.join(this.rootPath, operation.path);
324
-
325
- const relativePath = path.relative(this.rootPath, absolutePath);
326
-
327
- try {
328
- let content = await fs.readFile(absolutePath, 'utf-8');
329
- const maxBytes = operation.maxBytes ?? DEFAULT_MAX_BYTES;
330
- if (content.length > maxBytes) {
331
- content = content.slice(0, maxBytes);
332
- }
333
-
334
- let snippet = content;
335
- let startLine = 1;
336
- let endLine = content.split('\n').length;
337
-
338
- if (operation.startLine || operation.endLine) {
339
- const lines = content.split('\n');
340
- startLine = Math.max(operation.startLine ?? 1, 1);
341
- endLine = Math.min(operation.endLine ?? lines.length, lines.length);
342
- snippet = lines.slice(startLine - 1, endLine).join('\n');
343
- }
344
-
345
- return {
346
- type: 'workspace.file',
347
- promote: true,
348
- content: {
349
- path: relativePath,
350
- snippet,
351
- startLine,
352
- endLine,
353
- rationale: operation.rationale,
354
- },
355
- provenance: {
356
- tool: this.name(),
357
- operation: 'file',
358
- },
359
- };
360
- } catch {
361
- return {
362
- type: 'workspace.debug',
363
- promote: false,
364
- content: {
365
- operation,
366
- error: `Failed to read file: ${relativePath}`,
367
- },
368
- provenance: {
369
- tool: this.name(),
370
- operation: 'file',
371
- },
372
- };
373
- }
374
- }
375
-
376
- private async handleRecent(operation: Extract<WorkspaceContextOperation, { type: 'recent' }>): Promise<ContextRetrievalArtifact | null> {
377
- if (!this.index) {
378
- return null;
379
- }
380
-
381
- const limit = Math.min(operation.limit ?? 5, 20);
382
- const files = WorkspaceIndexer.getRecentFiles(this.index, limit);
383
- const filtered = operation.languages && operation.languages.length > 0
384
- ? files.filter(file => operation.languages!.includes(file.language))
385
- : files;
386
-
387
- return {
388
- type: 'workspace.metadata',
389
- promote: true,
390
- content: {
391
- kind: 'recent-files',
392
- files: filtered.map(file => ({
393
- path: file.path,
394
- mtime: file.mtime,
395
- language: file.language,
396
- size: file.size,
397
- })),
398
- rationale: operation.rationale,
399
- },
400
- provenance: {
401
- tool: this.name(),
402
- operation: 'recent',
403
- },
404
- };
405
- }
406
-
407
- private async handleMetadata(operation: Extract<WorkspaceContextOperation, { type: 'metadata' }>): Promise<ContextRetrievalArtifact | null> {
408
- if (!this.index) {
409
- return null;
410
- }
411
-
412
- return {
413
- type: 'workspace.metadata',
414
- promote: true,
415
- content: {
416
- kind: 'summary',
417
- files: this.index.totalFiles,
418
- totalSize: this.index.totalSize,
419
- languages: Array.from(new Set(this.index.files.map(f => f.language))).slice(0, 32),
420
- rationale: operation.rationale,
421
- },
422
- provenance: {
423
- tool: this.name(),
424
- operation: 'metadata',
425
- },
426
- };
427
- }
428
- }