@compilr-dev/sdk 0.1.28 → 0.2.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/dist/agent.js +16 -4
- package/dist/config.d.ts +12 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +27 -1
- package/dist/team/activity.d.ts +21 -0
- package/dist/team/activity.js +34 -0
- package/dist/team/agent-selection.d.ts +53 -0
- package/dist/team/agent-selection.js +88 -0
- package/dist/team/artifacts.d.ts +175 -0
- package/dist/team/artifacts.js +279 -0
- package/dist/team/collision-utils.d.ts +16 -0
- package/dist/team/collision-utils.js +28 -0
- package/dist/team/context-resolver.d.ts +97 -0
- package/dist/team/context-resolver.js +322 -0
- package/dist/team/custom-agents.d.ts +68 -0
- package/dist/team/custom-agents.js +150 -0
- package/dist/team/delegation-tracker.d.ts +147 -0
- package/dist/team/delegation-tracker.js +215 -0
- package/dist/team/index.d.ts +34 -0
- package/dist/team/index.js +30 -0
- package/dist/team/interfaces.d.ts +36 -0
- package/dist/team/interfaces.js +7 -0
- package/dist/team/mention-parser.d.ts +64 -0
- package/dist/team/mention-parser.js +138 -0
- package/dist/team/shared-context.d.ts +293 -0
- package/dist/team/shared-context.js +673 -0
- package/dist/team/skill-requirements.d.ts +66 -0
- package/dist/team/skill-requirements.js +178 -0
- package/dist/team/task-assignment.d.ts +69 -0
- package/dist/team/task-assignment.js +123 -0
- package/dist/team/task-suggestion.d.ts +31 -0
- package/dist/team/task-suggestion.js +84 -0
- package/dist/team/team-agent.d.ts +201 -0
- package/dist/team/team-agent.js +492 -0
- package/dist/team/team.d.ts +297 -0
- package/dist/team/team.js +615 -0
- package/dist/team/tool-config.d.ts +110 -0
- package/dist/team/tool-config.js +739 -0
- package/dist/team/types.d.ts +211 -0
- package/dist/team/types.js +638 -0
- package/package.json +1 -1
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ArtifactStore - Storage for team artifacts
|
|
3
|
+
*
|
|
4
|
+
* Artifacts are named pieces of work that agents can publish and reference:
|
|
5
|
+
* - design: Architecture, API specs, data models
|
|
6
|
+
* - plan: Sprint plans, task breakdowns, timelines
|
|
7
|
+
* - review: Code reviews, security audits, feedback
|
|
8
|
+
* - decision: Architectural decisions, trade-off analysis
|
|
9
|
+
* - note: General notes, meeting summaries
|
|
10
|
+
*/
|
|
11
|
+
// =============================================================================
|
|
12
|
+
// Constants
|
|
13
|
+
// =============================================================================
|
|
14
|
+
const MAX_SUMMARY_LENGTH = 200;
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Utilities
|
|
17
|
+
// =============================================================================
|
|
18
|
+
function truncate(str, maxLen) {
|
|
19
|
+
if (str.length <= maxLen)
|
|
20
|
+
return str;
|
|
21
|
+
return str.slice(0, maxLen - 3) + '...';
|
|
22
|
+
}
|
|
23
|
+
// =============================================================================
|
|
24
|
+
// ArtifactStore
|
|
25
|
+
// =============================================================================
|
|
26
|
+
/**
|
|
27
|
+
* Manages artifact storage and retrieval
|
|
28
|
+
*/
|
|
29
|
+
export class ArtifactStore {
|
|
30
|
+
artifacts = new Map();
|
|
31
|
+
nameToId = new Map(); // name -> id lookup
|
|
32
|
+
updatedAt = new Date();
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// CRUD Operations
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
/**
|
|
37
|
+
* Create a new artifact
|
|
38
|
+
*/
|
|
39
|
+
create(options) {
|
|
40
|
+
const id = `art-${String(Date.now())}-${Math.random().toString(36).slice(2, 8)}`;
|
|
41
|
+
// Generate summary if not provided
|
|
42
|
+
const summary = options.summary ?? this.generateSummary(options.content);
|
|
43
|
+
const artifact = {
|
|
44
|
+
id,
|
|
45
|
+
name: options.name,
|
|
46
|
+
agent: options.agent,
|
|
47
|
+
type: options.type,
|
|
48
|
+
content: options.content,
|
|
49
|
+
summary,
|
|
50
|
+
version: 1,
|
|
51
|
+
createdAt: new Date(),
|
|
52
|
+
updatedAt: new Date(),
|
|
53
|
+
mentions: [],
|
|
54
|
+
referencedBy: [],
|
|
55
|
+
};
|
|
56
|
+
this.artifacts.set(id, artifact);
|
|
57
|
+
this.nameToId.set(options.name.toLowerCase(), id);
|
|
58
|
+
this.updatedAt = new Date();
|
|
59
|
+
return artifact;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Get an artifact by ID
|
|
63
|
+
*/
|
|
64
|
+
get(id) {
|
|
65
|
+
return this.artifacts.get(id);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get an artifact by name (case-insensitive)
|
|
69
|
+
*/
|
|
70
|
+
getByName(name) {
|
|
71
|
+
const id = this.nameToId.get(name.toLowerCase());
|
|
72
|
+
if (id) {
|
|
73
|
+
return this.artifacts.get(id);
|
|
74
|
+
}
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Update an artifact
|
|
79
|
+
*/
|
|
80
|
+
update(id, options) {
|
|
81
|
+
const artifact = this.artifacts.get(id);
|
|
82
|
+
if (!artifact) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
if (options.content !== undefined) {
|
|
86
|
+
artifact.content = options.content;
|
|
87
|
+
// Regenerate summary if content changed and no new summary provided
|
|
88
|
+
if (options.summary === undefined) {
|
|
89
|
+
artifact.summary = this.generateSummary(options.content);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (options.summary !== undefined) {
|
|
93
|
+
artifact.summary = options.summary;
|
|
94
|
+
}
|
|
95
|
+
if (options.type !== undefined) {
|
|
96
|
+
artifact.type = options.type;
|
|
97
|
+
}
|
|
98
|
+
artifact.version++;
|
|
99
|
+
artifact.updatedAt = new Date();
|
|
100
|
+
this.updatedAt = new Date();
|
|
101
|
+
return artifact;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Delete an artifact
|
|
105
|
+
*/
|
|
106
|
+
delete(id) {
|
|
107
|
+
const artifact = this.artifacts.get(id);
|
|
108
|
+
if (!artifact) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
this.nameToId.delete(artifact.name.toLowerCase());
|
|
112
|
+
this.artifacts.delete(id);
|
|
113
|
+
this.updatedAt = new Date();
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Rename an artifact
|
|
118
|
+
*/
|
|
119
|
+
rename(id, newName) {
|
|
120
|
+
const artifact = this.artifacts.get(id);
|
|
121
|
+
if (!artifact) {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
// Update name lookup
|
|
125
|
+
this.nameToId.delete(artifact.name.toLowerCase());
|
|
126
|
+
artifact.name = newName;
|
|
127
|
+
this.nameToId.set(newName.toLowerCase(), id);
|
|
128
|
+
artifact.updatedAt = new Date();
|
|
129
|
+
this.updatedAt = new Date();
|
|
130
|
+
return artifact;
|
|
131
|
+
}
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
// Query Operations
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
/**
|
|
136
|
+
* List all artifacts
|
|
137
|
+
*/
|
|
138
|
+
list() {
|
|
139
|
+
return Array.from(this.artifacts.values());
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* List artifacts by agent
|
|
143
|
+
*/
|
|
144
|
+
listByAgent(agent) {
|
|
145
|
+
return this.list().filter((a) => a.agent === agent);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* List artifacts by type
|
|
149
|
+
*/
|
|
150
|
+
listByType(type) {
|
|
151
|
+
return this.list().filter((a) => a.type === type);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Search artifacts by name or content
|
|
155
|
+
*/
|
|
156
|
+
search(query) {
|
|
157
|
+
const lowerQuery = query.toLowerCase();
|
|
158
|
+
return this.list().filter((a) => a.name.toLowerCase().includes(lowerQuery) ||
|
|
159
|
+
a.content.toLowerCase().includes(lowerQuery) ||
|
|
160
|
+
a.summary.toLowerCase().includes(lowerQuery));
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Get artifact count
|
|
164
|
+
*/
|
|
165
|
+
get size() {
|
|
166
|
+
return this.artifacts.size;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Check if an artifact exists by name
|
|
170
|
+
*/
|
|
171
|
+
has(name) {
|
|
172
|
+
return this.nameToId.has(name.toLowerCase());
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Check if an artifact exists by ID
|
|
176
|
+
*/
|
|
177
|
+
hasId(id) {
|
|
178
|
+
return this.artifacts.has(id);
|
|
179
|
+
}
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
// Summary Generation
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
/**
|
|
184
|
+
* Generate a summary from content
|
|
185
|
+
* Simple extraction of first meaningful lines
|
|
186
|
+
*/
|
|
187
|
+
generateSummary(content) {
|
|
188
|
+
// Remove markdown headers and get first meaningful content
|
|
189
|
+
const lines = content
|
|
190
|
+
.split('\n')
|
|
191
|
+
.map((line) => line.trim())
|
|
192
|
+
.filter((line) => line.length > 0 && !line.startsWith('#'));
|
|
193
|
+
const summary = lines.slice(0, 3).join(' ');
|
|
194
|
+
if (summary.length > MAX_SUMMARY_LENGTH) {
|
|
195
|
+
return truncate(summary, MAX_SUMMARY_LENGTH);
|
|
196
|
+
}
|
|
197
|
+
return summary || 'No summary available';
|
|
198
|
+
}
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
// Index for Shared Context
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
/**
|
|
203
|
+
* Get summaries for shared context injection
|
|
204
|
+
*/
|
|
205
|
+
getSummaries() {
|
|
206
|
+
return this.list()
|
|
207
|
+
.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime())
|
|
208
|
+
.map((a) => ({
|
|
209
|
+
id: a.id,
|
|
210
|
+
name: a.name,
|
|
211
|
+
agent: a.agent,
|
|
212
|
+
type: a.type,
|
|
213
|
+
summary: a.summary,
|
|
214
|
+
updatedAt: a.updatedAt,
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
// ---------------------------------------------------------------------------
|
|
218
|
+
// Serialization
|
|
219
|
+
// ---------------------------------------------------------------------------
|
|
220
|
+
/**
|
|
221
|
+
* Serialize all artifacts for external persistence
|
|
222
|
+
*/
|
|
223
|
+
serialize() {
|
|
224
|
+
return this.list().map((a) => ({
|
|
225
|
+
id: a.id,
|
|
226
|
+
name: a.name,
|
|
227
|
+
agent: a.agent,
|
|
228
|
+
type: a.type,
|
|
229
|
+
content: a.content,
|
|
230
|
+
summary: a.summary,
|
|
231
|
+
version: a.version,
|
|
232
|
+
createdAt: a.createdAt.toISOString(),
|
|
233
|
+
updatedAt: a.updatedAt.toISOString(),
|
|
234
|
+
mentions: a.mentions,
|
|
235
|
+
referencedBy: a.referencedBy,
|
|
236
|
+
}));
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Restore artifacts from serialized data
|
|
240
|
+
*/
|
|
241
|
+
restore(data) {
|
|
242
|
+
this.artifacts.clear();
|
|
243
|
+
this.nameToId.clear();
|
|
244
|
+
for (const serialized of data) {
|
|
245
|
+
const artifact = {
|
|
246
|
+
id: serialized.id,
|
|
247
|
+
name: serialized.name,
|
|
248
|
+
agent: serialized.agent,
|
|
249
|
+
type: serialized.type,
|
|
250
|
+
content: serialized.content,
|
|
251
|
+
summary: serialized.summary,
|
|
252
|
+
version: serialized.version,
|
|
253
|
+
createdAt: new Date(serialized.createdAt),
|
|
254
|
+
updatedAt: new Date(serialized.updatedAt),
|
|
255
|
+
mentions: serialized.mentions ?? [],
|
|
256
|
+
referencedBy: serialized.referencedBy ?? [],
|
|
257
|
+
};
|
|
258
|
+
this.artifacts.set(artifact.id, artifact);
|
|
259
|
+
this.nameToId.set(artifact.name.toLowerCase(), artifact.id);
|
|
260
|
+
}
|
|
261
|
+
if (data.length > 0) {
|
|
262
|
+
this.updatedAt = new Date(Math.max(...data.map((d) => new Date(d.updatedAt).getTime())));
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Clear all artifacts
|
|
267
|
+
*/
|
|
268
|
+
clear() {
|
|
269
|
+
this.artifacts.clear();
|
|
270
|
+
this.nameToId.clear();
|
|
271
|
+
this.updatedAt = new Date();
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Get the last update timestamp
|
|
275
|
+
*/
|
|
276
|
+
getLastUpdated() {
|
|
277
|
+
return this.updatedAt;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent ID Collision Prevention
|
|
3
|
+
*
|
|
4
|
+
* When multiple terminals work on the same project, they may try to add
|
|
5
|
+
* agents with the same ID (e.g., both run `/add pm`). This module detects
|
|
6
|
+
* and resolves such collisions by querying the session registry for agent
|
|
7
|
+
* IDs already in use by other terminals.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Check if an agent ID is in use by another terminal and resolve collisions.
|
|
11
|
+
* Returns the original ID if available, or a suffixed variant (e.g., "pm_2").
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveAgentIdCollision(requestedId: string, localTeamIds: string[], globalAgentIds: string[]): {
|
|
14
|
+
id: string;
|
|
15
|
+
wasCollision: boolean;
|
|
16
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent ID Collision Prevention
|
|
3
|
+
*
|
|
4
|
+
* When multiple terminals work on the same project, they may try to add
|
|
5
|
+
* agents with the same ID (e.g., both run `/add pm`). This module detects
|
|
6
|
+
* and resolves such collisions by querying the session registry for agent
|
|
7
|
+
* IDs already in use by other terminals.
|
|
8
|
+
*/
|
|
9
|
+
import { randomUUID } from 'crypto';
|
|
10
|
+
/**
|
|
11
|
+
* Check if an agent ID is in use by another terminal and resolve collisions.
|
|
12
|
+
* Returns the original ID if available, or a suffixed variant (e.g., "pm_2").
|
|
13
|
+
*/
|
|
14
|
+
export function resolveAgentIdCollision(requestedId, localTeamIds, globalAgentIds) {
|
|
15
|
+
if (!globalAgentIds.includes(requestedId)) {
|
|
16
|
+
return { id: requestedId, wasCollision: false };
|
|
17
|
+
}
|
|
18
|
+
// Try suffixes: pm_2, pm_3, etc.
|
|
19
|
+
for (let i = 2; i <= 10; i++) {
|
|
20
|
+
const candidate = `${requestedId}_${String(i)}`;
|
|
21
|
+
if (!localTeamIds.includes(candidate) && !globalAgentIds.includes(candidate)) {
|
|
22
|
+
return { id: candidate, wasCollision: true };
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Fallback: UUID suffix
|
|
26
|
+
const fallback = `${requestedId}_${randomUUID().slice(0, 4)}`;
|
|
27
|
+
return { id: fallback, wasCollision: true };
|
|
28
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
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
|
+
import type { AgentTeam } from './team.js';
|
|
14
|
+
import type { ArtifactStore } from './artifacts.js';
|
|
15
|
+
import type { ParsedMention } from './mention-parser.js';
|
|
16
|
+
/**
|
|
17
|
+
* Resolution source type
|
|
18
|
+
*/
|
|
19
|
+
export type ResolutionSource = 'artifact' | 'history' | 'decision' | 'not_found';
|
|
20
|
+
/**
|
|
21
|
+
* Resolved mention with content
|
|
22
|
+
*/
|
|
23
|
+
export interface ResolvedMention {
|
|
24
|
+
/** Original mention */
|
|
25
|
+
mention: ParsedMention;
|
|
26
|
+
/** Resolution status */
|
|
27
|
+
resolved: boolean;
|
|
28
|
+
/** Source of resolution */
|
|
29
|
+
source: ResolutionSource;
|
|
30
|
+
/** Source name (artifact name, "recent history", etc.) */
|
|
31
|
+
sourceName: string;
|
|
32
|
+
/** Resolved content to inject */
|
|
33
|
+
content: string;
|
|
34
|
+
/** Approximate token count */
|
|
35
|
+
tokenCount: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Options for resolution
|
|
39
|
+
*/
|
|
40
|
+
export interface ResolveOptions {
|
|
41
|
+
/** Max tokens per mention (default: 2000) */
|
|
42
|
+
maxTokensPerMention?: number;
|
|
43
|
+
/** Max total tokens for all mentions (default: 3000) */
|
|
44
|
+
maxTotalTokens?: number;
|
|
45
|
+
/** Include artifact content (not just summary) */
|
|
46
|
+
includeFullArtifact?: boolean;
|
|
47
|
+
/** Max history messages to search */
|
|
48
|
+
maxHistoryMessages?: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resolve mentions to actual content
|
|
52
|
+
*/
|
|
53
|
+
export declare class ContextResolver {
|
|
54
|
+
private readonly team;
|
|
55
|
+
private readonly artifactStore;
|
|
56
|
+
constructor(team: AgentTeam, artifactStore: ArtifactStore);
|
|
57
|
+
/**
|
|
58
|
+
* Resolve multiple mentions
|
|
59
|
+
*/
|
|
60
|
+
resolveAll(mentions: ParsedMention[], options?: ResolveOptions): Map<string, ResolvedMention>;
|
|
61
|
+
/**
|
|
62
|
+
* Resolve a single mention
|
|
63
|
+
*/
|
|
64
|
+
resolveMention(mention: ParsedMention, options?: ResolveOptions): ResolvedMention;
|
|
65
|
+
/**
|
|
66
|
+
* Resolve from artifacts
|
|
67
|
+
*/
|
|
68
|
+
private resolveFromArtifacts;
|
|
69
|
+
/**
|
|
70
|
+
* Resolve from conversation history
|
|
71
|
+
*/
|
|
72
|
+
private resolveFromHistory;
|
|
73
|
+
/**
|
|
74
|
+
* Extract relevant content from messages based on context hint
|
|
75
|
+
*/
|
|
76
|
+
private extractRelevantContent;
|
|
77
|
+
/**
|
|
78
|
+
* Format a message for injection
|
|
79
|
+
*/
|
|
80
|
+
private formatMessage;
|
|
81
|
+
/**
|
|
82
|
+
* Format artifact with full content
|
|
83
|
+
*/
|
|
84
|
+
private formatArtifactFull;
|
|
85
|
+
/**
|
|
86
|
+
* Format artifact with summary only
|
|
87
|
+
*/
|
|
88
|
+
private formatArtifactSummary;
|
|
89
|
+
/**
|
|
90
|
+
* Truncate content to approximate token count
|
|
91
|
+
*/
|
|
92
|
+
private truncateToTokens;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Build a context map from resolved mentions
|
|
96
|
+
*/
|
|
97
|
+
export declare function buildContextMap(resolved: Map<string, ResolvedMention>): Map<string, string>;
|