@compilr-dev/cli 0.5.2 → 0.5.3
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.js +8 -6
- package/dist/commands-v2/handlers/core.js +26 -1
- package/dist/commands-v2/handlers/project.js +36 -3
- package/dist/commands-v2/handlers/reset.js +19 -6
- package/dist/commands-v2/handlers/session.d.ts +5 -1
- package/dist/commands-v2/handlers/session.js +54 -16
- package/dist/commands-v2/types.d.ts +5 -0
- package/dist/compilr-diff-companion.vsix +0 -0
- package/dist/index.js +99 -30
- package/dist/models/providers.d.ts +3 -1
- package/dist/models/providers.js +9 -0
- package/dist/repl-v2.d.ts +12 -0
- package/dist/repl-v2.js +11 -6
- package/dist/tool-names.d.ts +4 -0
- package/dist/tool-names.js +24 -0
- package/dist/tools.d.ts +14 -4
- package/dist/tools.js +57 -19
- package/dist/ui/terminal-ui.d.ts +7 -7
- package/dist/ui/terminal-ui.js +1 -1
- package/dist/ui/turn-metrics.d.ts +10 -10
- package/dist/ui/turn-metrics.js +5 -5
- package/dist/ui/types.d.ts +4 -4
- package/package.json +5 -5
|
@@ -356,7 +356,7 @@ export async function loadAndRestoreSession(projectId, agent, mode = 'auto') {
|
|
|
356
356
|
* @param teamOptions - Optional team switching options
|
|
357
357
|
* @returns Object with switch info, or null if no switch occurred
|
|
358
358
|
*/
|
|
359
|
-
export async function handleProjectSwitch(oldProjectId, agent, teamOptions) {
|
|
359
|
+
export async function handleProjectSwitch(oldProjectId, agent, teamOptions, agentOptions) {
|
|
360
360
|
const newProject = getCurrentProject();
|
|
361
361
|
const newProjectId = newProject?.id ?? null;
|
|
362
362
|
// No switch occurred
|
|
@@ -427,14 +427,24 @@ export async function handleProjectSwitch(oldProjectId, agent, teamOptions) {
|
|
|
427
427
|
messageCount = messages.length;
|
|
428
428
|
}
|
|
429
429
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
430
|
+
}
|
|
431
|
+
catch {
|
|
432
|
+
// Context refresh is best-effort
|
|
433
|
+
}
|
|
434
|
+
// Recreate default agent if agentOptions provided — the new agent gets
|
|
435
|
+
// the fresh system prompt (project name, COMPILR.md, guided context).
|
|
436
|
+
let newAgent;
|
|
437
|
+
if (agentOptions) {
|
|
438
|
+
try {
|
|
439
|
+
// 1. Update liveProjectState in index.ts so agentFactory reads fresh values
|
|
440
|
+
await agentOptions.updateProjectState?.(newProjectId);
|
|
441
|
+
// 2. Create fresh default agent with new project's system prompt
|
|
442
|
+
newAgent = await agentOptions.agentFactory({});
|
|
443
|
+
// 3. Transfer anchors to the NEW agent
|
|
444
|
+
newAgent.clearAnchors({ scope: 'persistent' });
|
|
435
445
|
const newAnchors = await getProjectAnchors(newProjectId);
|
|
436
446
|
for (const anchor of newAnchors) {
|
|
437
|
-
|
|
447
|
+
newAgent.addAnchor({
|
|
438
448
|
id: anchor.id,
|
|
439
449
|
content: anchor.content,
|
|
440
450
|
priority: anchor.priority,
|
|
@@ -442,18 +452,45 @@ export async function handleProjectSwitch(oldProjectId, agent, teamOptions) {
|
|
|
442
452
|
tags: anchor.tags,
|
|
443
453
|
});
|
|
444
454
|
}
|
|
455
|
+
// 4. Set history on the NEW agent (not the old one)
|
|
456
|
+
if (messages.length > 0) {
|
|
457
|
+
await newAgent.setHistory(messages, { turnCount: messageCount });
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
catch {
|
|
461
|
+
// If agent recreation fails, fall back to updating the old agent
|
|
462
|
+
newAgent = undefined;
|
|
445
463
|
}
|
|
446
464
|
}
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
465
|
+
// If no new agent was created, update the old agent as before
|
|
466
|
+
if (!newAgent) {
|
|
467
|
+
try {
|
|
468
|
+
// Update old agent's anchors
|
|
469
|
+
if (agent?.clearAnchors && agent.addAnchor) {
|
|
470
|
+
agent.clearAnchors({ scope: 'persistent' });
|
|
471
|
+
const newAnchors = await getProjectAnchors(newProjectId);
|
|
472
|
+
for (const anchor of newAnchors) {
|
|
473
|
+
agent.addAnchor({
|
|
474
|
+
id: anchor.id,
|
|
475
|
+
content: anchor.content,
|
|
476
|
+
priority: anchor.priority,
|
|
477
|
+
scope: anchor.scope,
|
|
478
|
+
tags: anchor.tags,
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
}
|
|
454
482
|
}
|
|
455
|
-
|
|
456
|
-
|
|
483
|
+
catch {
|
|
484
|
+
// Context refresh is best-effort
|
|
485
|
+
}
|
|
486
|
+
// Set the updated history on the old agent
|
|
487
|
+
if (agent) {
|
|
488
|
+
if (messages.length > 0) {
|
|
489
|
+
await agent.setHistory(messages, { turnCount: messageCount });
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
agent.clearHistory();
|
|
493
|
+
}
|
|
457
494
|
}
|
|
458
495
|
}
|
|
459
496
|
// Handle team switching if team options provided
|
|
@@ -496,6 +533,7 @@ export async function handleProjectSwitch(oldProjectId, agent, teamOptions) {
|
|
|
496
533
|
contextRefreshed,
|
|
497
534
|
contextMessage,
|
|
498
535
|
newTeam,
|
|
536
|
+
newAgent,
|
|
499
537
|
};
|
|
500
538
|
}
|
|
501
539
|
/**
|
|
@@ -43,6 +43,11 @@ export interface CommandContextV2 {
|
|
|
43
43
|
* Used when switching projects to create new team.
|
|
44
44
|
*/
|
|
45
45
|
agentFactory?: (config: Record<string, unknown>, systemPromptAddition?: string, useMinimalSystemPrompt?: boolean, noTools?: boolean) => Promise<Agent>;
|
|
46
|
+
/**
|
|
47
|
+
* Update live project state so agentFactory creates agents with fresh context.
|
|
48
|
+
* Called during project switch before recreating the default agent.
|
|
49
|
+
*/
|
|
50
|
+
updateProjectState?: (projectId: number | null) => Promise<void>;
|
|
46
51
|
/**
|
|
47
52
|
* Replace the current agent with a restored one.
|
|
48
53
|
* Used by /resume command to restore from a saved session.
|
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ process.env.FORCE_COLOR = '3';
|
|
|
11
11
|
import { perf, flushStartupPerf } from './utils/startup-perf.js';
|
|
12
12
|
perf('imports-start');
|
|
13
13
|
import { createAgent } from './agent.js';
|
|
14
|
-
import { getModelForTier } from './models/index.js';
|
|
14
|
+
import { getModelForTier, getProviderMetadata } from './models/index.js';
|
|
15
15
|
import { ReplV2 } from './repl-v2.js';
|
|
16
16
|
import { AgentTeam, setActiveSharedContext } from './multi-agent/index.js';
|
|
17
17
|
import { getStyles } from './themes/index.js';
|
|
@@ -320,34 +320,48 @@ async function main() {
|
|
|
320
320
|
}
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
|
+
// ==========================================================================
|
|
324
|
+
// Mutable project state — closures read these live so agentFactory
|
|
325
|
+
// always sees the current project context (not stale startup values).
|
|
326
|
+
// ==========================================================================
|
|
327
|
+
const liveProjectState = {
|
|
328
|
+
dbProject: null,
|
|
329
|
+
projectContext: undefined,
|
|
330
|
+
guidedModeContext: undefined,
|
|
331
|
+
};
|
|
323
332
|
// Load project memory (COMPILR.md or CLAUDE.md)
|
|
324
333
|
perf('project-memory-start');
|
|
325
334
|
const projectMemory = loadProjectMemory();
|
|
326
|
-
let projectContext;
|
|
327
335
|
if (projectMemory.found && projectMemory.filePath) {
|
|
328
|
-
projectContext = projectMemory.content;
|
|
336
|
+
liveProjectState.projectContext = projectMemory.content;
|
|
329
337
|
}
|
|
330
338
|
// ==========================================================================
|
|
331
339
|
// Load guided mode context from database (if project uses guided mode)
|
|
332
340
|
// ==========================================================================
|
|
333
341
|
perf('project-db-start');
|
|
334
|
-
let guidedModeContext;
|
|
335
342
|
// Determine which project to load based on projectStartup setting
|
|
336
343
|
const projectStartupMode = getProjectStartupMode();
|
|
337
|
-
let dbProject = null;
|
|
338
344
|
if (projectStartupMode === 'last') {
|
|
339
345
|
// Try to load the last opened project
|
|
340
346
|
const lastProjectId = getLastProjectId();
|
|
341
347
|
if (lastProjectId !== null) {
|
|
342
|
-
dbProject = projectRepository.getById(lastProjectId);
|
|
348
|
+
liveProjectState.dbProject = projectRepository.getById(lastProjectId);
|
|
343
349
|
// If last project no longer exists (deleted), don't auto-load any project
|
|
344
350
|
}
|
|
345
351
|
// If no lastProjectId remembered, don't auto-load any project
|
|
346
352
|
}
|
|
347
353
|
// else projectStartupMode === 'off': don't auto-load any project
|
|
348
|
-
if (dbProject) {
|
|
354
|
+
if (liveProjectState.dbProject) {
|
|
355
|
+
const dbProject = liveProjectState.dbProject;
|
|
349
356
|
// Set as active project for tools to use
|
|
350
357
|
setActiveProject({ id: dbProject.id, name: dbProject.name, displayName: dbProject.displayName, path: dbProject.path });
|
|
358
|
+
// Reload project memory from the DB project's path (not CWD)
|
|
359
|
+
// The initial loadProjectMemory() above uses process.cwd() which may
|
|
360
|
+
// load the wrong COMPILR.md/CLAUDE.md (e.g., workspace-level instead of project-specific)
|
|
361
|
+
if (dbProject.path) {
|
|
362
|
+
const memory = loadProjectMemory({ cwd: dbProject.path });
|
|
363
|
+
liveProjectState.projectContext = memory.found ? memory.content : undefined;
|
|
364
|
+
}
|
|
351
365
|
// If in guided mode, generate context
|
|
352
366
|
if (shouldInjectGuidedContext(dbProject)) {
|
|
353
367
|
// Get work item counts
|
|
@@ -376,7 +390,7 @@ async function main() {
|
|
|
376
390
|
inProgressCount: statusCounts.in_progress,
|
|
377
391
|
completedCount: statusCounts.completed,
|
|
378
392
|
};
|
|
379
|
-
guidedModeContext = getFullGuidedPrompt(contextOptions);
|
|
393
|
+
liveProjectState.guidedModeContext = getFullGuidedPrompt(contextOptions);
|
|
380
394
|
}
|
|
381
395
|
}
|
|
382
396
|
// ==========================================================================
|
|
@@ -386,8 +400,8 @@ async function main() {
|
|
|
386
400
|
// Load global anchors (always)
|
|
387
401
|
const globalAnchors = getGlobalAnchorManager().getAll({ scope: 'persistent' });
|
|
388
402
|
// Load project-specific anchors (if in a tracked project)
|
|
389
|
-
const projectAnchors = dbProject
|
|
390
|
-
? getAnchorManager(String(dbProject.id)).getAll({ scope: 'persistent' })
|
|
403
|
+
const projectAnchors = liveProjectState.dbProject
|
|
404
|
+
? getAnchorManager(String(liveProjectState.dbProject.id)).getAll({ scope: 'persistent' })
|
|
391
405
|
: [];
|
|
392
406
|
// Combine into persistedAnchors array for agent
|
|
393
407
|
const persistedAnchors = [
|
|
@@ -404,7 +418,7 @@ async function main() {
|
|
|
404
418
|
priority: a.priority,
|
|
405
419
|
scope: a.scope,
|
|
406
420
|
tags: a.tags,
|
|
407
|
-
projectId: String(dbProject?.id),
|
|
421
|
+
projectId: String(liveProjectState.dbProject?.id),
|
|
408
422
|
})),
|
|
409
423
|
];
|
|
410
424
|
// ==========================================================================
|
|
@@ -463,8 +477,8 @@ async function main() {
|
|
|
463
477
|
// ==========================================================================
|
|
464
478
|
perf('mcp-init-fire');
|
|
465
479
|
// Check if there are MCP servers to connect — fire the promise but don't await yet
|
|
466
|
-
const mcpServerCount = loadMCPConfig(dbProject?.path).length;
|
|
467
|
-
const mcpInitPromise = mcpServerCount > 0 ? initializeMCP(dbProject?.path) : null;
|
|
480
|
+
const mcpServerCount = loadMCPConfig(liveProjectState.dbProject?.path).length;
|
|
481
|
+
const mcpInitPromise = mcpServerCount > 0 ? initializeMCP(liveProjectState.dbProject?.path) : null;
|
|
468
482
|
// Mutable ref for MCP tools — read by team agent factory when creating new agents.
|
|
469
483
|
// Updated when background MCP init completes.
|
|
470
484
|
let mcpToolsRef = [];
|
|
@@ -472,9 +486,10 @@ async function main() {
|
|
|
472
486
|
// Episode Recorder Setup (work history tracking)
|
|
473
487
|
// ==========================================================================
|
|
474
488
|
const createEpisodeRecorder = (agentId) => {
|
|
475
|
-
if (!dbProject)
|
|
489
|
+
if (!liveProjectState.dbProject)
|
|
476
490
|
return undefined;
|
|
477
|
-
const
|
|
491
|
+
const projectId = liveProjectState.dbProject.id;
|
|
492
|
+
const episodesPath = path.join(getSessionsPath(), `project-${String(projectId)}`, 'episodes.json');
|
|
478
493
|
const store = new FileEpisodeStore({ filePath: episodesPath });
|
|
479
494
|
// Set global store for recall_work tool access
|
|
480
495
|
setGlobalEpisodeStore(store);
|
|
@@ -486,7 +501,7 @@ async function main() {
|
|
|
486
501
|
onBatchFlushed: () => {
|
|
487
502
|
updateWorkSummaryAnchor({
|
|
488
503
|
store,
|
|
489
|
-
projectId: String(
|
|
504
|
+
projectId: String(projectId),
|
|
490
505
|
getAnchorManager,
|
|
491
506
|
});
|
|
492
507
|
},
|
|
@@ -500,16 +515,16 @@ async function main() {
|
|
|
500
515
|
model,
|
|
501
516
|
minimal: options.minimal,
|
|
502
517
|
quiet: true,
|
|
503
|
-
enableMetaTools: !options.minimal
|
|
518
|
+
enableMetaTools: !options.minimal && getProviderMetadata(provider).supportsMetaTools,
|
|
504
519
|
onPermissionRequest,
|
|
505
520
|
onIterationLimitReached,
|
|
506
521
|
onSuggest: (event) => {
|
|
507
522
|
// Store suggestion to be applied after agent finishes
|
|
508
523
|
sharedState.pendingSuggestion = event.action;
|
|
509
524
|
},
|
|
510
|
-
projectName: dbProject?.displayName,
|
|
511
|
-
projectContext,
|
|
512
|
-
guidedModeContext,
|
|
525
|
+
projectName: liveProjectState.dbProject?.displayName,
|
|
526
|
+
projectContext: liveProjectState.projectContext,
|
|
527
|
+
guidedModeContext: liveProjectState.guidedModeContext,
|
|
513
528
|
// Anchors - library handles re-injection on every LLM call
|
|
514
529
|
enableAnchors: true,
|
|
515
530
|
persistedAnchors: persistedAnchors.length > 0 ? persistedAnchors : undefined,
|
|
@@ -537,9 +552,11 @@ async function main() {
|
|
|
537
552
|
episodeRecorder: defaultEpisodeRecorder,
|
|
538
553
|
});
|
|
539
554
|
perf('create-agent-done');
|
|
555
|
+
// Mutable ref so grantSession and onDefaultAgentSwapped closures track the current default agent
|
|
556
|
+
let defaultAgentRef = agent;
|
|
540
557
|
// Bind grantSession for the permission handler to use
|
|
541
558
|
sharedState.grantSession = (toolName) => {
|
|
542
|
-
|
|
559
|
+
defaultAgentRef.grantSessionPermission(toolName);
|
|
543
560
|
};
|
|
544
561
|
// ==========================================================================
|
|
545
562
|
// Create AgentTeam with the default agent (or restore from persistence)
|
|
@@ -554,15 +571,15 @@ async function main() {
|
|
|
554
571
|
provider,
|
|
555
572
|
model: agentModel,
|
|
556
573
|
minimal: options.minimal,
|
|
557
|
-
enableMetaTools: !options.minimal && !noTools
|
|
574
|
+
enableMetaTools: !options.minimal && !noTools && getProviderMetadata(provider).supportsMetaTools,
|
|
558
575
|
onPermissionRequest,
|
|
559
576
|
onIterationLimitReached,
|
|
560
577
|
onSuggest: (event) => {
|
|
561
578
|
sharedState.pendingSuggestion = event.action;
|
|
562
579
|
},
|
|
563
|
-
projectName: dbProject?.displayName,
|
|
564
|
-
projectContext,
|
|
565
|
-
guidedModeContext,
|
|
580
|
+
projectName: liveProjectState.dbProject?.displayName,
|
|
581
|
+
projectContext: liveProjectState.projectContext,
|
|
582
|
+
guidedModeContext: liveProjectState.guidedModeContext,
|
|
566
583
|
enableAnchors: true,
|
|
567
584
|
persistedAnchors: persistedAnchors.length > 0 ? persistedAnchors : undefined,
|
|
568
585
|
enableGuardrails: true,
|
|
@@ -605,11 +622,11 @@ async function main() {
|
|
|
605
622
|
// Set the active shared context for activity recording
|
|
606
623
|
setActiveSharedContext(team.sharedContext);
|
|
607
624
|
// Populate shared context with actual project info so agents know the project name
|
|
608
|
-
if (dbProject) {
|
|
625
|
+
if (liveProjectState.dbProject) {
|
|
609
626
|
team.sharedContext.setProject({
|
|
610
|
-
id: dbProject.id,
|
|
611
|
-
name: dbProject.displayName,
|
|
612
|
-
path: dbProject.path,
|
|
627
|
+
id: liveProjectState.dbProject.id,
|
|
628
|
+
name: liveProjectState.dbProject.displayName,
|
|
629
|
+
path: liveProjectState.dbProject.path,
|
|
613
630
|
});
|
|
614
631
|
}
|
|
615
632
|
// ==========================================================================
|
|
@@ -636,7 +653,7 @@ async function main() {
|
|
|
636
653
|
provider,
|
|
637
654
|
version: VERSION,
|
|
638
655
|
updateAvailable,
|
|
639
|
-
projectName: dbProject?.displayName ?? process.cwd().split('/').pop(),
|
|
656
|
+
projectName: liveProjectState.dbProject?.displayName ?? process.cwd().split('/').pop(),
|
|
640
657
|
// Set up V2 permission overlay callback when UI is ready
|
|
641
658
|
onUIReady: (showOverlay) => {
|
|
642
659
|
sharedState.showPermissionOverlayV2 = showOverlay;
|
|
@@ -705,6 +722,58 @@ async function main() {
|
|
|
705
722
|
onTeamReplaced: (newTeam) => {
|
|
706
723
|
sharedState.team = newTeam;
|
|
707
724
|
},
|
|
725
|
+
// Recreate default agent on project switch — updates liveProjectState
|
|
726
|
+
// so agentFactory reads fresh project context for the new agent.
|
|
727
|
+
onProjectStateUpdate: (projectId) => {
|
|
728
|
+
if (projectId !== null) {
|
|
729
|
+
liveProjectState.dbProject = projectRepository.getById(projectId);
|
|
730
|
+
if (liveProjectState.dbProject?.path) {
|
|
731
|
+
const memory = loadProjectMemory({ cwd: liveProjectState.dbProject.path });
|
|
732
|
+
liveProjectState.projectContext = memory.found ? memory.content : undefined;
|
|
733
|
+
}
|
|
734
|
+
else {
|
|
735
|
+
liveProjectState.projectContext = undefined;
|
|
736
|
+
}
|
|
737
|
+
if (liveProjectState.dbProject && shouldInjectGuidedContext(liveProjectState.dbProject)) {
|
|
738
|
+
const statusCounts = workItemRepository.getStatusCounts(liveProjectState.dbProject.id);
|
|
739
|
+
let currentItem = null;
|
|
740
|
+
if (liveProjectState.dbProject.currentItemId) {
|
|
741
|
+
currentItem = workItemRepository.getByItemId(liveProjectState.dbProject.id, liveProjectState.dbProject.currentItemId);
|
|
742
|
+
}
|
|
743
|
+
else {
|
|
744
|
+
const inProgressItems = workItemRepository.query({
|
|
745
|
+
project_id: liveProjectState.dbProject.id,
|
|
746
|
+
status: 'in_progress',
|
|
747
|
+
limit: 1,
|
|
748
|
+
});
|
|
749
|
+
if (inProgressItems.items.length > 0) {
|
|
750
|
+
currentItem = inProgressItems.items[0];
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
const contextOptions = {
|
|
754
|
+
project: liveProjectState.dbProject,
|
|
755
|
+
currentItem,
|
|
756
|
+
backlogCount: statusCounts.backlog,
|
|
757
|
+
inProgressCount: statusCounts.in_progress,
|
|
758
|
+
completedCount: statusCounts.completed,
|
|
759
|
+
};
|
|
760
|
+
liveProjectState.guidedModeContext = getFullGuidedPrompt(contextOptions);
|
|
761
|
+
}
|
|
762
|
+
else {
|
|
763
|
+
liveProjectState.guidedModeContext = undefined;
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
liveProjectState.dbProject = null;
|
|
768
|
+
liveProjectState.projectContext = undefined;
|
|
769
|
+
liveProjectState.guidedModeContext = undefined;
|
|
770
|
+
}
|
|
771
|
+
return Promise.resolve();
|
|
772
|
+
},
|
|
773
|
+
// Keep defaultAgentRef in sync when project switch creates a new default agent
|
|
774
|
+
onDefaultAgentSwapped: (newAgent) => {
|
|
775
|
+
defaultAgentRef = newAgent;
|
|
776
|
+
},
|
|
708
777
|
// Set session prefix for VS Code diff IPC after session registration
|
|
709
778
|
onSessionRegistered: (sessionId) => {
|
|
710
779
|
sharedState.sessionPrefix = sessionId.slice(0, 8);
|
|
@@ -9,11 +9,13 @@ import type { ProviderKey } from '../utils/credentials.js';
|
|
|
9
9
|
import { type ProviderMetadata as SdkProviderMetadata } from '@compilr-dev/sdk';
|
|
10
10
|
export { type OthersProviderModel, TOGETHER_MODELS, GROQ_MODELS, FIREWORKS_MODELS, PERPLEXITY_MODELS, OPENROUTER_MODELS, getModelsForOthersProvider, } from '@compilr-dev/sdk';
|
|
11
11
|
/**
|
|
12
|
-
* CLI-extended provider metadata — adds credentialKey
|
|
12
|
+
* CLI-extended provider metadata — adds credentialKey and capability flags.
|
|
13
13
|
*/
|
|
14
14
|
export interface ProviderMetadata extends SdkProviderMetadata {
|
|
15
15
|
/** Credential key for API key storage (CLI-specific) */
|
|
16
16
|
credentialKey: ProviderKey;
|
|
17
|
+
/** Whether this provider handles the meta-tools indirection pattern well */
|
|
18
|
+
supportsMetaTools: boolean;
|
|
17
19
|
}
|
|
18
20
|
/**
|
|
19
21
|
* CLI-extended provider metadata registry.
|
package/dist/models/providers.js
CHANGED
|
@@ -22,6 +22,14 @@ const CREDENTIAL_KEYS = {
|
|
|
22
22
|
openrouter: 'openrouter',
|
|
23
23
|
custom: 'openai', // Custom uses openai-compatible format by default
|
|
24
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Meta-tools capability: which providers handle the indirection pattern well.
|
|
27
|
+
* When false, all tools are registered directly (higher token cost, but reliable).
|
|
28
|
+
*/
|
|
29
|
+
const SUPPORTS_META_TOOLS = {
|
|
30
|
+
claude: true,
|
|
31
|
+
gemini: true,
|
|
32
|
+
};
|
|
25
33
|
/**
|
|
26
34
|
* CLI-extended provider metadata registry.
|
|
27
35
|
* Merges SDK metadata with CLI credential keys.
|
|
@@ -33,6 +41,7 @@ export const PROVIDER_METADATA = (() => {
|
|
|
33
41
|
result[providerType] = {
|
|
34
42
|
...sdkMeta,
|
|
35
43
|
credentialKey: CREDENTIAL_KEYS[providerType],
|
|
44
|
+
supportsMetaTools: SUPPORTS_META_TOOLS[providerType] ?? false,
|
|
36
45
|
};
|
|
37
46
|
}
|
|
38
47
|
return result;
|
package/dist/repl-v2.d.ts
CHANGED
|
@@ -160,6 +160,16 @@ export interface ReplV2Options {
|
|
|
160
160
|
* see the restored team (with all agents) instead of the initial one.
|
|
161
161
|
*/
|
|
162
162
|
onTeamReplaced?: (newTeam: AgentTeam) => void;
|
|
163
|
+
/**
|
|
164
|
+
* Callback to update live project state in index.ts before recreating the default agent.
|
|
165
|
+
* Updates liveProjectState (COMPILR.md, guided context) so agentFactory sees fresh values.
|
|
166
|
+
*/
|
|
167
|
+
onProjectStateUpdate?: (projectId: number | null) => Promise<void>;
|
|
168
|
+
/**
|
|
169
|
+
* Callback invoked after the default agent is swapped on project switch.
|
|
170
|
+
* Allows index.ts to update defaultAgentRef for grantSession.
|
|
171
|
+
*/
|
|
172
|
+
onDefaultAgentSwapped?: (newAgent: Agent) => void;
|
|
163
173
|
}
|
|
164
174
|
/**
|
|
165
175
|
* Options for switchAgent().
|
|
@@ -220,6 +230,8 @@ export declare class ReplV2 {
|
|
|
220
230
|
private readonly onBackgroundDelegationReady?;
|
|
221
231
|
private readonly onSessionRegistered?;
|
|
222
232
|
private readonly onTeamReplaced?;
|
|
233
|
+
private readonly onProjectStateUpdate?;
|
|
234
|
+
private readonly onDefaultAgentSwapped?;
|
|
223
235
|
private readonly authOnly;
|
|
224
236
|
private restoredSessionInfo;
|
|
225
237
|
private currentExecutingBackgroundAgentId;
|
package/dist/repl-v2.js
CHANGED
|
@@ -197,6 +197,8 @@ export class ReplV2 {
|
|
|
197
197
|
onBackgroundDelegationReady;
|
|
198
198
|
onSessionRegistered;
|
|
199
199
|
onTeamReplaced;
|
|
200
|
+
onProjectStateUpdate;
|
|
201
|
+
onDefaultAgentSwapped;
|
|
200
202
|
authOnly;
|
|
201
203
|
restoredSessionInfo = null;
|
|
202
204
|
// Phase 3b: Track which background agent is currently executing (for permission routing)
|
|
@@ -242,6 +244,8 @@ export class ReplV2 {
|
|
|
242
244
|
this.onBackgroundDelegationReady = options.onBackgroundDelegationReady;
|
|
243
245
|
this.onSessionRegistered = options.onSessionRegistered;
|
|
244
246
|
this.onTeamReplaced = options.onTeamReplaced;
|
|
247
|
+
this.onProjectStateUpdate = options.onProjectStateUpdate;
|
|
248
|
+
this.onDefaultAgentSwapped = options.onDefaultAgentSwapped;
|
|
245
249
|
this.authOnly = options.authOnly ?? false;
|
|
246
250
|
}
|
|
247
251
|
/**
|
|
@@ -734,6 +738,7 @@ export class ReplV2 {
|
|
|
734
738
|
*/
|
|
735
739
|
restoreAgent(newAgent) {
|
|
736
740
|
this.agent = newAgent;
|
|
741
|
+
this.onDefaultAgentSwapped?.(newAgent);
|
|
737
742
|
}
|
|
738
743
|
/**
|
|
739
744
|
* Get the current agent instance.
|
|
@@ -1667,6 +1672,7 @@ export class ReplV2 {
|
|
|
1667
1672
|
agent: this.agent,
|
|
1668
1673
|
team: this.team,
|
|
1669
1674
|
agentFactory: this.agentFactory,
|
|
1675
|
+
updateProjectState: this.onProjectStateUpdate,
|
|
1670
1676
|
setTeam: (newTeam) => {
|
|
1671
1677
|
const oldTeam = this.team;
|
|
1672
1678
|
this.team = newTeam;
|
|
@@ -3245,13 +3251,12 @@ export class ReplV2 {
|
|
|
3245
3251
|
if (metrics.toolCalls > 0) {
|
|
3246
3252
|
parts.push(`${String(metrics.toolCalls)} tool${metrics.toolCalls > 1 ? 's' : ''}`);
|
|
3247
3253
|
}
|
|
3248
|
-
// DEBUG: Show payload debug info (
|
|
3254
|
+
// DEBUG: Show payload debug info (token estimates sent to provider)
|
|
3249
3255
|
if (metrics.debugPayload) {
|
|
3250
|
-
const {
|
|
3251
|
-
const
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
parts.push(`[dbg ${String(metrics.apiCalls)}calls sent:${formatTokens(totalChars)} (~${formatTokens(estTokens)} est) sys:${formatTokens(systemChars)} cont:${formatTokens(contentsChars)} tools:${formatTokens(toolsChars)}]`);
|
|
3256
|
+
const { systemTokens, contentsTokens, toolsTokens } = metrics.debugPayload;
|
|
3257
|
+
const totalTokens = systemTokens + contentsTokens + toolsTokens;
|
|
3258
|
+
// Format: [dbg 2calls sent:31k sys:10k cont:8k tools:13k]
|
|
3259
|
+
parts.push(`[dbg ${String(metrics.apiCalls)}calls sent:${formatTokens(totalTokens)} sys:${formatTokens(systemTokens)} cont:${formatTokens(contentsTokens)} tools:${formatTokens(toolsTokens)}]`);
|
|
3255
3260
|
}
|
|
3256
3261
|
// Print as muted info line
|
|
3257
3262
|
this.ui.print({ type: 'turn-summary', parts });
|
package/dist/tool-names.d.ts
CHANGED
|
@@ -102,6 +102,10 @@ export declare const TOOL_NAMES: {
|
|
|
102
102
|
export type ToolName = (typeof TOOL_NAMES)[keyof typeof TOOL_NAMES];
|
|
103
103
|
/** Array of all direct tool names (always available) */
|
|
104
104
|
export declare const DIRECT_TOOL_NAMES: readonly ToolName[];
|
|
105
|
+
/** Hot tools — used in >50% of turns, always declared as direct schemas */
|
|
106
|
+
export declare const HOT_TOOL_NAMES: readonly ToolName[];
|
|
107
|
+
/** Warm tools — used occasionally, moved to meta-registry in hot-tools mode */
|
|
108
|
+
export declare const WARM_TOOL_NAMES: readonly ToolName[];
|
|
105
109
|
/** Array of all meta-tool names (tool discovery) */
|
|
106
110
|
export declare const META_TOOL_NAMES: readonly ToolName[];
|
|
107
111
|
/** Array of all meta-registry tool names (accessed via use_tool) */
|
package/dist/tool-names.js
CHANGED
|
@@ -142,6 +142,30 @@ export const DIRECT_TOOL_NAMES = [
|
|
|
142
142
|
TOOL_NAMES.TASK,
|
|
143
143
|
TOOL_NAMES.SUGGEST,
|
|
144
144
|
];
|
|
145
|
+
/** Hot tools — used in >50% of turns, always declared as direct schemas */
|
|
146
|
+
export const HOT_TOOL_NAMES = [
|
|
147
|
+
TOOL_NAMES.READ_FILE,
|
|
148
|
+
TOOL_NAMES.WRITE_FILE,
|
|
149
|
+
TOOL_NAMES.EDIT,
|
|
150
|
+
TOOL_NAMES.BASH,
|
|
151
|
+
TOOL_NAMES.GREP,
|
|
152
|
+
TOOL_NAMES.GLOB,
|
|
153
|
+
TOOL_NAMES.ASK_USER,
|
|
154
|
+
];
|
|
155
|
+
/** Warm tools — used occasionally, moved to meta-registry in hot-tools mode */
|
|
156
|
+
export const WARM_TOOL_NAMES = [
|
|
157
|
+
TOOL_NAMES.BASH_OUTPUT,
|
|
158
|
+
TOOL_NAMES.KILL_SHELL,
|
|
159
|
+
TOOL_NAMES.TODO_WRITE,
|
|
160
|
+
TOOL_NAMES.TODO_READ,
|
|
161
|
+
TOOL_NAMES.TODO_CLAIM,
|
|
162
|
+
TOOL_NAMES.TODO_HANDOFF,
|
|
163
|
+
TOOL_NAMES.ASK_USER_SIMPLE,
|
|
164
|
+
TOOL_NAMES.DELEGATE,
|
|
165
|
+
TOOL_NAMES.DELEGATE_BACKGROUND,
|
|
166
|
+
TOOL_NAMES.HANDOFF,
|
|
167
|
+
TOOL_NAMES.COMPILR_GUIDE,
|
|
168
|
+
];
|
|
145
169
|
/** Array of all meta-tool names (tool discovery) */
|
|
146
170
|
export const META_TOOL_NAMES = [
|
|
147
171
|
TOOL_NAMES.LIST_TOOLS,
|
package/dist/tools.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* Tool names are defined in tool-names.ts (a dependency-free module).
|
|
15
15
|
* This file re-exports them for convenience. Import from here or tool-names.ts.
|
|
16
16
|
*/
|
|
17
|
-
export { TOOL_NAMES, type ToolName, DIRECT_TOOL_NAMES, META_TOOL_NAMES, META_REGISTRY_TOOL_NAMES, getAllToolNames, } from './tool-names.js';
|
|
17
|
+
export { TOOL_NAMES, type ToolName, DIRECT_TOOL_NAMES, HOT_TOOL_NAMES, WARM_TOOL_NAMES, META_TOOL_NAMES, META_REGISTRY_TOOL_NAMES, getAllToolNames, } from './tool-names.js';
|
|
18
18
|
import { TodoStore, type Tool } from '@compilr-dev/sdk';
|
|
19
19
|
export declare const todoStore: TodoStore;
|
|
20
20
|
import { setMetaToolFilter, getRegisteredMetaTools } from './tools/meta-tools.js';
|
|
@@ -32,9 +32,10 @@ export declare function createToolRegistry(): unknown[];
|
|
|
32
32
|
export declare function createMinimalToolRegistry(): unknown[];
|
|
33
33
|
/**
|
|
34
34
|
* Get direct tools that are always available.
|
|
35
|
-
*
|
|
35
|
+
* When hotOnly is true, returns only hot tools (7 tools, ~2.1K tokens).
|
|
36
|
+
* When false/undefined, returns all direct tools (18 tools, ~5.4K tokens).
|
|
36
37
|
*/
|
|
37
|
-
export declare function getDirectTools(): Tool[];
|
|
38
|
+
export declare function getDirectTools(hotOnly?: boolean): Tool[];
|
|
38
39
|
/**
|
|
39
40
|
* Get meta-tools for agent registration.
|
|
40
41
|
* Only get_tool_info is kept as a direct tool — use_tool and list_tools
|
|
@@ -47,11 +48,18 @@ export declare function getMetaTools(): Tool[];
|
|
|
47
48
|
* checks the meta-registry and executes it transparently.
|
|
48
49
|
*/
|
|
49
50
|
export declare function createToolFallback(): (name: string, input: Record<string, unknown>) => Promise<import('@compilr-dev/sdk').ToolExecutionResult | null>;
|
|
51
|
+
/**
|
|
52
|
+
* Check if hot-tools mode is active.
|
|
53
|
+
* When true, only hot tools are declared as direct schemas; warm tools are in meta-registry.
|
|
54
|
+
*/
|
|
55
|
+
export declare function isHotToolsMode(): boolean;
|
|
50
56
|
/**
|
|
51
57
|
* Initialize the meta-tool registry with specialized tools.
|
|
58
|
+
* When includeWarmTools is true, warm tools are also added to the meta-registry
|
|
59
|
+
* (enabling hot-tools mode where only 7 core tools are declared directly).
|
|
52
60
|
* Call this once at startup.
|
|
53
61
|
*/
|
|
54
|
-
export declare function initializeMetaTools(): void;
|
|
62
|
+
export declare function initializeMetaTools(includeWarmTools?: boolean): void;
|
|
55
63
|
/**
|
|
56
64
|
* Get the tool index for the system prompt.
|
|
57
65
|
* This lists all meta-registry tools with their signatures.
|
|
@@ -71,6 +79,8 @@ export declare function isMetaToolsEnabled(): boolean;
|
|
|
71
79
|
*/
|
|
72
80
|
export declare function getToolStats(): {
|
|
73
81
|
directTools: number;
|
|
82
|
+
hotTools: number;
|
|
83
|
+
warmTools: number;
|
|
74
84
|
metaRegistryTools: number;
|
|
75
85
|
totalTools: number;
|
|
76
86
|
estimatedDirectTokens: number;
|