@compilr-dev/sdk 0.1.20 → 0.1.22

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.
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Capability Catalog Generator
3
+ *
4
+ * Generates the system prompt section that lists available (loadable)
5
+ * capability packs for agent self-loading.
6
+ */
7
+ import type { CapabilityCatalogEntry } from './types.js';
8
+ /**
9
+ * Generate a system prompt section listing loadable capability packs.
10
+ *
11
+ * @param catalog - Entries from CapabilityManager.getCatalog()
12
+ * @param loadedPackIds - Currently loaded pack IDs (for "Currently loaded" line)
13
+ * @returns System prompt section string, or empty string if catalog is empty
14
+ */
15
+ export declare function generateCapabilityCatalog(catalog: CapabilityCatalogEntry[], loadedPackIds: string[]): string;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Capability Catalog Generator
3
+ *
4
+ * Generates the system prompt section that lists available (loadable)
5
+ * capability packs for agent self-loading.
6
+ */
7
+ /**
8
+ * Generate a system prompt section listing loadable capability packs.
9
+ *
10
+ * @param catalog - Entries from CapabilityManager.getCatalog()
11
+ * @param loadedPackIds - Currently loaded pack IDs (for "Currently loaded" line)
12
+ * @returns System prompt section string, or empty string if catalog is empty
13
+ */
14
+ export function generateCapabilityCatalog(catalog, loadedPackIds) {
15
+ if (catalog.length === 0) {
16
+ return '';
17
+ }
18
+ const lines = [
19
+ '## Available Capabilities',
20
+ '',
21
+ 'Call `load_capability("name")` to activate additional tools:',
22
+ ];
23
+ for (const entry of catalog) {
24
+ const readOnlySuffix = entry.readOnly ? ', read-only' : '';
25
+ lines.push(`- ${entry.id}: ${entry.label} (${String(entry.toolCount)} tools${readOnlySuffix})`);
26
+ }
27
+ if (loadedPackIds.length > 0) {
28
+ lines.push('');
29
+ lines.push(`Currently loaded: ${loadedPackIds.join(', ')}`);
30
+ }
31
+ return lines.join('\n');
32
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Dynamic Capability Loading
3
+ *
4
+ * Provides three-tier capability management for agents:
5
+ * - Upfront: always active (HOT tools ∩ profile)
6
+ * - Loadable: on-demand activation (sticky)
7
+ * - Forbidden: outside profile (triggers handoff)
8
+ */
9
+ export type { CapabilityPack, CapabilityTier, LoadedCapability, CapabilityCatalogEntry, CapabilityLoadResult, } from './types.js';
10
+ export { CAPABILITY_PACKS, FORBIDDEN_PACK_SUGGESTIONS, getPackCount, getAllPackIds, } from './packs.js';
11
+ export { CapabilityManager } from './manager.js';
12
+ export type { CapabilityManagerConfig } from './manager.js';
13
+ export { createLoadCapabilityTool } from './load-tool.js';
14
+ export { generateCapabilityCatalog } from './catalog.js';
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Dynamic Capability Loading
3
+ *
4
+ * Provides three-tier capability management for agents:
5
+ * - Upfront: always active (HOT tools ∩ profile)
6
+ * - Loadable: on-demand activation (sticky)
7
+ * - Forbidden: outside profile (triggers handoff)
8
+ */
9
+ // Pack definitions
10
+ export { CAPABILITY_PACKS, FORBIDDEN_PACK_SUGGESTIONS, getPackCount, getAllPackIds, } from './packs.js';
11
+ // Manager
12
+ export { CapabilityManager } from './manager.js';
13
+ // Self-loading tool
14
+ export { createLoadCapabilityTool } from './load-tool.js';
15
+ // Catalog generator
16
+ export { generateCapabilityCatalog } from './catalog.js';
@@ -0,0 +1,21 @@
1
+ /**
2
+ * load_capability Tool
3
+ *
4
+ * Allows agents to self-load capability packs at runtime.
5
+ * When called, sets a pending load flag that the BeforeLLM hook
6
+ * picks up on the next turn.
7
+ */
8
+ import type { Tool } from '@compilr-dev/agents';
9
+ import type { CapabilityManager } from './manager.js';
10
+ interface LoadCapabilityInput {
11
+ capability: string;
12
+ }
13
+ /**
14
+ * Create a load_capability tool bound to a CapabilityManager.
15
+ *
16
+ * The tool immediately loads the pack into the manager.
17
+ * The BeforeLLM hook will see the updated state on the next turn
18
+ * and rebuild the system prompt + tool filter accordingly.
19
+ */
20
+ export declare function createLoadCapabilityTool(manager: CapabilityManager): Tool<LoadCapabilityInput>;
21
+ export {};
@@ -0,0 +1,62 @@
1
+ /**
2
+ * load_capability Tool
3
+ *
4
+ * Allows agents to self-load capability packs at runtime.
5
+ * When called, sets a pending load flag that the BeforeLLM hook
6
+ * picks up on the next turn.
7
+ */
8
+ import { defineTool, createSuccessResult, createErrorResult } from '@compilr-dev/agents';
9
+ /**
10
+ * Create a load_capability tool bound to a CapabilityManager.
11
+ *
12
+ * The tool immediately loads the pack into the manager.
13
+ * The BeforeLLM hook will see the updated state on the next turn
14
+ * and rebuild the system prompt + tool filter accordingly.
15
+ */
16
+ export function createLoadCapabilityTool(manager) {
17
+ return defineTool({
18
+ name: 'load_capability',
19
+ description: 'Load a capability pack to gain access to additional tools. ' +
20
+ 'See the "Available Capabilities" section in your instructions for pack IDs.',
21
+ inputSchema: {
22
+ type: 'object',
23
+ properties: {
24
+ capability: {
25
+ type: 'string',
26
+ description: 'Pack ID from the capability catalog (e.g., "git_read", "runners", "backlog_write")',
27
+ },
28
+ },
29
+ required: ['capability'],
30
+ },
31
+ silent: true,
32
+ execute: (input) => {
33
+ const { capability } = input;
34
+ // Check if already loaded
35
+ if (manager.isLoaded(capability)) {
36
+ return Promise.resolve(createSuccessResult({
37
+ status: 'already_loaded',
38
+ message: `Capability "${capability}" is already loaded.`,
39
+ }));
40
+ }
41
+ // Attempt to load
42
+ const tier = manager.getTier(capability);
43
+ if (tier === 'forbidden') {
44
+ const suggested = manager.getSuggestedAgent(capability);
45
+ const handoffHint = suggested
46
+ ? ` Try: handoff("${suggested}", "Need ${capability} access")`
47
+ : '';
48
+ return Promise.resolve(createErrorResult(`Capability "${capability}" is outside your tool profile.${handoffHint}`));
49
+ }
50
+ const success = manager.load(capability, 'agent-self');
51
+ if (success) {
52
+ return Promise.resolve(createSuccessResult({
53
+ status: 'loaded',
54
+ message: `Capability "${capability}" loaded. ` +
55
+ 'The tools will be available on your next response.',
56
+ }));
57
+ }
58
+ return Promise.resolve(createErrorResult(`Unknown capability pack: "${capability}". ` +
59
+ 'Check the "Available Capabilities" section in your instructions.'));
60
+ },
61
+ });
62
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Dynamic Capability Loading — CapabilityManager
3
+ *
4
+ * Manages the three-tier loading model for an agent:
5
+ * - Upfront: always active from the start
6
+ * - Loadable: within profile, activated on demand (sticky)
7
+ * - Forbidden: outside profile, triggers handoff suggestion
8
+ */
9
+ import type { CapabilityPack, CapabilityTier, LoadedCapability, CapabilityCatalogEntry, CapabilityLoadResult } from './types.js';
10
+ export interface CapabilityManagerConfig {
11
+ /** All group IDs the agent's profile allows */
12
+ profileGroups: string[];
13
+ /** All pack definitions */
14
+ packs: Record<string, CapabilityPack>;
15
+ /** Group IDs to load upfront (HOT_TOOLS ∩ profile) */
16
+ upfrontGroups: string[];
17
+ }
18
+ export declare class CapabilityManager {
19
+ private readonly profileGroupSet;
20
+ private readonly packs;
21
+ private readonly loaded;
22
+ /** Reverse index: tool name → pack ID */
23
+ private readonly toolToPackIndex;
24
+ constructor(config: CapabilityManagerConfig);
25
+ /**
26
+ * Get the tier of a capability pack relative to this agent.
27
+ */
28
+ getTier(packId: string): CapabilityTier;
29
+ /**
30
+ * Load a capability pack. Returns false if forbidden.
31
+ * Once loaded, packs stay loaded (sticky mode).
32
+ */
33
+ load(packId: string, trigger: LoadedCapability['trigger']): boolean;
34
+ /**
35
+ * Load multiple packs for a skill invocation.
36
+ * Maps tool names to pack IDs, then loads each.
37
+ */
38
+ loadForSkill(toolNames: string[], trigger: LoadedCapability['trigger']): CapabilityLoadResult;
39
+ /**
40
+ * Get all currently loaded tool names (deduplicated).
41
+ */
42
+ getActiveToolNames(): string[];
43
+ /**
44
+ * Get prompt module IDs to include (deduplicated across loaded packs).
45
+ */
46
+ getActivePromptModuleIds(): Set<string>;
47
+ /**
48
+ * Get prompt snippets from loaded packs.
49
+ */
50
+ getActivePromptSnippets(): string[];
51
+ /**
52
+ * Get catalog of loadable (not yet loaded) packs for the system prompt.
53
+ */
54
+ getCatalog(): CapabilityCatalogEntry[];
55
+ /**
56
+ * Check if any loadable packs remain (not yet loaded).
57
+ */
58
+ hasLoadablePacks(): boolean;
59
+ /**
60
+ * Find which pack contains a given tool name.
61
+ */
62
+ findPackForTool(toolName: string): string | undefined;
63
+ /**
64
+ * Get suggested agent for a forbidden pack.
65
+ */
66
+ getSuggestedAgent(packId: string): string | undefined;
67
+ /**
68
+ * Get all loaded pack IDs.
69
+ */
70
+ getLoadedPackIds(): string[];
71
+ /**
72
+ * Check if a specific pack is loaded.
73
+ */
74
+ isLoaded(packId: string): boolean;
75
+ /**
76
+ * Token estimate for currently loaded state.
77
+ */
78
+ getTokenEstimate(): {
79
+ promptTokens: number;
80
+ toolTokens: number;
81
+ };
82
+ }
@@ -0,0 +1,223 @@
1
+ /**
2
+ * Dynamic Capability Loading — CapabilityManager
3
+ *
4
+ * Manages the three-tier loading model for an agent:
5
+ * - Upfront: always active from the start
6
+ * - Loadable: within profile, activated on demand (sticky)
7
+ * - Forbidden: outside profile, triggers handoff suggestion
8
+ */
9
+ import { FORBIDDEN_PACK_SUGGESTIONS } from './packs.js';
10
+ export class CapabilityManager {
11
+ profileGroupSet;
12
+ packs;
13
+ loaded = new Map();
14
+ /** Reverse index: tool name → pack ID */
15
+ toolToPackIndex = new Map();
16
+ constructor(config) {
17
+ this.profileGroupSet = new Set(config.profileGroups);
18
+ this.packs = config.packs;
19
+ // Build tool → pack reverse index
20
+ for (const [packId, pack] of Object.entries(this.packs)) {
21
+ for (const tool of pack.tools) {
22
+ this.toolToPackIndex.set(tool, packId);
23
+ }
24
+ }
25
+ // Load upfront packs
26
+ for (const groupId of config.upfrontGroups) {
27
+ if (groupId in this.packs && this.profileGroupSet.has(groupId)) {
28
+ this.loaded.set(groupId, {
29
+ packId: groupId,
30
+ loadedAt: Date.now(),
31
+ trigger: 'upfront',
32
+ });
33
+ }
34
+ }
35
+ }
36
+ /**
37
+ * Get the tier of a capability pack relative to this agent.
38
+ */
39
+ getTier(packId) {
40
+ if (this.loaded.has(packId)) {
41
+ return 'upfront'; // Already loaded (whether upfront or later)
42
+ }
43
+ if (this.profileGroupSet.has(packId)) {
44
+ return 'loadable';
45
+ }
46
+ return 'forbidden';
47
+ }
48
+ /**
49
+ * Load a capability pack. Returns false if forbidden.
50
+ * Once loaded, packs stay loaded (sticky mode).
51
+ */
52
+ load(packId, trigger) {
53
+ // Already loaded → no-op success
54
+ if (this.loaded.has(packId)) {
55
+ return true;
56
+ }
57
+ // Not in profile → forbidden
58
+ if (!this.profileGroupSet.has(packId)) {
59
+ return false;
60
+ }
61
+ // Pack must exist
62
+ if (!(packId in this.packs)) {
63
+ return false;
64
+ }
65
+ this.loaded.set(packId, {
66
+ packId,
67
+ loadedAt: Date.now(),
68
+ trigger,
69
+ });
70
+ return true;
71
+ }
72
+ /**
73
+ * Load multiple packs for a skill invocation.
74
+ * Maps tool names to pack IDs, then loads each.
75
+ */
76
+ loadForSkill(toolNames, trigger) {
77
+ const loaded = [];
78
+ const alreadyLoaded = [];
79
+ const forbidden = [];
80
+ // Deduplicate pack IDs from tool names
81
+ const packIds = new Set();
82
+ for (const toolName of toolNames) {
83
+ const packId = this.toolToPackIndex.get(toolName);
84
+ if (packId) {
85
+ packIds.add(packId);
86
+ }
87
+ }
88
+ for (const packId of packIds) {
89
+ if (this.loaded.has(packId)) {
90
+ alreadyLoaded.push(packId);
91
+ }
92
+ else if (this.load(packId, trigger)) {
93
+ loaded.push(packId);
94
+ }
95
+ else {
96
+ forbidden.push({
97
+ packId,
98
+ suggestedAgent: this.getSuggestedAgent(packId),
99
+ });
100
+ }
101
+ }
102
+ return {
103
+ success: forbidden.length === 0,
104
+ loaded,
105
+ alreadyLoaded,
106
+ forbidden,
107
+ };
108
+ }
109
+ /**
110
+ * Get all currently loaded tool names (deduplicated).
111
+ */
112
+ getActiveToolNames() {
113
+ const names = new Set();
114
+ for (const [packId] of this.loaded) {
115
+ const pack = this.packs[packId];
116
+ for (const tool of pack.tools) {
117
+ names.add(tool);
118
+ }
119
+ }
120
+ return [...names];
121
+ }
122
+ /**
123
+ * Get prompt module IDs to include (deduplicated across loaded packs).
124
+ */
125
+ getActivePromptModuleIds() {
126
+ const ids = new Set();
127
+ for (const [packId] of this.loaded) {
128
+ const pack = this.packs[packId];
129
+ for (const moduleId of pack.promptModules) {
130
+ ids.add(moduleId);
131
+ }
132
+ }
133
+ return ids;
134
+ }
135
+ /**
136
+ * Get prompt snippets from loaded packs.
137
+ */
138
+ getActivePromptSnippets() {
139
+ const snippets = [];
140
+ for (const [packId] of this.loaded) {
141
+ const pack = this.packs[packId];
142
+ if (pack.promptSnippet) {
143
+ snippets.push(pack.promptSnippet);
144
+ }
145
+ }
146
+ return snippets;
147
+ }
148
+ /**
149
+ * Get catalog of loadable (not yet loaded) packs for the system prompt.
150
+ */
151
+ getCatalog() {
152
+ const entries = [];
153
+ for (const [packId, pack] of Object.entries(this.packs)) {
154
+ // Only include packs that are loadable (in profile but not yet loaded)
155
+ if (this.profileGroupSet.has(packId) && !this.loaded.has(packId)) {
156
+ entries.push({
157
+ id: pack.id,
158
+ label: pack.label,
159
+ toolCount: pack.tools.length,
160
+ readOnly: pack.readOnly,
161
+ });
162
+ }
163
+ }
164
+ return entries;
165
+ }
166
+ /**
167
+ * Check if any loadable packs remain (not yet loaded).
168
+ */
169
+ hasLoadablePacks() {
170
+ for (const packId of this.profileGroupSet) {
171
+ if (!this.loaded.has(packId)) {
172
+ return true;
173
+ }
174
+ }
175
+ return false;
176
+ }
177
+ /**
178
+ * Find which pack contains a given tool name.
179
+ */
180
+ findPackForTool(toolName) {
181
+ return this.toolToPackIndex.get(toolName);
182
+ }
183
+ /**
184
+ * Get suggested agent for a forbidden pack.
185
+ */
186
+ getSuggestedAgent(packId) {
187
+ return FORBIDDEN_PACK_SUGGESTIONS[packId];
188
+ }
189
+ /**
190
+ * Get all loaded pack IDs.
191
+ */
192
+ getLoadedPackIds() {
193
+ return [...this.loaded.keys()];
194
+ }
195
+ /**
196
+ * Check if a specific pack is loaded.
197
+ */
198
+ isLoaded(packId) {
199
+ return this.loaded.has(packId);
200
+ }
201
+ /**
202
+ * Token estimate for currently loaded state.
203
+ */
204
+ getTokenEstimate() {
205
+ let promptTokens = 0;
206
+ let toolTokens = 0;
207
+ // Track seen prompt module IDs to avoid double-counting shared modules
208
+ const seenModules = new Set();
209
+ for (const [packId] of this.loaded) {
210
+ const pack = this.packs[packId];
211
+ // Count prompt tokens only for new modules
212
+ for (const moduleId of pack.promptModules) {
213
+ if (!seenModules.has(moduleId)) {
214
+ seenModules.add(moduleId);
215
+ promptTokens += pack.estimatedPromptTokens;
216
+ }
217
+ }
218
+ // Always count tool tokens (tools are unique per pack)
219
+ toolTokens += pack.estimatedToolTokens;
220
+ }
221
+ return { promptTokens, toolTokens };
222
+ }
223
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Dynamic Capability Loading — Pack Definitions
3
+ *
4
+ * Maps each tool group (from tool-config.ts) to a capability pack with
5
+ * associated prompt modules and usage guidance.
6
+ *
7
+ * 24 packs total, matching 1:1 with TOOL_GROUPS keys.
8
+ */
9
+ import type { CapabilityPack } from './types.js';
10
+ /**
11
+ * All capability pack definitions.
12
+ *
13
+ * Tool names are string literals (not imported from TOOL_NAMES) to keep the SDK
14
+ * independent of CLI-specific tool-names.ts. The CLI validates consistency at startup.
15
+ */
16
+ export declare const CAPABILITY_PACKS: Record<string, CapabilityPack>;
17
+ /**
18
+ * Mapping from forbidden pack IDs to suggested agent roles.
19
+ * Used for handoff suggestions when an agent tries to load a forbidden capability.
20
+ */
21
+ export declare const FORBIDDEN_PACK_SUGGESTIONS: Record<string, string>;
22
+ /**
23
+ * Get the total number of defined capability packs.
24
+ */
25
+ export declare function getPackCount(): number;
26
+ /**
27
+ * Get all pack IDs.
28
+ */
29
+ export declare function getAllPackIds(): string[];
@@ -0,0 +1,291 @@
1
+ /**
2
+ * Dynamic Capability Loading — Pack Definitions
3
+ *
4
+ * Maps each tool group (from tool-config.ts) to a capability pack with
5
+ * associated prompt modules and usage guidance.
6
+ *
7
+ * 24 packs total, matching 1:1 with TOOL_GROUPS keys.
8
+ */
9
+ /**
10
+ * All capability pack definitions.
11
+ *
12
+ * Tool names are string literals (not imported from TOOL_NAMES) to keep the SDK
13
+ * independent of CLI-specific tool-names.ts. The CLI validates consistency at startup.
14
+ */
15
+ export const CAPABILITY_PACKS = {
16
+ // ============= DIRECT TOOL PACKS =============
17
+ file_read: {
18
+ id: 'file_read',
19
+ label: 'File Reading',
20
+ tools: ['read_file', 'glob', 'grep'],
21
+ readOnly: true,
22
+ promptModules: [],
23
+ estimatedPromptTokens: 0,
24
+ estimatedToolTokens: 900,
25
+ },
26
+ file_write: {
27
+ id: 'file_write',
28
+ label: 'File Writing',
29
+ tools: ['write_file', 'edit'],
30
+ readOnly: false,
31
+ promptModules: [],
32
+ estimatedPromptTokens: 0,
33
+ estimatedToolTokens: 600,
34
+ },
35
+ shell: {
36
+ id: 'shell',
37
+ label: 'Shell Commands',
38
+ tools: ['bash', 'bash_output', 'kill_shell'],
39
+ readOnly: false,
40
+ promptModules: [],
41
+ estimatedPromptTokens: 0,
42
+ estimatedToolTokens: 900,
43
+ },
44
+ tasks: {
45
+ id: 'tasks',
46
+ label: 'Task Tracking',
47
+ tools: ['todo_write', 'todo_read', 'todo_claim', 'todo_handoff'],
48
+ readOnly: false,
49
+ promptModules: [],
50
+ estimatedPromptTokens: 0,
51
+ estimatedToolTokens: 1200,
52
+ },
53
+ interaction: {
54
+ id: 'interaction',
55
+ label: 'User Interaction',
56
+ tools: ['ask_user', 'ask_user_simple', 'suggest'],
57
+ readOnly: true,
58
+ promptModules: [],
59
+ estimatedPromptTokens: 0,
60
+ estimatedToolTokens: 900,
61
+ },
62
+ coordinator: {
63
+ id: 'coordinator',
64
+ label: 'Coordination',
65
+ tools: ['delegate', 'delegate_background', 'delegation_status'],
66
+ readOnly: false,
67
+ promptModules: [],
68
+ estimatedPromptTokens: 0,
69
+ estimatedToolTokens: 900,
70
+ },
71
+ handoff: {
72
+ id: 'handoff',
73
+ label: 'Agent Handoff',
74
+ tools: ['handoff'],
75
+ readOnly: false,
76
+ promptModules: [],
77
+ estimatedPromptTokens: 0,
78
+ estimatedToolTokens: 300,
79
+ },
80
+ guide: {
81
+ id: 'guide',
82
+ label: 'CLI Documentation',
83
+ tools: ['compilr_guide'],
84
+ readOnly: true,
85
+ promptModules: [],
86
+ estimatedPromptTokens: 0,
87
+ estimatedToolTokens: 300,
88
+ },
89
+ meta: {
90
+ id: 'meta',
91
+ label: 'Tool Discovery',
92
+ tools: ['list_tools', 'get_tool_info', 'use_tool'],
93
+ readOnly: true,
94
+ promptModules: [],
95
+ estimatedPromptTokens: 0,
96
+ estimatedToolTokens: 900,
97
+ },
98
+ subagents: {
99
+ id: 'subagents',
100
+ label: 'Subagent Delegation',
101
+ tools: ['task'],
102
+ readOnly: false,
103
+ promptModules: [],
104
+ estimatedPromptTokens: 0,
105
+ estimatedToolTokens: 300,
106
+ },
107
+ // ============= META-REGISTRY TOOL PACKS =============
108
+ git_read: {
109
+ id: 'git_read',
110
+ label: 'Git (Read)',
111
+ tools: ['git_status', 'git_diff', 'git_log', 'git_blame', 'git_file_history'],
112
+ readOnly: true,
113
+ promptModules: ['git-safety'],
114
+ promptSnippet: 'Git read tools: git_status, git_diff, git_log, git_blame, git_file_history',
115
+ estimatedPromptTokens: 300,
116
+ estimatedToolTokens: 1500,
117
+ },
118
+ git_write: {
119
+ id: 'git_write',
120
+ label: 'Git (Write)',
121
+ tools: ['git_commit', 'git_branch', 'git_stash'],
122
+ readOnly: false,
123
+ promptModules: ['git-safety'],
124
+ promptSnippet: 'Git write tools: git_commit, git_branch, git_stash. Always check git_status before committing.',
125
+ estimatedPromptTokens: 300,
126
+ estimatedToolTokens: 900,
127
+ },
128
+ project: {
129
+ id: 'project',
130
+ label: 'Project Analysis',
131
+ tools: [
132
+ 'detect_project',
133
+ 'find_project_root',
134
+ 'get_file_structure',
135
+ 'get_complexity',
136
+ 'read_function',
137
+ 'read_class',
138
+ 'read_type',
139
+ ],
140
+ readOnly: true,
141
+ promptModules: [],
142
+ promptSnippet: 'Project analysis: detect_project, find_project_root, get_file_structure, get_complexity, read_function, read_class, read_type',
143
+ estimatedPromptTokens: 30,
144
+ estimatedToolTokens: 2100,
145
+ },
146
+ runners: {
147
+ id: 'runners',
148
+ label: 'Runners (Test/Build/Lint)',
149
+ tools: ['run_tests', 'run_lint', 'run_build', 'run_format'],
150
+ readOnly: false,
151
+ promptModules: [],
152
+ promptSnippet: 'Runner tools: run_tests, run_lint, run_build, run_format',
153
+ estimatedPromptTokens: 15,
154
+ estimatedToolTokens: 1200,
155
+ },
156
+ search: {
157
+ id: 'search',
158
+ label: 'Code Search',
159
+ tools: ['find_definition', 'find_references', 'find_todos'],
160
+ readOnly: true,
161
+ promptModules: [],
162
+ promptSnippet: 'Code search: find_definition, find_references, find_todos',
163
+ estimatedPromptTokens: 15,
164
+ estimatedToolTokens: 900,
165
+ },
166
+ dependencies: {
167
+ id: 'dependencies',
168
+ label: 'Dependency Analysis',
169
+ tools: ['check_outdated', 'find_vulnerabilities', 'analyze_test_coverage'],
170
+ readOnly: true,
171
+ promptModules: [],
172
+ promptSnippet: 'Dependencies: check_outdated, find_vulnerabilities, analyze_test_coverage',
173
+ estimatedPromptTokens: 15,
174
+ estimatedToolTokens: 900,
175
+ },
176
+ backlog_read: {
177
+ id: 'backlog_read',
178
+ label: 'Backlog (Read)',
179
+ tools: ['workitem_query', 'workitem_status_counts'],
180
+ readOnly: true,
181
+ promptModules: ['platform-tool-hints'],
182
+ promptSnippet: 'Backlog read: workitem_query, workitem_status_counts',
183
+ estimatedPromptTokens: 120,
184
+ estimatedToolTokens: 600,
185
+ },
186
+ backlog_write: {
187
+ id: 'backlog_write',
188
+ label: 'Backlog (Write)',
189
+ tools: [
190
+ 'workitem_add',
191
+ 'workitem_update',
192
+ 'workitem_delete',
193
+ 'workitem_next',
194
+ 'workitem_advance_step',
195
+ 'workitem_claim',
196
+ 'workitem_handoff',
197
+ ],
198
+ readOnly: false,
199
+ promptModules: ['platform-tool-hints'],
200
+ promptSnippet: 'Backlog write: workitem_add, workitem_update, workitem_delete, workitem_next, workitem_advance_step, workitem_claim, workitem_handoff. Use workitem_query before modifications.',
201
+ estimatedPromptTokens: 120,
202
+ estimatedToolTokens: 2100,
203
+ },
204
+ documents: {
205
+ id: 'documents',
206
+ label: 'Project Documents',
207
+ tools: [
208
+ 'project_document_add',
209
+ 'project_document_get',
210
+ 'project_document_list',
211
+ 'project_document_delete',
212
+ ],
213
+ readOnly: false,
214
+ promptModules: ['platform-tool-hints'],
215
+ promptSnippet: 'Documents stored in database, not filesystem. Use project_document_add/get/list/delete. Valid doc_types: prd, architecture, design, notes, session-note',
216
+ estimatedPromptTokens: 120,
217
+ estimatedToolTokens: 1200,
218
+ },
219
+ plans: {
220
+ id: 'plans',
221
+ label: 'Planning',
222
+ tools: ['plan_create', 'plan_update', 'plan_get', 'plan_list', 'plan_delete'],
223
+ readOnly: false,
224
+ promptModules: ['platform-tool-hints'],
225
+ promptSnippet: 'Plan tools: plan_create, plan_get, plan_list, plan_update, plan_delete. Status flow: draft → approved → in_progress → completed',
226
+ estimatedPromptTokens: 120,
227
+ estimatedToolTokens: 1500,
228
+ },
229
+ artifacts: {
230
+ id: 'artifacts',
231
+ label: 'Team Artifacts',
232
+ tools: ['artifact_save', 'artifact_get', 'artifact_list', 'artifact_delete'],
233
+ readOnly: false,
234
+ promptModules: ['platform-tool-hints'],
235
+ promptSnippet: 'Artifacts: artifact_save, artifact_get, artifact_list, artifact_delete. Types: design, plan, review, decision, note. Names must be unique within team.',
236
+ estimatedPromptTokens: 120,
237
+ estimatedToolTokens: 1200,
238
+ },
239
+ anchors: {
240
+ id: 'anchors',
241
+ label: 'Context Anchors',
242
+ tools: ['anchor_add', 'anchor_list', 'anchor_remove'],
243
+ readOnly: false,
244
+ promptModules: ['platform-tool-hints'],
245
+ promptSnippet: 'Anchors survive context compaction. Use "critical" priority sparingly. Most anchors should be "info" priority with "project" scope.',
246
+ estimatedPromptTokens: 120,
247
+ estimatedToolTokens: 900,
248
+ },
249
+ project_db: {
250
+ id: 'project_db',
251
+ label: 'Project Database',
252
+ tools: ['project_get', 'project_list', 'project_update'],
253
+ readOnly: false,
254
+ promptModules: ['platform-tool-hints'],
255
+ promptSnippet: 'Project database: project_get, project_list, project_update. Default to active project unless targeting a different one.',
256
+ estimatedPromptTokens: 120,
257
+ estimatedToolTokens: 900,
258
+ },
259
+ };
260
+ /**
261
+ * Mapping from forbidden pack IDs to suggested agent roles.
262
+ * Used for handoff suggestions when an agent tries to load a forbidden capability.
263
+ */
264
+ export const FORBIDDEN_PACK_SUGGESTIONS = {
265
+ file_write: '$dev',
266
+ shell: '$dev',
267
+ git_write: '$dev',
268
+ runners: '$dev',
269
+ backlog_write: '$pm',
270
+ backlog_read: '$pm',
271
+ documents: '$pm',
272
+ plans: '$pm',
273
+ search: '$arch',
274
+ dependencies: '$arch',
275
+ coordinator: '$default',
276
+ artifacts: '$pm',
277
+ anchors: '$pm',
278
+ project_db: '$pm',
279
+ };
280
+ /**
281
+ * Get the total number of defined capability packs.
282
+ */
283
+ export function getPackCount() {
284
+ return Object.keys(CAPABILITY_PACKS).length;
285
+ }
286
+ /**
287
+ * Get all pack IDs.
288
+ */
289
+ export function getAllPackIds() {
290
+ return Object.keys(CAPABILITY_PACKS);
291
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Dynamic Capability Loading — Types
3
+ *
4
+ * Capability packs bundle tools, prompt modules, and usage guidance.
5
+ * Each pack maps 1:1 to an existing tool group from tool-config.ts.
6
+ */
7
+ /**
8
+ * A capability pack bundles tools with their associated prompt modules and guidance.
9
+ */
10
+ export interface CapabilityPack {
11
+ /** Matches a TOOL_GROUPS key (e.g., 'git_read', 'backlog_write') */
12
+ id: string;
13
+ /** Human-readable label (e.g., 'Git (Read)', 'Backlog Management') */
14
+ label: string;
15
+ /** Tool names in this pack */
16
+ tools: readonly string[];
17
+ /** Whether all tools in this pack are read-only */
18
+ readOnly: boolean;
19
+ /** System prompt module IDs to inject when loaded (from modules.ts) */
20
+ promptModules: readonly string[];
21
+ /** Optional inline prompt snippet for pack-specific guidance */
22
+ promptSnippet?: string;
23
+ /** Estimated token cost: prompt modules + snippet */
24
+ estimatedPromptTokens: number;
25
+ /** Estimated token cost: tool schemas in meta-registry index */
26
+ estimatedToolTokens: number;
27
+ }
28
+ /**
29
+ * Three-tier loading model for each capability pack relative to an agent.
30
+ *
31
+ * - upfront: Always loaded from the start (HOT_TOOLS ∩ profile)
32
+ * - loadable: Within profile but not yet active; loaded on demand
33
+ * - forbidden: Outside the agent's tool profile; triggers handoff suggestion
34
+ */
35
+ export type CapabilityTier = 'upfront' | 'loadable' | 'forbidden';
36
+ /**
37
+ * Tracks when and how a capability was loaded.
38
+ */
39
+ export interface LoadedCapability {
40
+ packId: string;
41
+ loadedAt: number;
42
+ trigger: 'upfront' | 'slash-command' | 'agent-self' | 'auto-detect';
43
+ }
44
+ /**
45
+ * Catalog entry shown in the agent's system prompt for self-loading.
46
+ */
47
+ export interface CapabilityCatalogEntry {
48
+ id: string;
49
+ label: string;
50
+ toolCount: number;
51
+ readOnly: boolean;
52
+ }
53
+ /**
54
+ * Result of attempting to load capabilities (e.g., for a skill invocation).
55
+ */
56
+ export interface CapabilityLoadResult {
57
+ success: boolean;
58
+ /** Packs that were loaded */
59
+ loaded: string[];
60
+ /** Packs that were already loaded */
61
+ alreadyLoaded: string[];
62
+ /** Packs that are forbidden (with suggested agent) */
63
+ forbidden: Array<{
64
+ packId: string;
65
+ suggestedAgent?: string;
66
+ }>;
67
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Dynamic Capability Loading — Types
3
+ *
4
+ * Capability packs bundle tools, prompt modules, and usage guidance.
5
+ * Each pack maps 1:1 to an existing tool group from tool-config.ts.
6
+ */
7
+ export {};
package/dist/index.d.ts CHANGED
@@ -45,6 +45,8 @@ export { type ModelTier, type TierInfo, type ProviderModelMap, MODEL_TIERS, TIER
45
45
  export { assembleTools, deduplicateTools } from './tools.js';
46
46
  export { MetaToolsRegistry, createMetaTools, META_TOOLS_SYSTEM_PROMPT_PREFIX, } from './meta-tools/index.js';
47
47
  export type { MetaToolStats, MetaTools } from './meta-tools/index.js';
48
+ export { CapabilityManager, CAPABILITY_PACKS, FORBIDDEN_PACK_SUGGESTIONS, getPackCount, getAllPackIds, createLoadCapabilityTool, generateCapabilityCatalog, } from './capabilities/index.js';
49
+ export type { CapabilityPack, CapabilityTier, LoadedCapability, CapabilityCatalogEntry, CapabilityLoadResult, CapabilityManagerConfig, } from './capabilities/index.js';
48
50
  export { SystemPromptBuilder, buildSystemPrompt, detectGitRepository, getModuleStats, ALL_MODULES, IDENTITY_MODULE, STYLE_MODULE, TASK_EXECUTION_MODULE, TODO_MANAGEMENT_MODULE, TOOL_USAGE_DIRECT_MODULE, TOOL_USAGE_HINTS_MODULE, PLATFORM_TOOL_HINTS_MODULE, FACTORY_TOOL_HINTS_MODULE, TOOL_USAGE_META_MODULE, DELEGATION_MODULE, GIT_SAFETY_MODULE, SUGGEST_MODULE, IMPORTANT_RULES_MODULE, ENVIRONMENT_MODULE, shouldIncludeModule, getEstimatedTokensForConditions, getTotalEstimatedTokens, } from './system-prompt/index.js';
49
51
  export type { SystemPromptContext, BuildResult, SystemPromptModule, ModuleConditions, } from './system-prompt/index.js';
50
52
  export type { ProjectType, ProjectStatus, RepoPattern, WorkflowMode, LifecycleState, WorkItemType, WorkItemStatus, WorkItemPriority, GuidedStep, DocumentType, PlanStatus, Project, WorkItem, ProjectDocument, Plan, PlanSummary, PlanWithWorkItem, HistoryEntry, CreateProjectInput, UpdateProjectInput, ProjectListOptions, CreateWorkItemInput, UpdateWorkItemInput, QueryWorkItemsInput, CreateDocumentInput, UpdateDocumentInput, CreatePlanInput, UpdatePlanInput, ListPlansOptions, WorkItemQueryResult, ProjectListResult, BulkCreateItem, IProjectRepository, IWorkItemRepository, IDocumentRepository, IPlanRepository, IAnchorService, IArtifactService, IEpisodeService, AnchorData, ArtifactType, ArtifactData, ArtifactSummaryData, WorkEpisode, ProjectWorkSummary, PlatformContext, PlatformToolsConfig, PlatformHooks, StepCriteria, } from './platform/index.js';
package/dist/index.js CHANGED
@@ -65,6 +65,18 @@ export { assembleTools, deduplicateTools } from './tools.js';
65
65
  // =============================================================================
66
66
  export { MetaToolsRegistry, createMetaTools, META_TOOLS_SYSTEM_PROMPT_PREFIX, } from './meta-tools/index.js';
67
67
  // =============================================================================
68
+ // Dynamic Capability Loading
69
+ // =============================================================================
70
+ export {
71
+ // Manager
72
+ CapabilityManager,
73
+ // Pack definitions
74
+ CAPABILITY_PACKS, FORBIDDEN_PACK_SUGGESTIONS, getPackCount, getAllPackIds,
75
+ // Self-loading tool
76
+ createLoadCapabilityTool,
77
+ // Catalog generator
78
+ generateCapabilityCatalog, } from './capabilities/index.js';
79
+ // =============================================================================
68
80
  // System Prompt Builder
69
81
  // =============================================================================
70
82
  export {
@@ -17,7 +17,7 @@
17
17
  */
18
18
  export const MODEL_REGISTRY = [
19
19
  // ---------------------------------------------------------------------------
20
- // Claude Models (Anthropic)
20
+ // Claude Models (Anthropic) — Current generation (4.6 + Haiku 4.5)
21
21
  // ---------------------------------------------------------------------------
22
22
  {
23
23
  id: 'claude-haiku-4-5-20251001',
@@ -30,8 +30,8 @@ export const MODEL_REGISTRY = [
30
30
  contextWindow: 200000,
31
31
  },
32
32
  {
33
- id: 'claude-sonnet-4-5-20250929',
34
- displayName: 'Sonnet 4.5',
33
+ id: 'claude-sonnet-4-6',
34
+ displayName: 'Sonnet 4.6',
35
35
  description: 'Balanced (recommended)',
36
36
  provider: 'claude',
37
37
  defaultTier: 'balanced',
@@ -40,8 +40,8 @@ export const MODEL_REGISTRY = [
40
40
  contextWindow: 200000,
41
41
  },
42
42
  {
43
- id: 'claude-opus-4-5-20251101',
44
- displayName: 'Opus 4.5',
43
+ id: 'claude-opus-4-6',
44
+ displayName: 'Opus 4.6',
45
45
  description: 'Most capable',
46
46
  provider: 'claude',
47
47
  defaultTier: 'powerful',
@@ -49,26 +49,36 @@ export const MODEL_REGISTRY = [
49
49
  status: 'supported',
50
50
  contextWindow: 200000,
51
51
  },
52
- // Older Claude models (still supported)
52
+ // Legacy Claude models (still supported)
53
53
  {
54
- id: 'claude-3-5-sonnet-20241022',
55
- displayName: 'Sonnet 3.5',
54
+ id: 'claude-sonnet-4-5-20250929',
55
+ displayName: 'Sonnet 4.5',
56
+ description: 'Previous generation',
57
+ provider: 'claude',
58
+ thinkingFormat: 'claude',
59
+ status: 'supported',
60
+ contextWindow: 200000,
61
+ notes: 'Legacy — consider upgrading to Sonnet 4.6',
62
+ },
63
+ {
64
+ id: 'claude-opus-4-5-20251101',
65
+ displayName: 'Opus 4.5',
56
66
  description: 'Previous generation',
57
67
  provider: 'claude',
58
68
  thinkingFormat: 'claude',
59
69
  status: 'supported',
60
70
  contextWindow: 200000,
61
- notes: 'Previous generation',
71
+ notes: 'Legacy — consider upgrading to Opus 4.6',
62
72
  },
63
73
  {
64
- id: 'claude-3-5-haiku-20241022',
65
- displayName: 'Haiku 3.5',
74
+ id: 'claude-sonnet-4-20250514',
75
+ displayName: 'Sonnet 4',
66
76
  description: 'Previous generation',
67
77
  provider: 'claude',
68
78
  thinkingFormat: 'claude',
69
79
  status: 'supported',
70
80
  contextWindow: 200000,
71
- notes: 'Previous generation',
81
+ notes: 'Legacy',
72
82
  },
73
83
  // ---------------------------------------------------------------------------
74
84
  // Gemini Models (Google)
@@ -413,8 +423,8 @@ export const MODEL_REGISTRY = [
413
423
  status: 'supported',
414
424
  },
415
425
  {
416
- id: 'anthropic/claude-3-5-sonnet',
417
- displayName: 'Claude 3.5 Sonnet',
426
+ id: 'anthropic/claude-sonnet-4-6',
427
+ displayName: 'Claude Sonnet 4.6',
418
428
  description: 'Balanced (via OpenRouter)',
419
429
  provider: 'openrouter',
420
430
  defaultTier: 'balanced',
@@ -422,8 +432,8 @@ export const MODEL_REGISTRY = [
422
432
  status: 'supported',
423
433
  },
424
434
  {
425
- id: 'anthropic/claude-3-opus',
426
- displayName: 'Claude 3 Opus',
435
+ id: 'anthropic/claude-opus-4-6',
436
+ displayName: 'Claude Opus 4.6',
427
437
  description: 'Most capable (via OpenRouter)',
428
438
  provider: 'openrouter',
429
439
  defaultTier: 'powerful',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compilr-dev/sdk",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "description": "Universal agent runtime for building AI-powered applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",