@compilr-dev/cli 0.5.1 → 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/LICENSE +108 -0
- package/README.md +2 -2
- 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/context.js +20 -0
- package/dist/commands-v2/handlers/core.js +26 -1
- package/dist/commands-v2/handlers/project.js +88 -12
- 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/db/repositories/document-repository.js +1 -0
- package/dist/db/schema.d.ts +1 -1
- package/dist/index.js +99 -30
- package/dist/models/providers.d.ts +3 -1
- package/dist/models/providers.js +9 -0
- package/dist/repl-helpers.js +2 -0
- package/dist/repl-v2.d.ts +12 -0
- package/dist/repl-v2.js +27 -11
- package/dist/tool-names.d.ts +9 -0
- package/dist/tool-names.js +36 -0
- package/dist/tools/db-tools.d.ts +6 -1
- package/dist/tools/db-tools.js +6 -2
- package/dist/tools/meta-tools.d.ts +1 -1
- package/dist/tools/platform-adapter.d.ts +6 -0
- package/dist/tools/platform-adapter.js +10 -0
- package/dist/tools.d.ts +14 -4
- package/dist/tools.js +60 -20
- package/dist/ui/constants/labels.js +1 -0
- package/dist/ui/overlay/impl/workflow-overlay-v2.d.ts +1 -0
- package/dist/ui/overlay/impl/workflow-overlay-v2.js +5 -3
- package/dist/ui/terminal-ui.d.ts +7 -7
- package/dist/ui/terminal-ui.js +1 -1
- package/dist/ui/tool-formatters.js +190 -6
- 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 +6 -5
- package/dist/tools/anchor-tools.d.ts +0 -31
- package/dist/tools/anchor-tools.js +0 -255
- package/dist/tools/artifact-tools.d.ts +0 -42
- package/dist/tools/artifact-tools.js +0 -328
- package/dist/tools/backlog-wrappers.d.ts +0 -56
- package/dist/tools/backlog-wrappers.js +0 -353
- package/dist/tools/document-db.d.ts +0 -43
- package/dist/tools/document-db.js +0 -220
- package/dist/tools/plan-tools.d.ts +0 -54
- package/dist/tools/plan-tools.js +0 -338
- package/dist/tools/recall-work-tool.d.ts +0 -18
- package/dist/tools/recall-work-tool.js +0 -82
- package/dist/tools/workitem-db.d.ts +0 -135
- package/dist/tools/workitem-db.js +0 -730
|
@@ -90,16 +90,29 @@ export const resetCommand = {
|
|
|
90
90
|
ctx.ui.print({ type: 'info', message: `${String(clearedCount)} queued message${clearedCount !== 1 ? 's' : ''} cleared` });
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
+
// Recreate the default agent with fresh system prompt
|
|
94
|
+
// (reset-reload reloads COMPILR.md from disk; reset-only keeps current context but still
|
|
95
|
+
// needs a fresh agent so the empty history is reflected in a clean system prompt)
|
|
96
|
+
if (ctx.agentFactory && ctx.restoreAgent) {
|
|
97
|
+
try {
|
|
98
|
+
if (result.option === 'reset-reload' && ctx.updateProjectState) {
|
|
99
|
+
// Reload project context (COMPILR.md, guided mode) from disk
|
|
100
|
+
await ctx.updateProjectState(projectId);
|
|
101
|
+
}
|
|
102
|
+
const freshAgent = await ctx.agentFactory({});
|
|
103
|
+
ctx.restoreAgent(freshAgent);
|
|
104
|
+
if (ctx.team) {
|
|
105
|
+
ctx.team.setDefaultAgent(freshAgent);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Best effort — continue with old agent (history already cleared above)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
93
112
|
if (result.option === 'reset-reload') {
|
|
94
|
-
// Reset & reload context - need to refresh project context
|
|
95
|
-
// This is handled by creating a new agent with fresh context
|
|
96
|
-
// For now, we just clear history. Full context refresh requires
|
|
97
|
-
// recreating the agent (to be implemented in Phase 2 integration)
|
|
98
113
|
ctx.ui.print({ type: 'success', message: 'Conversation cleared. Project context refreshed.' });
|
|
99
|
-
ctx.ui.print({ type: 'info', message: 'Note: Full context reload requires CLI restart for now.' });
|
|
100
114
|
}
|
|
101
115
|
else {
|
|
102
|
-
// Reset only - just clear messages
|
|
103
116
|
ctx.ui.print({ type: 'success', message: 'Conversation cleared. Context preserved.' });
|
|
104
117
|
}
|
|
105
118
|
// Save the fresh session state
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Sessions are now bound to projects - each project has its own session.
|
|
6
6
|
*/
|
|
7
7
|
import type { CommandHandlerV2 } from '../types.js';
|
|
8
|
-
import type { AgentState, SessionInfo, AnchorScope, AnchorClearOptions, AnchorPriority, Message } from '@compilr-dev/sdk';
|
|
8
|
+
import type { Agent, AgentState, SessionInfo, AnchorScope, AnchorClearOptions, AnchorPriority, Message } from '@compilr-dev/sdk';
|
|
9
9
|
import type { PrintableItem } from '../../ui/terminal-ui.js';
|
|
10
10
|
import { type ProjectSession } from '../../session/index.js';
|
|
11
11
|
import type { AgentTeam, AgentTeamConfig } from '../../multi-agent/index.js';
|
|
@@ -105,6 +105,9 @@ export declare function handleProjectSwitch(oldProjectId: number | null, agent:
|
|
|
105
105
|
team: AgentTeam | null;
|
|
106
106
|
agentFactory: AgentTeamConfig['agentFactory'];
|
|
107
107
|
onEvent?: AgentTeamConfig['onEvent'];
|
|
108
|
+
}, agentOptions?: {
|
|
109
|
+
agentFactory: AgentTeamConfig['agentFactory'];
|
|
110
|
+
updateProjectState?: (projectId: number | null) => Promise<void>;
|
|
108
111
|
}): Promise<{
|
|
109
112
|
switched: boolean;
|
|
110
113
|
oldProjectId: number | null;
|
|
@@ -115,6 +118,7 @@ export declare function handleProjectSwitch(oldProjectId: number | null, agent:
|
|
|
115
118
|
contextRefreshed: boolean;
|
|
116
119
|
contextMessage?: string;
|
|
117
120
|
newTeam?: AgentTeam;
|
|
121
|
+
newAgent?: Agent;
|
|
118
122
|
} | null>;
|
|
119
123
|
/**
|
|
120
124
|
* Get the current project ID for tracking before overlay.
|
|
@@ -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/db/schema.d.ts
CHANGED
|
@@ -83,7 +83,7 @@ export type WorkItemType = 'feature' | 'bug' | 'tech-debt' | 'chore';
|
|
|
83
83
|
export type WorkItemStatus = 'backlog' | 'in_progress' | 'completed' | 'skipped';
|
|
84
84
|
export type WorkItemPriority = 'critical' | 'high' | 'medium' | 'low';
|
|
85
85
|
export type GuidedStep = 'plan' | 'implement' | 'test' | 'commit' | 'review';
|
|
86
|
-
export type DocumentType = 'prd' | 'architecture' | 'design' | 'notes' | 'plan';
|
|
86
|
+
export type DocumentType = 'prd' | 'architecture' | 'design' | 'notes' | 'plan' | 'app-model';
|
|
87
87
|
export type PlanStatus = 'draft' | 'approved' | 'in_progress' | 'completed' | 'abandoned';
|
|
88
88
|
export type TerminalSessionStatus = 'active' | 'stale' | 'dead';
|
|
89
89
|
export interface TerminalSessionRecord {
|
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-helpers.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { builtinSkills, platformSkills } from '@compilr-dev/sdk';
|
|
9
9
|
import { codingSkills } from '@compilr-dev/agents-coding';
|
|
10
|
+
import { factorySkills } from '@compilr-dev/factory';
|
|
10
11
|
import * as fs from 'fs';
|
|
11
12
|
import * as path from 'path';
|
|
12
13
|
import { findBacklogPath, parseBacklogItems } from './tools/backlog.js';
|
|
@@ -203,6 +204,7 @@ export function hasBacklogItems(backlogPath) {
|
|
|
203
204
|
*/
|
|
204
205
|
export function getSkillPrompt(name) {
|
|
205
206
|
const skill = platformSkills.find((s) => s.name === name)
|
|
207
|
+
?? factorySkills.find((s) => s.name === name)
|
|
206
208
|
?? builtinSkills.find((s) => s.name === name)
|
|
207
209
|
?? codingSkills.find((s) => s.name === name);
|
|
208
210
|
return skill?.prompt ?? null;
|
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;
|
|
@@ -2511,15 +2517,26 @@ export class ReplV2 {
|
|
|
2511
2517
|
}
|
|
2512
2518
|
// Handle get_tool_info - show compact summary
|
|
2513
2519
|
if (toolName === 'get_tool_info') {
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2520
|
+
let name = '?';
|
|
2521
|
+
if (result.success) {
|
|
2522
|
+
if (typeof result.result === 'string') {
|
|
2523
|
+
// Compact schema format (SDK 0.1.15+): "tool_name(...)\n description"
|
|
2524
|
+
const parenIdx = result.result.indexOf('(');
|
|
2525
|
+
if (parenIdx > 0)
|
|
2526
|
+
name = result.result.slice(0, parenIdx);
|
|
2527
|
+
}
|
|
2528
|
+
else if (typeof result.result === 'object' && result.result !== null) {
|
|
2529
|
+
// Legacy object format: { name, description, parameters }
|
|
2530
|
+
const obj = result.result;
|
|
2531
|
+
if (typeof obj.name === 'string')
|
|
2532
|
+
name = obj.name;
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2518
2535
|
this.ui.print({
|
|
2519
2536
|
type: 'tool-result',
|
|
2520
2537
|
name: 'get_tool_info',
|
|
2521
2538
|
params: name,
|
|
2522
|
-
summary: `Schema
|
|
2539
|
+
summary: `Schema: ${name}`,
|
|
2523
2540
|
success: result.success,
|
|
2524
2541
|
agentId: activeAgentId,
|
|
2525
2542
|
});
|
|
@@ -3234,13 +3251,12 @@ export class ReplV2 {
|
|
|
3234
3251
|
if (metrics.toolCalls > 0) {
|
|
3235
3252
|
parts.push(`${String(metrics.toolCalls)} tool${metrics.toolCalls > 1 ? 's' : ''}`);
|
|
3236
3253
|
}
|
|
3237
|
-
// DEBUG: Show payload debug info (
|
|
3254
|
+
// DEBUG: Show payload debug info (token estimates sent to provider)
|
|
3238
3255
|
if (metrics.debugPayload) {
|
|
3239
|
-
const {
|
|
3240
|
-
const
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
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)}]`);
|
|
3244
3260
|
}
|
|
3245
3261
|
// Print as muted info line
|
|
3246
3262
|
this.ui.print({ type: 'turn-summary', parts });
|
package/dist/tool-names.d.ts
CHANGED
|
@@ -92,11 +92,20 @@ export declare const TOOL_NAMES: {
|
|
|
92
92
|
readonly ARTIFACT_LIST: "artifact_list";
|
|
93
93
|
readonly ARTIFACT_DELETE: "artifact_delete";
|
|
94
94
|
readonly RECALL_WORK: "recall_work";
|
|
95
|
+
readonly APP_MODEL_GET: "app_model_get";
|
|
96
|
+
readonly APP_MODEL_UPDATE: "app_model_update";
|
|
97
|
+
readonly APP_MODEL_VALIDATE: "app_model_validate";
|
|
98
|
+
readonly FACTORY_SCAFFOLD: "factory_scaffold";
|
|
99
|
+
readonly FACTORY_LIST_TOOLKITS: "factory_list_toolkits";
|
|
95
100
|
};
|
|
96
101
|
/** Type for all valid tool names */
|
|
97
102
|
export type ToolName = (typeof TOOL_NAMES)[keyof typeof TOOL_NAMES];
|
|
98
103
|
/** Array of all direct tool names (always available) */
|
|
99
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[];
|
|
100
109
|
/** Array of all meta-tool names (tool discovery) */
|
|
101
110
|
export declare const META_TOOL_NAMES: readonly ToolName[];
|
|
102
111
|
/** Array of all meta-registry tool names (accessed via use_tool) */
|