@compilr-dev/cli 0.6.1 → 0.6.2

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 (44) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +12 -0
  3. package/dist/commands-v2/handlers/index.js +2 -2
  4. package/dist/compilr-diff-companion.vsix +0 -0
  5. package/dist/index.js +5 -2
  6. package/dist/utils/update-checker.d.ts +6 -1
  7. package/dist/utils/update-checker.js +16 -1
  8. package/package.json +5 -4
  9. package/dist/.tsbuildinfo.app +0 -1
  10. package/dist/.tsbuildinfo.data +0 -1
  11. package/dist/.tsbuildinfo.domain +0 -1
  12. package/dist/.tsbuildinfo.foundation +0 -1
  13. package/dist/guide/guide-content.d.ts +0 -23
  14. package/dist/guide/guide-content.js +0 -196
  15. package/dist/multi-agent/activity.d.ts +0 -21
  16. package/dist/multi-agent/activity.js +0 -34
  17. package/dist/multi-agent/agent-selection.d.ts +0 -55
  18. package/dist/multi-agent/agent-selection.js +0 -90
  19. package/dist/multi-agent/artifacts.d.ts +0 -197
  20. package/dist/multi-agent/artifacts.js +0 -379
  21. package/dist/multi-agent/collision-utils.d.ts +0 -16
  22. package/dist/multi-agent/collision-utils.js +0 -28
  23. package/dist/multi-agent/context-resolver.d.ts +0 -97
  24. package/dist/multi-agent/context-resolver.js +0 -316
  25. package/dist/multi-agent/mention-parser.d.ts +0 -64
  26. package/dist/multi-agent/mention-parser.js +0 -146
  27. package/dist/multi-agent/shared-context.d.ts +0 -293
  28. package/dist/multi-agent/shared-context.js +0 -671
  29. package/dist/multi-agent/skill-requirements.d.ts +0 -66
  30. package/dist/multi-agent/skill-requirements.js +0 -178
  31. package/dist/multi-agent/task-assignment.d.ts +0 -69
  32. package/dist/multi-agent/task-assignment.js +0 -123
  33. package/dist/multi-agent/task-suggestion.d.ts +0 -31
  34. package/dist/multi-agent/task-suggestion.js +0 -72
  35. package/dist/multi-agent/team-agent.d.ts +0 -201
  36. package/dist/multi-agent/team-agent.js +0 -488
  37. package/dist/multi-agent/team.d.ts +0 -286
  38. package/dist/multi-agent/team.js +0 -610
  39. package/dist/multi-agent/tool-config.d.ts +0 -110
  40. package/dist/multi-agent/tool-config.js +0 -661
  41. package/dist/multi-agent/types.d.ts +0 -211
  42. package/dist/multi-agent/types.js +0 -617
  43. package/dist/tools/guide-tool.d.ts +0 -12
  44. package/dist/tools/guide-tool.js +0 -59
@@ -1,316 +0,0 @@
1
- /**
2
- * ContextResolver - Resolve $agent mentions to actual content
3
- *
4
- * Resolution strategy:
5
- * 1. Check for explicit artifact reference in context hint
6
- * 2. Search artifacts by name/content matching context hint
7
- * 3. Fall back to recent conversation history
8
- *
9
- * Token budgets:
10
- * - Single mention: 2000 tokens max
11
- * - Multiple mentions: 3000 tokens total, split among mentions
12
- */
13
- // =============================================================================
14
- // Constants
15
- // =============================================================================
16
- const DEFAULT_MAX_TOKENS_PER_MENTION = 2000;
17
- const DEFAULT_MAX_TOTAL_TOKENS = 3000;
18
- const DEFAULT_MAX_HISTORY_MESSAGES = 10;
19
- // Token counting via tiktoken
20
- import { estimateTokens } from '../utils/token-tracker.js';
21
- // =============================================================================
22
- // ContextResolver
23
- // =============================================================================
24
- /**
25
- * Resolve mentions to actual content
26
- */
27
- export class ContextResolver {
28
- team;
29
- artifactStore;
30
- constructor(team, artifactStore) {
31
- this.team = team;
32
- this.artifactStore = artifactStore;
33
- }
34
- /**
35
- * Resolve multiple mentions
36
- */
37
- resolveAll(mentions, options = {}) {
38
- const maxTotal = options.maxTotalTokens ?? DEFAULT_MAX_TOTAL_TOKENS;
39
- const perMention = options.maxTokensPerMention ?? DEFAULT_MAX_TOKENS_PER_MENTION;
40
- // Calculate budget per mention
41
- const budgetPerMention = Math.min(perMention, Math.floor(maxTotal / mentions.length));
42
- const results = new Map();
43
- let totalTokens = 0;
44
- for (const mention of mentions) {
45
- // Skip if we're out of budget
46
- if (totalTokens >= maxTotal) {
47
- results.set(mention.agentId, {
48
- mention,
49
- resolved: false,
50
- source: 'not_found',
51
- sourceName: 'budget exceeded',
52
- content: '',
53
- tokenCount: 0,
54
- });
55
- continue;
56
- }
57
- const remainingBudget = Math.min(budgetPerMention, maxTotal - totalTokens);
58
- const resolved = this.resolveMention(mention, {
59
- ...options,
60
- maxTokensPerMention: remainingBudget,
61
- });
62
- results.set(mention.agentId, resolved);
63
- totalTokens += resolved.tokenCount;
64
- }
65
- return results;
66
- }
67
- /**
68
- * Resolve a single mention
69
- */
70
- resolveMention(mention, options = {}) {
71
- const maxTokens = options.maxTokensPerMention ?? DEFAULT_MAX_TOKENS_PER_MENTION;
72
- // 1. Try to find matching artifact
73
- const artifactResult = this.resolveFromArtifacts(mention, maxTokens, options);
74
- if (artifactResult) {
75
- return artifactResult;
76
- }
77
- // 2. Try to extract from conversation history
78
- const historyResult = this.resolveFromHistory(mention, maxTokens, options);
79
- if (historyResult) {
80
- return historyResult;
81
- }
82
- // 3. Not found
83
- return {
84
- mention,
85
- resolved: false,
86
- source: 'not_found',
87
- sourceName: 'no relevant content found',
88
- content: '',
89
- tokenCount: 0,
90
- };
91
- }
92
- /**
93
- * Resolve from artifacts
94
- */
95
- resolveFromArtifacts(mention, maxTokens, options) {
96
- const { agentId, context } = mention;
97
- // Get artifacts by this agent
98
- const agentArtifacts = this.artifactStore.listByAgent(agentId);
99
- if (agentArtifacts.length === 0) {
100
- return null;
101
- }
102
- // Sort artifacts by most recent first
103
- const sortedArtifacts = agentArtifacts
104
- .sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
105
- // Find matching artifact based on context hint
106
- let matchedArtifact;
107
- if (context) {
108
- // Search by name or content
109
- const searchResults = this.artifactStore.search(context);
110
- const searchMatch = searchResults.find(a => a.agent === agentId);
111
- // Use search match if found, otherwise fall back to most recent
112
- matchedArtifact = searchMatch ?? sortedArtifacts[0];
113
- }
114
- else {
115
- // No context hint - use most recent artifact
116
- matchedArtifact = sortedArtifacts[0];
117
- }
118
- // Format artifact content
119
- let content;
120
- let tokenCount;
121
- if (options.includeFullArtifact) {
122
- content = this.formatArtifactFull(matchedArtifact);
123
- tokenCount = estimateTokens(content);
124
- // If over budget, fall back to summary
125
- if (tokenCount > maxTokens) {
126
- content = this.formatArtifactSummary(matchedArtifact);
127
- tokenCount = estimateTokens(content);
128
- }
129
- }
130
- else {
131
- // Start with summary, include full if within budget
132
- const summary = this.formatArtifactSummary(matchedArtifact);
133
- const full = this.formatArtifactFull(matchedArtifact);
134
- if (estimateTokens(full) <= maxTokens) {
135
- content = full;
136
- }
137
- else {
138
- content = summary;
139
- }
140
- tokenCount = estimateTokens(content);
141
- }
142
- return {
143
- mention,
144
- resolved: true,
145
- source: 'artifact',
146
- sourceName: matchedArtifact.name,
147
- content,
148
- tokenCount,
149
- };
150
- }
151
- /**
152
- * Resolve from conversation history
153
- */
154
- resolveFromHistory(mention, maxTokens, options) {
155
- const { agentId, context } = mention;
156
- const maxMessages = options.maxHistoryMessages ?? DEFAULT_MAX_HISTORY_MESSAGES;
157
- // Get the team agent
158
- const teamAgent = this.team.get(agentId);
159
- if (!teamAgent) {
160
- return null;
161
- }
162
- // Get the underlying agent
163
- const agent = teamAgent.agent;
164
- if (!agent) {
165
- return null;
166
- }
167
- // Get recent messages from the agent's history
168
- const state = agent.serialize();
169
- const messages = state.messages;
170
- if (messages.length === 0) {
171
- return null;
172
- }
173
- // Get assistant messages (agent's responses)
174
- const assistantMessages = messages
175
- .filter((m) => m.role === 'assistant')
176
- .slice(-maxMessages);
177
- if (assistantMessages.length === 0) {
178
- return null;
179
- }
180
- // Extract relevant content
181
- let relevantContent;
182
- if (context) {
183
- // Search for context in messages
184
- relevantContent = this.extractRelevantContent(assistantMessages, context, maxTokens);
185
- }
186
- else {
187
- // Use most recent message
188
- const lastMessage = assistantMessages[assistantMessages.length - 1];
189
- relevantContent = this.formatMessage(lastMessage);
190
- }
191
- if (!relevantContent) {
192
- return null;
193
- }
194
- // Truncate if needed
195
- const tokenCount = estimateTokens(relevantContent);
196
- if (tokenCount > maxTokens) {
197
- relevantContent = this.truncateToTokens(relevantContent, maxTokens);
198
- }
199
- return {
200
- mention,
201
- resolved: true,
202
- source: 'history',
203
- sourceName: 'recent conversation',
204
- content: relevantContent,
205
- tokenCount: estimateTokens(relevantContent),
206
- };
207
- }
208
- /**
209
- * Extract relevant content from messages based on context hint
210
- */
211
- extractRelevantContent(messages, context, maxTokens) {
212
- const keywords = context.toLowerCase().split(/\s+/).filter(w => w.length > 2);
213
- // Score messages by relevance
214
- const scored = messages.map(msg => {
215
- const content = this.formatMessage(msg);
216
- const contentLower = content.toLowerCase();
217
- let score = 0;
218
- for (const keyword of keywords) {
219
- if (contentLower.includes(keyword)) {
220
- score += 1;
221
- }
222
- }
223
- return { content, score };
224
- });
225
- // Sort by score (highest first)
226
- scored.sort((a, b) => b.score - a.score);
227
- // Take best matches within token budget
228
- const results = [];
229
- let totalTokens = 0;
230
- for (const { content, score } of scored) {
231
- if (score === 0)
232
- continue;
233
- const tokens = estimateTokens(content);
234
- if (totalTokens + tokens > maxTokens) {
235
- // Try to include truncated version
236
- const remaining = maxTokens - totalTokens;
237
- if (remaining > 100) {
238
- results.push(this.truncateToTokens(content, remaining));
239
- }
240
- break;
241
- }
242
- results.push(content);
243
- totalTokens += tokens;
244
- }
245
- return results.join('\n\n---\n\n');
246
- }
247
- /**
248
- * Format a message for injection
249
- */
250
- formatMessage(message) {
251
- if (typeof message.content === 'string') {
252
- return message.content;
253
- }
254
- // Handle array content (Claude format)
255
- if (Array.isArray(message.content)) {
256
- const blocks = message.content;
257
- return blocks
258
- .filter((block) => block.type === 'text' && typeof block.text === 'string')
259
- .map(block => block.text)
260
- .join('\n');
261
- }
262
- return String(message.content);
263
- }
264
- /**
265
- * Format artifact with full content
266
- */
267
- formatArtifactFull(artifact) {
268
- return [
269
- `**${artifact.name}** (${artifact.type})`,
270
- `By: $${artifact.agent} | Updated: ${artifact.updatedAt.toLocaleDateString()}`,
271
- '',
272
- artifact.content,
273
- ].join('\n');
274
- }
275
- /**
276
- * Format artifact with summary only
277
- */
278
- formatArtifactSummary(artifact) {
279
- return [
280
- `**${artifact.name}** (${artifact.type})`,
281
- `By: $${artifact.agent} | Updated: ${artifact.updatedAt.toLocaleDateString()}`,
282
- '',
283
- `Summary: ${artifact.summary}`,
284
- '',
285
- `[Full content available via: /artifact view "${artifact.name}"]`,
286
- ].join('\n');
287
- }
288
- /**
289
- * Truncate content to approximate token count
290
- */
291
- truncateToTokens(content, maxTokens) {
292
- const maxChars = maxTokens * 4;
293
- if (content.length <= maxChars) {
294
- return content;
295
- }
296
- // Truncate at word boundary
297
- const truncated = content.slice(0, maxChars);
298
- const lastSpace = truncated.lastIndexOf(' ');
299
- if (lastSpace > maxChars * 0.8) {
300
- return truncated.slice(0, lastSpace) + '...';
301
- }
302
- return truncated + '...';
303
- }
304
- }
305
- /**
306
- * Build a context map from resolved mentions
307
- */
308
- export function buildContextMap(resolved) {
309
- const contextMap = new Map();
310
- for (const [agentId, resolution] of resolved) {
311
- if (resolution.resolved && resolution.content) {
312
- contextMap.set(agentId, resolution.content);
313
- }
314
- }
315
- return contextMap;
316
- }
@@ -1,64 +0,0 @@
1
- /**
2
- * MentionParser - Parse $agent references in user input
3
- *
4
- * Two types of $agent usage:
5
- * 1. Switch: "$arch message" at start of input → switch to arch, send message
6
- * 2. Reference: "what did $arch propose" mid-sentence → inject arch's context
7
- *
8
- * Detection rule: $name at START of trimmed input = switch. Otherwise = reference.
9
- */
10
- /**
11
- * A parsed mention in the input
12
- */
13
- export interface ParsedMention {
14
- /** Agent ID without $ prefix */
15
- agentId: string;
16
- /** Position in original input */
17
- startIndex: number;
18
- endIndex: number;
19
- /** The full match including $ prefix */
20
- raw: string;
21
- /** Optional query/context after the agent name */
22
- context?: string;
23
- }
24
- /**
25
- * Result of parsing user input for mentions
26
- */
27
- export interface ParsedInput {
28
- /** Original input text */
29
- original: string;
30
- /** Whether the input starts with a switch ($agent at beginning) */
31
- hasSwitch: boolean;
32
- /** The switch target agent (if hasSwitch is true) */
33
- switchTarget?: string;
34
- /** Message to send after switching (if hasSwitch is true) */
35
- messageAfterSwitch?: string;
36
- /** All reference mentions (mid-sentence $agent) */
37
- references: ParsedMention[];
38
- /** Input with mentions replaced by placeholders for context injection */
39
- normalizedInput: string;
40
- }
41
- /**
42
- * Parse user input for $agent mentions
43
- *
44
- * @param input - User input string
45
- * @param validAgents - Set of valid agent IDs (for validation)
46
- * @returns Parsed input with mentions identified
47
- */
48
- export declare function parseInputForMentions(input: string, validAgents?: Set<string>): ParsedInput;
49
- /**
50
- * Get unique agent IDs from references
51
- */
52
- export declare function getReferencedAgents(parsed: ParsedInput): string[];
53
- /**
54
- * Check if input contains any references (not just switch)
55
- */
56
- export declare function hasReferences(parsed: ParsedInput): boolean;
57
- /**
58
- * Build a message with context injected for mentions
59
- *
60
- * @param parsed - Parsed input
61
- * @param contextMap - Map of agentId → resolved context string
62
- * @returns Message with context prepended or injected
63
- */
64
- export declare function buildMessageWithContext(parsed: ParsedInput, contextMap: Map<string, string>): string;
@@ -1,146 +0,0 @@
1
- /**
2
- * MentionParser - Parse $agent references in user input
3
- *
4
- * Two types of $agent usage:
5
- * 1. Switch: "$arch message" at start of input → switch to arch, send message
6
- * 2. Reference: "what did $arch propose" mid-sentence → inject arch's context
7
- *
8
- * Detection rule: $name at START of trimmed input = switch. Otherwise = reference.
9
- */
10
- // =============================================================================
11
- // Constants
12
- // =============================================================================
13
- // Match $agentname pattern - alphanumeric and underscore/hyphen
14
- const MENTION_PATTERN = /\$([a-zA-Z][a-zA-Z0-9_-]*)/g;
15
- // Match $agent at start of input (for switch detection)
16
- const SWITCH_PATTERN = /^\$([a-zA-Z][a-zA-Z0-9_-]*)\s*/;
17
- // =============================================================================
18
- // Parser
19
- // =============================================================================
20
- /**
21
- * Parse user input for $agent mentions
22
- *
23
- * @param input - User input string
24
- * @param validAgents - Set of valid agent IDs (for validation)
25
- * @returns Parsed input with mentions identified
26
- */
27
- export function parseInputForMentions(input, validAgents) {
28
- const trimmed = input.trim();
29
- // Check for switch pattern at start
30
- const switchMatch = trimmed.match(SWITCH_PATTERN);
31
- let hasSwitch = false;
32
- let switchTarget;
33
- let messageAfterSwitch;
34
- let searchStart = 0;
35
- if (switchMatch) {
36
- const agentId = switchMatch[1].toLowerCase();
37
- // Only treat as switch if it's a valid agent
38
- if (!validAgents || validAgents.has(agentId)) {
39
- hasSwitch = true;
40
- switchTarget = agentId;
41
- messageAfterSwitch = trimmed.slice(switchMatch[0].length).trim();
42
- searchStart = switchMatch[0].length; // Skip switch when looking for references
43
- }
44
- }
45
- // Find all reference mentions (excluding the switch)
46
- const references = [];
47
- MENTION_PATTERN.lastIndex = searchStart;
48
- let match;
49
- while ((match = MENTION_PATTERN.exec(trimmed)) !== null) {
50
- const agentId = match[1].toLowerCase();
51
- // Skip if not a valid agent (if validation set provided)
52
- if (validAgents && !validAgents.has(agentId)) {
53
- continue;
54
- }
55
- // Skip if this is the switch mention
56
- if (hasSwitch && match.index === 0) {
57
- continue;
58
- }
59
- references.push({
60
- agentId,
61
- startIndex: match.index,
62
- endIndex: match.index + match[0].length,
63
- raw: match[0],
64
- });
65
- }
66
- // Extract context hints for each reference
67
- for (const ref of references) {
68
- ref.context = extractContextHint(trimmed, ref.endIndex);
69
- }
70
- // Build normalized input (with mention placeholders)
71
- const normalizedInput = hasSwitch ? messageAfterSwitch ?? '' : trimmed;
72
- // For normalized input, we keep mentions as-is but could replace with markers
73
- // This is useful for the resolver to know where to inject context
74
- return {
75
- original: input,
76
- hasSwitch,
77
- switchTarget,
78
- messageAfterSwitch,
79
- references,
80
- normalizedInput,
81
- };
82
- }
83
- /**
84
- * Extract a context hint following a mention
85
- *
86
- * Examples:
87
- * - "what did $arch propose for the API" → "propose for the API"
88
- * - "review $qa's feedback on the PR" → "'s feedback on the PR"
89
- * - "based on $arch" → undefined
90
- */
91
- function extractContextHint(text, afterIndex) {
92
- const remaining = text.slice(afterIndex);
93
- // Common patterns that provide context:
94
- // - "'s <noun>" (possessive)
95
- // - " <verb> <object>" (action)
96
- // - " about <topic>"
97
- // - " for <topic>"
98
- // - " on <topic>"
99
- // Get up to end of sentence or 50 chars
100
- const endMatch = remaining.match(/^[^.!?\n]{0,50}/);
101
- if (!endMatch || endMatch[0].trim().length < 3) {
102
- return undefined;
103
- }
104
- return endMatch[0].trim();
105
- }
106
- /**
107
- * Get unique agent IDs from references
108
- */
109
- export function getReferencedAgents(parsed) {
110
- const agents = new Set();
111
- for (const ref of parsed.references) {
112
- agents.add(ref.agentId);
113
- }
114
- return Array.from(agents);
115
- }
116
- /**
117
- * Check if input contains any references (not just switch)
118
- */
119
- export function hasReferences(parsed) {
120
- return parsed.references.length > 0;
121
- }
122
- /**
123
- * Build a message with context injected for mentions
124
- *
125
- * @param parsed - Parsed input
126
- * @param contextMap - Map of agentId → resolved context string
127
- * @returns Message with context prepended or injected
128
- */
129
- export function buildMessageWithContext(parsed, contextMap) {
130
- if (parsed.references.length === 0) {
131
- return parsed.normalizedInput;
132
- }
133
- // Collect context blocks
134
- const contextBlocks = [];
135
- for (const ref of parsed.references) {
136
- const context = contextMap.get(ref.agentId);
137
- if (context) {
138
- contextBlocks.push(`[Context from $${ref.agentId}:\n${context}\n]`);
139
- }
140
- }
141
- if (contextBlocks.length === 0) {
142
- return parsed.normalizedInput;
143
- }
144
- // Prepend context blocks to the message
145
- return `${contextBlocks.join('\n\n')}\n\n${parsed.normalizedInput}`;
146
- }