@compilr-dev/cli 0.5.15 → 0.5.17
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/.tsbuildinfo.app +1 -1
- package/dist/.tsbuildinfo.data +1 -1
- package/dist/.tsbuildinfo.domain +1 -1
- package/dist/.tsbuildinfo.foundation +1 -1
- package/dist/agent.d.ts +4 -0
- package/dist/agent.js +32 -157
- package/dist/agents/registry.js +5 -4
- package/dist/auth/index.js +3 -3
- package/dist/commands/custom-registry.js +4 -3
- package/dist/compilr-diff-companion.vsix +0 -0
- package/dist/foundation/logger.d.ts +9 -0
- package/dist/foundation/logger.js +16 -0
- package/dist/repl-v2.js +4 -3
- package/dist/settings/index.js +2 -1
- package/dist/settings/paths.js +2 -1
- package/dist/shared-handlers.d.ts +2 -32
- package/dist/tools/ask-user-simple.d.ts +4 -15
- package/dist/tools/ask-user-simple.js +10 -82
- package/dist/tools/ask-user.d.ts +5 -28
- package/dist/tools/ask-user.js +10 -109
- package/dist/tools/db-tools.d.ts +1 -1
- package/dist/tools/platform-adapter.d.ts +1 -1
- package/dist/ui/terminal-renderer.js +2 -2
- package/dist/utils/credentials.js +6 -3
- package/package.json +5 -4
package/dist/agent.d.ts
CHANGED
|
@@ -194,6 +194,10 @@ export declare function getBuiltinGuardrailInfo(): Array<{
|
|
|
194
194
|
action: 'warn' | 'confirm' | 'block';
|
|
195
195
|
category: string;
|
|
196
196
|
}>;
|
|
197
|
+
/**
|
|
198
|
+
* Derive profile group IDs from a tool filter (array of tool names).
|
|
199
|
+
* A group is included if any of its tools are in the filter.
|
|
200
|
+
*/
|
|
197
201
|
/**
|
|
198
202
|
* Creates an Agent instance configured with all tools.
|
|
199
203
|
*/
|
package/dist/agent.js
CHANGED
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
* ClaudeProvider, OllamaProvider, OpenAIProvider, or GeminiProvider
|
|
6
6
|
* and available tools.
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
8
|
+
import { log } from './foundation/logger.js';
|
|
9
|
+
import { Agent, ContextManager, DEFAULT_CONTEXT_CONFIG, createTaskTool, createSuggestTool, defaultAgentTypes, TOOL_SETS, BUILTIN_GUARDRAILS, createProviderFromType, CapabilityManager, CapabilityContext, CAPABILITY_PACKS, GIT_SAFETY_MODULE, PLATFORM_TOOL_HINTS_MODULE, FACTORY_TOOL_HINTS_MODULE, TOOL_USAGE_META_MODULE, createLoadCapabilityTool, createCapabilityHook, resolveProfileGroups, resolveUpfrontGroups, } from '@compilr-dev/sdk';
|
|
9
10
|
import { isAutoCompactEnabled, isDelegationEnabled, getSetting } from './settings/index.js';
|
|
10
11
|
import { getApiKey } from './utils/credentials.js';
|
|
11
12
|
import { createToolRegistry, createMinimalToolRegistry, getDirectTools, getMetaTools, initializeMetaTools, getToolIndexForSystemPrompt, getFilteredToolIndexForSystemPrompt, getToolStats, setMetaToolFilter, createToolFallback, getRegisteredMetaTools, } from './tools.js';
|
|
12
|
-
|
|
13
|
+
// TOOL_GROUPS no longer needed — profile resolution moved to SDK
|
|
13
14
|
import { setCapabilityManager } from './multi-agent/capability-loader.js';
|
|
14
15
|
import { getAgentRegistry } from './agents/registry.js';
|
|
15
16
|
import { SystemPromptBuilder } from './system-prompt/index.js';
|
|
@@ -135,144 +136,9 @@ function createProvider(options) {
|
|
|
135
136
|
* Derive profile group IDs from a tool filter (array of tool names).
|
|
136
137
|
* A group is included if any of its tools are in the filter.
|
|
137
138
|
*/
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
for (const [groupId, group] of Object.entries(TOOL_GROUPS)) {
|
|
142
|
-
if (group.tools.some((t) => toolSet.has(t))) {
|
|
143
|
-
groups.push(groupId);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
return groups;
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Scan recent messages for "Tool not found: X" errors and auto-load
|
|
150
|
-
* the corresponding capability packs (max 2 per turn, loadable only).
|
|
151
|
-
* Also detects forbidden tool access for handoff suggestions.
|
|
152
|
-
*/
|
|
153
|
-
function autoDetectCapabilities(manager, messages) {
|
|
154
|
-
const MAX_AUTO_LOADS = 2;
|
|
155
|
-
const result = { loaded: [], forbidden: [] };
|
|
156
|
-
const toolNotFoundPattern = /Tool not found: (\w+)/;
|
|
157
|
-
// Find the most recent user message (contains the last turn's tool results)
|
|
158
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
159
|
-
const msg = messages[i];
|
|
160
|
-
if (msg.role !== 'user' || typeof msg.content === 'string')
|
|
161
|
-
continue;
|
|
162
|
-
// Scan this message's tool_result blocks for "Tool not found" errors
|
|
163
|
-
for (const block of msg.content) {
|
|
164
|
-
if (block.type !== 'tool_result' || !block.isError || !block.content)
|
|
165
|
-
continue;
|
|
166
|
-
const match = toolNotFoundPattern.exec(block.content);
|
|
167
|
-
if (!match)
|
|
168
|
-
continue;
|
|
169
|
-
const toolName = match[1];
|
|
170
|
-
const packId = manager.findPackForTool(toolName);
|
|
171
|
-
if (!packId || manager.isLoaded(packId))
|
|
172
|
-
continue;
|
|
173
|
-
const tier = manager.getTier(packId);
|
|
174
|
-
if (tier === 'loadable' && result.loaded.length < MAX_AUTO_LOADS) {
|
|
175
|
-
manager.load(packId, 'auto-detect');
|
|
176
|
-
result.loaded.push(packId);
|
|
177
|
-
}
|
|
178
|
-
else if (tier === 'forbidden') {
|
|
179
|
-
result.forbidden.push({
|
|
180
|
-
toolName,
|
|
181
|
-
packId,
|
|
182
|
-
suggestedAgent: manager.getSuggestedAgent(packId),
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
// Only scan the most recent user message
|
|
187
|
-
break;
|
|
188
|
-
}
|
|
189
|
-
return result;
|
|
190
|
-
}
|
|
191
|
-
function createCapabilityHook(manager, basePrompt, orphanTools) {
|
|
192
|
-
return (ctx) => {
|
|
193
|
-
// Auto-detect capability needs from tool failures (safety net)
|
|
194
|
-
let forbiddenHints = [];
|
|
195
|
-
if (manager.hasLoadablePacks() || ctx.messages.length > 1) {
|
|
196
|
-
const detected = autoDetectCapabilities(manager, ctx.messages);
|
|
197
|
-
// Generate handoff suggestions for forbidden tool access
|
|
198
|
-
if (detected.forbidden.length > 0) {
|
|
199
|
-
forbiddenHints = detected.forbidden.map((f) => {
|
|
200
|
-
const agentHint = f.suggestedAgent
|
|
201
|
-
? ` Consider using handoff("${f.suggestedAgent}", "Need ${f.packId} access for ${f.toolName}").`
|
|
202
|
-
: '';
|
|
203
|
-
return `[System] Tool "${f.toolName}" requires ${f.packId} capability which is outside your tool profile.${agentHint}`;
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
const activeToolNames = manager.getActiveToolNames();
|
|
208
|
-
const activeModuleIds = manager.getActivePromptModuleIds();
|
|
209
|
-
// Include orphan tools (not in any capability pack) — always visible
|
|
210
|
-
const allActiveTools = [...activeToolNames, ...orphanTools];
|
|
211
|
-
// Update meta-tool filter for this turn
|
|
212
|
-
setMetaToolFilter(allActiveTools);
|
|
213
|
-
// Build dynamic system prompt sections
|
|
214
|
-
const dynamicSections = [];
|
|
215
|
-
// Meta-tools protocol (how to use get_tool_info/use_tool)
|
|
216
|
-
dynamicSections.push(TOOL_USAGE_META_MODULE.content);
|
|
217
|
-
// Conditional modules based on loaded capability packs
|
|
218
|
-
if (activeModuleIds.has('git-safety')) {
|
|
219
|
-
dynamicSections.push(GIT_SAFETY_MODULE.content);
|
|
220
|
-
}
|
|
221
|
-
if (activeModuleIds.has('platform-tool-hints')) {
|
|
222
|
-
dynamicSections.push(PLATFORM_TOOL_HINTS_MODULE.content);
|
|
223
|
-
}
|
|
224
|
-
if (activeModuleIds.has('factory-tool-hints')) {
|
|
225
|
-
dynamicSections.push(FACTORY_TOOL_HINTS_MODULE.content);
|
|
226
|
-
}
|
|
227
|
-
// Prompt snippets from loaded packs
|
|
228
|
-
const snippets = manager.getActivePromptSnippets();
|
|
229
|
-
if (snippets.length > 0) {
|
|
230
|
-
dynamicSections.push('## Active Tool Capabilities\n' + snippets.join('\n'));
|
|
231
|
-
}
|
|
232
|
-
// Filtered tool index (only loaded tools)
|
|
233
|
-
const filteredIndex = getFilteredToolIndexForSystemPrompt(allActiveTools);
|
|
234
|
-
dynamicSections.push(filteredIndex);
|
|
235
|
-
// Capability catalog (if loadable packs remain)
|
|
236
|
-
if (manager.hasLoadablePacks()) {
|
|
237
|
-
const catalog = manager.getCatalog();
|
|
238
|
-
const catalogSection = generateCapabilityCatalog(catalog, manager.getLoadedPackIds());
|
|
239
|
-
if (catalogSection) {
|
|
240
|
-
dynamicSections.push(catalogSection);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
// Preserve anchors from the current system prompt.
|
|
244
|
-
// The agents library injects anchors into systemContent BEFORE this hook runs.
|
|
245
|
-
// We must extract and re-append them, since we rebuild the prompt from basePrompt.
|
|
246
|
-
let anchorsBlock = '';
|
|
247
|
-
const anchorMarker = '## Active Anchors (Critical Information)';
|
|
248
|
-
const anchorIdx = ctx.systemPrompt.indexOf(anchorMarker);
|
|
249
|
-
if (anchorIdx > 0) {
|
|
250
|
-
// Find the preceding "---\n\n" separator
|
|
251
|
-
const separatorBefore = ctx.systemPrompt.lastIndexOf('---', anchorIdx);
|
|
252
|
-
const startIdx = separatorBefore > 0 ? separatorBefore : anchorIdx;
|
|
253
|
-
// Find the end: either the next "---" after the anchor block, or end of string
|
|
254
|
-
const afterAnchor = ctx.systemPrompt.indexOf('\n\n---\n\n', anchorIdx);
|
|
255
|
-
if (afterAnchor > 0) {
|
|
256
|
-
// Anchors are followed by more content (e.g., role ending) — extract just the anchor block
|
|
257
|
-
anchorsBlock = '\n\n' + ctx.systemPrompt.substring(startIdx, afterAnchor + 7); // include trailing "---\n\n"
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
// Anchors are at the end of the prompt
|
|
261
|
-
anchorsBlock = '\n\n' + ctx.systemPrompt.substring(startIdx);
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
const hookResult = {
|
|
265
|
-
systemPrompt: basePrompt + '\n\n' + dynamicSections.join('\n\n') + anchorsBlock,
|
|
266
|
-
};
|
|
267
|
-
// Inject forbidden boundary messages (handoff suggestions)
|
|
268
|
-
if (forbiddenHints.length > 0) {
|
|
269
|
-
const hintContent = forbiddenHints.join('\n');
|
|
270
|
-
const hintMessage = { role: 'user', content: hintContent };
|
|
271
|
-
hookResult.messages = [...ctx.messages, hintMessage];
|
|
272
|
-
}
|
|
273
|
-
return hookResult;
|
|
274
|
-
};
|
|
275
|
-
}
|
|
139
|
+
// getProfileGroupsFromToolFilter → replaced by resolveProfileGroups from SDK
|
|
140
|
+
// autoDetectCapabilities → replaced by autoDetectCapabilities from SDK
|
|
141
|
+
// createCapabilityHook → replaced by createCapabilityHook + CapabilityContext from SDK
|
|
276
142
|
/**
|
|
277
143
|
* Creates an Agent instance configured with all tools.
|
|
278
144
|
*/
|
|
@@ -300,10 +166,10 @@ export function createAgent(options = {}) {
|
|
|
300
166
|
const onEvent = options.verbose
|
|
301
167
|
? (event) => {
|
|
302
168
|
if (event.type === 'tool_start') {
|
|
303
|
-
|
|
169
|
+
log.debug({ component: 'agent', tool: event.name }, 'Tool starting');
|
|
304
170
|
}
|
|
305
171
|
else if (event.type === 'tool_end') {
|
|
306
|
-
|
|
172
|
+
log.debug({ component: 'agent', tool: event.name }, 'Tool done');
|
|
307
173
|
}
|
|
308
174
|
}
|
|
309
175
|
: undefined;
|
|
@@ -322,17 +188,14 @@ export function createAgent(options = {}) {
|
|
|
322
188
|
// tools and prompt modules are active per-turn.
|
|
323
189
|
// ==========================================================================
|
|
324
190
|
let capabilityManager;
|
|
191
|
+
let capabilityContext;
|
|
325
192
|
let orphanToolNames = [];
|
|
326
193
|
if (useMetaTools) {
|
|
327
|
-
//
|
|
194
|
+
// Use SDK's profile resolver instead of local implementation
|
|
328
195
|
const profileGroups = options.toolFilter
|
|
329
|
-
?
|
|
196
|
+
? resolveProfileGroups(options.toolFilter)
|
|
330
197
|
: Object.keys(CAPABILITY_PACKS);
|
|
331
|
-
|
|
332
|
-
const upfrontGroupIds = Object.entries(TOOL_GROUPS)
|
|
333
|
-
.filter(([, group]) => group.tier === 'direct')
|
|
334
|
-
.map(([id]) => id)
|
|
335
|
-
.filter((id) => profileGroups.includes(id));
|
|
198
|
+
const upfrontGroupIds = resolveUpfrontGroups(profileGroups);
|
|
336
199
|
capabilityManager = new CapabilityManager({
|
|
337
200
|
profileGroups,
|
|
338
201
|
packs: CAPABILITY_PACKS,
|
|
@@ -341,7 +204,6 @@ export function createAgent(options = {}) {
|
|
|
341
204
|
// Expose the capability manager for slash command handlers (Phase 3)
|
|
342
205
|
setCapabilityManager(capabilityManager);
|
|
343
206
|
// Compute orphan tools (meta-registry tools not in any capability pack)
|
|
344
|
-
// These are always visible regardless of which packs are loaded.
|
|
345
207
|
const packedTools = new Set();
|
|
346
208
|
for (const pack of Object.values(CAPABILITY_PACKS)) {
|
|
347
209
|
for (const tool of pack.tools) {
|
|
@@ -352,8 +214,13 @@ export function createAgent(options = {}) {
|
|
|
352
214
|
orphanToolNames = registered
|
|
353
215
|
.map((t) => t.definition.name)
|
|
354
216
|
.filter((name) => !packedTools.has(name));
|
|
355
|
-
//
|
|
356
|
-
|
|
217
|
+
// Create capability context (SDK) for filter sync + auto-load callback
|
|
218
|
+
capabilityContext = new CapabilityContext({
|
|
219
|
+
manager: capabilityManager,
|
|
220
|
+
orphanTools: orphanToolNames,
|
|
221
|
+
onFilterUpdate: (allowed) => { setMetaToolFilter(allowed); },
|
|
222
|
+
});
|
|
223
|
+
capabilityContext.syncFilter();
|
|
357
224
|
// Log stats (unless quiet mode)
|
|
358
225
|
if (!options.quiet) {
|
|
359
226
|
const stats = getToolStats();
|
|
@@ -506,9 +373,17 @@ ${options.systemPromptAddition}
|
|
|
506
373
|
messages.splice(1, 0, { role: 'user', content: hint });
|
|
507
374
|
return { messages };
|
|
508
375
|
},
|
|
509
|
-
// Capability-aware system prompt assembly (with auto-detection
|
|
510
|
-
...(
|
|
511
|
-
? [createCapabilityHook(
|
|
376
|
+
// Capability-aware system prompt assembly (SDK hook with auto-detection)
|
|
377
|
+
...(capabilityContext && baseSystemPrompt
|
|
378
|
+
? [createCapabilityHook(capabilityContext, baseSystemPrompt, {
|
|
379
|
+
staticSections: [TOOL_USAGE_META_MODULE.content],
|
|
380
|
+
conditionalModules: [
|
|
381
|
+
{ content: GIT_SAFETY_MODULE.content, whenModuleActive: ['git-safety'] },
|
|
382
|
+
{ content: PLATFORM_TOOL_HINTS_MODULE.content, whenModuleActive: ['platform-tool-hints'] },
|
|
383
|
+
{ content: FACTORY_TOOL_HINTS_MODULE.content, whenModuleActive: ['factory-tool-hints'] },
|
|
384
|
+
],
|
|
385
|
+
getToolIndex: (allowedNames) => getFilteredToolIndexForSystemPrompt(allowedNames),
|
|
386
|
+
})]
|
|
512
387
|
: []),
|
|
513
388
|
],
|
|
514
389
|
beforeTool: [createFileLockCheckHook(getActiveProject)],
|
|
@@ -601,7 +476,7 @@ ${options.systemPromptAddition}
|
|
|
601
476
|
// Now uses toolUseId for direct correlation (no more FIFO matching!)
|
|
602
477
|
onSpawn: (agentType, description, toolUseId) => {
|
|
603
478
|
if (options.verbose) {
|
|
604
|
-
|
|
479
|
+
log.debug({ component: 'agent', agentType, toolUseId }, 'Spawning sub-agent: %s', description);
|
|
605
480
|
}
|
|
606
481
|
// Immediately notify with toolUseId - no more queuing/matching!
|
|
607
482
|
if (toolUseId) {
|
|
@@ -613,7 +488,7 @@ ${options.systemPromptAddition}
|
|
|
613
488
|
},
|
|
614
489
|
onComplete: (agentType, result, toolUseId) => {
|
|
615
490
|
if (options.verbose) {
|
|
616
|
-
|
|
491
|
+
log.debug({ component: 'agent', agentType, iterations: result.iterations }, 'Sub-agent completed');
|
|
617
492
|
}
|
|
618
493
|
// Direct notification with toolUseId - no more searching!
|
|
619
494
|
if (toolUseId && options.onSubagentEnd) {
|
package/dist/agents/registry.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Handles loading, saving, and managing agent definitions.
|
|
5
5
|
* Loads from both project (.compilr-dev/agents/) and user (~/.compilr-dev/agents/) directories.
|
|
6
6
|
*/
|
|
7
|
+
import { log } from '../foundation/logger.js';
|
|
7
8
|
import * as fs from 'fs';
|
|
8
9
|
import * as path from 'path';
|
|
9
10
|
import { BUILTIN_AGENTS, PROJECT_AGENTS_DIR, USER_AGENTS_DIR, isValidAgentName, isBuiltinAgentName, } from './types.js';
|
|
@@ -61,16 +62,16 @@ function loadAgentsFromDir(dir, location) {
|
|
|
61
62
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
62
63
|
const parsed = parseAgentFile(content);
|
|
63
64
|
if (!parsed) {
|
|
64
|
-
|
|
65
|
+
log.warn({ component: 'agents', filePath }, 'Invalid agent file (no frontmatter)');
|
|
65
66
|
continue;
|
|
66
67
|
}
|
|
67
68
|
const { frontmatter, content: systemPrompt } = parsed;
|
|
68
69
|
if (!frontmatter.name || !frontmatter.description) {
|
|
69
|
-
|
|
70
|
+
log.warn({ component: 'agents', filePath }, 'Invalid agent file (missing name or description)');
|
|
70
71
|
continue;
|
|
71
72
|
}
|
|
72
73
|
if (!isValidAgentName(frontmatter.name)) {
|
|
73
|
-
|
|
74
|
+
log.warn({ component: 'agents', name: frontmatter.name, filePath }, 'Invalid agent name');
|
|
74
75
|
continue;
|
|
75
76
|
}
|
|
76
77
|
const model = (['sonnet', 'opus', 'haiku', 'inherit'].includes(frontmatter.model || '')
|
|
@@ -86,7 +87,7 @@ function loadAgentsFromDir(dir, location) {
|
|
|
86
87
|
});
|
|
87
88
|
}
|
|
88
89
|
catch (error) {
|
|
89
|
-
|
|
90
|
+
log.warn({ component: 'agents', filePath, err: error }, 'Failed to load agent file');
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
return agents;
|
package/dist/auth/index.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* // Show login prompt
|
|
11
11
|
* }
|
|
12
12
|
*/
|
|
13
|
+
import { log } from '../foundation/logger.js';
|
|
13
14
|
import { v4 as uuidv4 } from 'uuid';
|
|
14
15
|
import * as os from 'os';
|
|
15
16
|
import { loadAuthData, saveAuthData, clearAuthData, updateSession, hasAuthData, checkAuthFilePermissions, } from './storage.js';
|
|
@@ -314,9 +315,8 @@ class AuthManager {
|
|
|
314
315
|
}
|
|
315
316
|
const result = await apiRefreshToken(this.authData.session.refreshToken);
|
|
316
317
|
if (!result.success || !result.access_token || !result.refresh_token) {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
console.error('[auth] API_BASE_URL:', process.env.COMPILR_API_URL ?? '(not set, using compilr.dev)');
|
|
318
|
+
log.error({ component: 'auth', error: result.error ?? 'missing token fields' }, 'Token refresh failed');
|
|
319
|
+
log.error({ component: 'auth', apiBaseUrl: process.env.COMPILR_API_URL ?? '(not set, using compilr.dev)' }, 'API base URL at time of failure');
|
|
320
320
|
return false;
|
|
321
321
|
}
|
|
322
322
|
// Calculate expiry from expires_in (seconds), default to 1 hour
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Handles loading, saving, and managing custom command definitions.
|
|
5
5
|
* Loads from both project (.compilr-dev/commands/) and user (~/.compilr-dev/commands/) directories.
|
|
6
6
|
*/
|
|
7
|
+
import { log } from '../foundation/logger.js';
|
|
7
8
|
import * as fs from 'fs';
|
|
8
9
|
import * as path from 'path';
|
|
9
10
|
import { PROJECT_COMMANDS_DIR, USER_COMMANDS_DIR, isValidCommandName, } from './types.js';
|
|
@@ -88,11 +89,11 @@ function loadCommandsFromDir(dir, location) {
|
|
|
88
89
|
// Name from filename (without .md extension)
|
|
89
90
|
const name = path.basename(file, '.md');
|
|
90
91
|
if (!isValidCommandName(name)) {
|
|
91
|
-
|
|
92
|
+
log.warn({ component: 'commands', name, filePath }, 'Invalid command name');
|
|
92
93
|
continue;
|
|
93
94
|
}
|
|
94
95
|
if (!parsed.content) {
|
|
95
|
-
|
|
96
|
+
log.warn({ component: 'commands', filePath }, 'Empty command file');
|
|
96
97
|
continue;
|
|
97
98
|
}
|
|
98
99
|
commands.push({
|
|
@@ -104,7 +105,7 @@ function loadCommandsFromDir(dir, location) {
|
|
|
104
105
|
});
|
|
105
106
|
}
|
|
106
107
|
catch (error) {
|
|
107
|
-
|
|
108
|
+
log.warn({ component: 'commands', filePath, err: error }, 'Failed to load command file');
|
|
108
109
|
}
|
|
109
110
|
}
|
|
110
111
|
return commands;
|
|
Binary file
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI logger instance.
|
|
3
|
+
*
|
|
4
|
+
* Diagnostic logging only — NOT for user-facing terminal output.
|
|
5
|
+
* User-facing output uses TerminalUI/TerminalRenderer.
|
|
6
|
+
*
|
|
7
|
+
* Logs are written to ~/.compilr-dev/logs/cli.log (rotated, 10MB x 5).
|
|
8
|
+
*/
|
|
9
|
+
export declare const log: import("@compilr-dev/logger").Logger;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI logger instance.
|
|
3
|
+
*
|
|
4
|
+
* Diagnostic logging only — NOT for user-facing terminal output.
|
|
5
|
+
* User-facing output uses TerminalUI/TerminalRenderer.
|
|
6
|
+
*
|
|
7
|
+
* Logs are written to ~/.compilr-dev/logs/cli.log (rotated, 10MB x 5).
|
|
8
|
+
*/
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import { homedir } from 'os';
|
|
11
|
+
import { createLogger } from '@compilr-dev/logger';
|
|
12
|
+
const logDir = join(homedir(), '.compilr-dev', 'logs');
|
|
13
|
+
export const log = createLogger({
|
|
14
|
+
package: 'cli',
|
|
15
|
+
filePath: join(logDir, 'cli.log'),
|
|
16
|
+
});
|
package/dist/repl-v2.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* Or imported and used with a real agent from index.ts
|
|
11
11
|
*/
|
|
12
12
|
import { appendFileSync } from 'fs';
|
|
13
|
+
import { log } from './foundation/logger.js';
|
|
13
14
|
import { generateEditDiff, generateWriteDiff } from './ui/diff.js';
|
|
14
15
|
import { getPendingRequestsManager, setActiveSharedContext } from './multi-agent/index.js';
|
|
15
16
|
import { parseInputForMentions, hasReferences, buildMessageWithContext, ContextResolver, buildContextMap, } from './multi-agent/index.js';
|
|
@@ -153,11 +154,11 @@ ${JSON.stringify(state.messages, null, 2)}
|
|
|
153
154
|
|
|
154
155
|
`;
|
|
155
156
|
appendFileSync(DEBUG_LOG_FILE, logEntry);
|
|
156
|
-
|
|
157
|
-
|
|
157
|
+
log.debug({ component: 'repl', requestNum: debugRequestCount, file: DEBUG_LOG_FILE }, 'Debug request logged');
|
|
158
|
+
log.debug({ component: 'repl', systemPromptTokens, messagesTokens, totalToolTokens, totalEstimate }, 'Token estimate');
|
|
158
159
|
}
|
|
159
160
|
catch (error) {
|
|
160
|
-
|
|
161
|
+
log.error({ component: 'repl', err: error }, 'Failed to log agent request');
|
|
161
162
|
}
|
|
162
163
|
}
|
|
163
164
|
// =============================================================================
|
package/dist/settings/index.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Centralized settings management for the CLI.
|
|
5
5
|
* Persistence in ~/.compilr-dev/settings.json
|
|
6
6
|
*/
|
|
7
|
+
import { log } from '../foundation/logger.js';
|
|
7
8
|
import * as fs from 'fs';
|
|
8
9
|
import * as path from 'path';
|
|
9
10
|
import * as os from 'os';
|
|
@@ -89,7 +90,7 @@ function saveToDisk(settings) {
|
|
|
89
90
|
fs.writeFileSync(CONFIG_FILE, JSON.stringify(settings, null, 2), 'utf-8');
|
|
90
91
|
}
|
|
91
92
|
catch (error) {
|
|
92
|
-
|
|
93
|
+
log.error({ component: 'settings', err: error }, 'Failed to save settings');
|
|
93
94
|
}
|
|
94
95
|
}
|
|
95
96
|
// =============================================================================
|
package/dist/settings/paths.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* 2. Config file (~/.compilr-dev/settings.json)
|
|
10
10
|
* 3. Default/derived value
|
|
11
11
|
*/
|
|
12
|
+
import { log } from '../foundation/logger.js';
|
|
12
13
|
import * as fs from 'fs';
|
|
13
14
|
import * as path from 'path';
|
|
14
15
|
import * as os from 'os';
|
|
@@ -60,7 +61,7 @@ function savePathConfig(pathConfig) {
|
|
|
60
61
|
fs.writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2), 'utf-8');
|
|
61
62
|
}
|
|
62
63
|
catch (error) {
|
|
63
|
-
|
|
64
|
+
log.error({ component: 'settings', err: error }, 'Failed to save path config');
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
/**
|
|
@@ -5,38 +5,8 @@
|
|
|
5
5
|
* accessible from tools but are set up at the application level.
|
|
6
6
|
* This avoids circular imports between index.ts and tool modules.
|
|
7
7
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
header: string;
|
|
11
|
-
question: string;
|
|
12
|
-
options?: string[];
|
|
13
|
-
allowCustom?: boolean;
|
|
14
|
-
multiSelect?: boolean;
|
|
15
|
-
}
|
|
16
|
-
export interface AskUserInput {
|
|
17
|
-
questions: AskUserQuestion[];
|
|
18
|
-
context?: string;
|
|
19
|
-
}
|
|
20
|
-
export interface AskUserResult {
|
|
21
|
-
answers: Record<string, string | string[]>;
|
|
22
|
-
skipped: string[];
|
|
23
|
-
}
|
|
24
|
-
export type AskUserHandler = (input: AskUserInput) => Promise<AskUserResult>;
|
|
25
|
-
export interface AskUserSimpleInput {
|
|
26
|
-
/** The question text */
|
|
27
|
-
question: string;
|
|
28
|
-
/** Predefined options (optional, max 5) */
|
|
29
|
-
options?: string[];
|
|
30
|
-
/** Allow free-text input (default: true) */
|
|
31
|
-
allowCustom?: boolean;
|
|
32
|
-
}
|
|
33
|
-
export interface AskUserSimpleResult {
|
|
34
|
-
/** User's answer */
|
|
35
|
-
answer: string;
|
|
36
|
-
/** True if user skipped the question */
|
|
37
|
-
skipped: boolean;
|
|
38
|
-
}
|
|
39
|
-
export type AskUserSimpleHandler = (input: AskUserSimpleInput) => Promise<AskUserSimpleResult>;
|
|
8
|
+
import type { AskUserHandler, AskUserSimpleHandler } from '@compilr-dev/sdk';
|
|
9
|
+
export type { AskUserQuestion, AskUserInput, AskUserResult, AskUserHandler, AskUserSimpleInput, AskUserSimpleResult, AskUserSimpleHandler, } from '@compilr-dev/sdk';
|
|
40
10
|
/**
|
|
41
11
|
* Register the ask_user handler. Called during app initialization.
|
|
42
12
|
*/
|
|
@@ -1,19 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Ask User Simple Tool
|
|
2
|
+
* Ask User Simple Tool — CLI wrapper around SDK factory
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* models like Haiku, Flash, and GPT-4o-mini to generate correctly.
|
|
7
|
-
*
|
|
8
|
-
* Used by /sketch command for quick project outlines.
|
|
4
|
+
* Uses getAskUserSimpleHandler() from shared-handlers.ts which coordinates
|
|
5
|
+
* with the terminal footer (pause/resume) and shows the overlay.
|
|
9
6
|
*/
|
|
10
|
-
|
|
11
|
-
/** The question text */
|
|
12
|
-
question: string;
|
|
13
|
-
/** Predefined options (optional, max 5) */
|
|
14
|
-
options?: string[];
|
|
15
|
-
/** Allow free-text input (default: true) */
|
|
16
|
-
allowCustom?: boolean;
|
|
17
|
-
}
|
|
7
|
+
import { type AskUserSimpleInput } from '@compilr-dev/sdk';
|
|
18
8
|
export declare const askUserSimpleTool: import("@compilr-dev/sdk").Tool<AskUserSimpleInput>;
|
|
19
|
-
export {};
|
|
@@ -1,87 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Ask User Simple Tool
|
|
2
|
+
* Ask User Simple Tool — CLI wrapper around SDK factory
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* models like Haiku, Flash, and GPT-4o-mini to generate correctly.
|
|
7
|
-
*
|
|
8
|
-
* Used by /sketch command for quick project outlines.
|
|
4
|
+
* Uses getAskUserSimpleHandler() from shared-handlers.ts which coordinates
|
|
5
|
+
* with the terminal footer (pause/resume) and shows the overlay.
|
|
9
6
|
*/
|
|
10
|
-
import {
|
|
7
|
+
import { createAskUserSimpleTool } from '@compilr-dev/sdk';
|
|
11
8
|
import { getAskUserSimpleHandler } from '../shared-handlers.js';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
'Provide optional predefined choices or allow free-text input. ' +
|
|
19
|
-
'Use this for simple question flows - one question at a time. ' +
|
|
20
|
-
'Best suited for /sketch command and smaller models.',
|
|
21
|
-
inputSchema: {
|
|
22
|
-
type: 'object',
|
|
23
|
-
properties: {
|
|
24
|
-
question: {
|
|
25
|
-
type: 'string',
|
|
26
|
-
description: 'The question to ask the user',
|
|
27
|
-
},
|
|
28
|
-
options: {
|
|
29
|
-
type: 'array',
|
|
30
|
-
description: 'Predefined options for the user to choose from (max 5)',
|
|
31
|
-
items: { type: 'string' },
|
|
32
|
-
maxItems: 5,
|
|
33
|
-
},
|
|
34
|
-
allowCustom: {
|
|
35
|
-
type: 'boolean',
|
|
36
|
-
description: 'Allow free-text input in addition to options (default: true)',
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
required: ['question'],
|
|
40
|
-
},
|
|
41
|
-
execute: async (input) => {
|
|
42
|
-
try {
|
|
43
|
-
// Validate input
|
|
44
|
-
if (!input.question || input.question.trim().length === 0) {
|
|
45
|
-
return {
|
|
46
|
-
success: false,
|
|
47
|
-
error: 'Question text is required',
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
if (input.options && input.options.length > 5) {
|
|
51
|
-
return {
|
|
52
|
-
success: false,
|
|
53
|
-
error: 'Maximum 5 options allowed',
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
// Get the handler from shared-handlers
|
|
57
|
-
const askUserSimpleHandler = getAskUserSimpleHandler();
|
|
58
|
-
if (!askUserSimpleHandler) {
|
|
59
|
-
return {
|
|
60
|
-
success: false,
|
|
61
|
-
error: 'ask_user_simple handler not initialized. This tool requires the CLI context.',
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
// Show the overlay via the handler (which pauses footer)
|
|
65
|
-
const result = await askUserSimpleHandler({
|
|
66
|
-
question: input.question,
|
|
67
|
-
options: input.options,
|
|
68
|
-
allowCustom: input.allowCustom,
|
|
69
|
-
});
|
|
70
|
-
const output = {
|
|
71
|
-
answer: result.answer,
|
|
72
|
-
skipped: result.skipped,
|
|
73
|
-
};
|
|
74
|
-
return {
|
|
75
|
-
success: true,
|
|
76
|
-
result: output,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
catch (err) {
|
|
80
|
-
return {
|
|
81
|
-
success: false,
|
|
82
|
-
error: `Failed to ask user: ${err instanceof Error ? err.message : String(err)}`,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
silent: true,
|
|
9
|
+
export const askUserSimpleTool = createAskUserSimpleTool(async (input) => {
|
|
10
|
+
const handler = getAskUserSimpleHandler();
|
|
11
|
+
if (!handler) {
|
|
12
|
+
throw new Error('ask_user_simple handler not initialized. This tool requires the CLI context.');
|
|
13
|
+
}
|
|
14
|
+
return handler(input);
|
|
87
15
|
});
|