@compilr-dev/cli 0.6.6 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands-v2/handlers/core.js +10 -1
- package/dist/commands-v2/handlers/index.d.ts +1 -0
- package/dist/commands-v2/handlers/index.js +3 -0
- package/dist/commands-v2/handlers/settings.js +21 -5
- package/dist/commands-v2/handlers/skill.d.ts +10 -0
- package/dist/commands-v2/handlers/skill.js +63 -0
- package/dist/commands-v2/index.d.ts +1 -1
- package/dist/commands-v2/index.js +1 -1
- package/dist/commands-v2/registry.d.ts +4 -0
- package/dist/commands-v2/registry.js +19 -0
- package/dist/compilr-diff-companion.vsix +0 -0
- package/dist/index.js +8 -12
- package/dist/repl-helpers.d.ts +29 -1
- package/dist/repl-helpers.js +77 -7
- package/dist/repl-v2.js +29 -3
- package/dist/tools/delegation-status.d.ts +3 -12
- package/dist/tools/delegation-status.js +4 -123
- package/dist/tools/handoff.d.ts +9 -17
- package/dist/tools/handoff.js +28 -48
- package/dist/ui/conversation.js +1 -2
- package/dist/ui/markdown-renderer.d.ts +43 -0
- package/dist/ui/markdown-renderer.js +474 -0
- package/dist/ui/overlay/impl/artifact-detail-overlay-v2.js +1 -2
- package/dist/ui/overlay/impl/document-detail-overlay-v2.js +1 -2
- package/dist/ui/overlay/impl/help-overlay-v2.d.ts +7 -1
- package/dist/ui/overlay/impl/help-overlay-v2.js +19 -2
- package/dist/ui/overlay/impl/skill-detail-overlay-v2.d.ts +91 -0
- package/dist/ui/overlay/impl/skill-detail-overlay-v2.js +863 -0
- package/dist/ui/overlay/impl/skill-editor-overlay.d.ts +56 -0
- package/dist/ui/overlay/impl/skill-editor-overlay.js +493 -0
- package/dist/ui/overlay/impl/skills-overlay-v2.d.ts +83 -0
- package/dist/ui/overlay/impl/skills-overlay-v2.js +1095 -0
- package/dist/utils/skill-paths.d.ts +21 -0
- package/dist/utils/skill-paths.js +44 -0
- package/package.json +9 -6
|
@@ -65,7 +65,16 @@ export const helpCommand = {
|
|
|
65
65
|
'Esc to go back or close',
|
|
66
66
|
],
|
|
67
67
|
async execute(_args, ctx) {
|
|
68
|
-
const
|
|
68
|
+
const { getSkillAutocompleteEntries } = await import('../../repl-helpers.js');
|
|
69
|
+
const helpOverlay = new HelpOverlayV2({
|
|
70
|
+
getHelpCommands,
|
|
71
|
+
getCommand,
|
|
72
|
+
getSkillEntries: () => getSkillAutocompleteEntries().map((e) => ({
|
|
73
|
+
command: e.command,
|
|
74
|
+
description: e.description,
|
|
75
|
+
isBinding: e.description.includes('binding'),
|
|
76
|
+
})),
|
|
77
|
+
});
|
|
69
78
|
await ctx.ui.showOverlay(helpOverlay);
|
|
70
79
|
return true;
|
|
71
80
|
},
|
|
@@ -22,6 +22,7 @@ import { notificationsCommands } from './notifications.js';
|
|
|
22
22
|
import { mcpCommands } from './mcp.js';
|
|
23
23
|
import { delegationsCommands } from './delegations.js';
|
|
24
24
|
import { perfCommands } from './perf.js';
|
|
25
|
+
import { skillCommands } from './skill.js';
|
|
25
26
|
// Re-export individual modules
|
|
26
27
|
export * from './core.js';
|
|
27
28
|
export * from './settings.js';
|
|
@@ -42,6 +43,7 @@ export * from './notifications.js';
|
|
|
42
43
|
export * from './mcp.js';
|
|
43
44
|
export * from './delegations.js';
|
|
44
45
|
export * from './perf.js';
|
|
46
|
+
export * from './skill.js';
|
|
45
47
|
// All commands combined
|
|
46
48
|
export const allCommands = [
|
|
47
49
|
...coreCommands,
|
|
@@ -63,4 +65,5 @@ export const allCommands = [
|
|
|
63
65
|
...mcpCommands,
|
|
64
66
|
...delegationsCommands,
|
|
65
67
|
...perfCommands,
|
|
68
|
+
...skillCommands,
|
|
66
69
|
];
|
|
@@ -119,8 +119,8 @@ export const verboseCommand = {
|
|
|
119
119
|
// =============================================================================
|
|
120
120
|
export const modelCommand = {
|
|
121
121
|
name: 'model',
|
|
122
|
-
description: 'Change AI model',
|
|
123
|
-
details: 'Opens the model selector
|
|
122
|
+
description: 'Change AI model for the active agent',
|
|
123
|
+
details: 'Opens the model selector for the active agent. Changing the model takes effect immediately on the next message. Settings model (via /config) is the template for new agents only.',
|
|
124
124
|
examples: [{ code: '/model' }],
|
|
125
125
|
interactions: [
|
|
126
126
|
'Tab/Shift+Tab to switch providers',
|
|
@@ -131,15 +131,31 @@ export const modelCommand = {
|
|
|
131
131
|
'Esc to go back/close',
|
|
132
132
|
],
|
|
133
133
|
async execute(_args, ctx) {
|
|
134
|
-
|
|
134
|
+
// Use the active agent's current model, not the settings default
|
|
135
|
+
const agent = ctx.agent;
|
|
136
|
+
const agentModel = agent ? agent.getModel() : undefined;
|
|
137
|
+
const currentModel = agentModel ?? getSetting('defaultModel') ?? undefined;
|
|
135
138
|
const currentProvider = getSetting('defaultProvider');
|
|
136
139
|
const modelOverlay = new ModelOverlayV2({
|
|
137
140
|
currentModel: currentModel ?? undefined,
|
|
138
141
|
currentProvider: currentProvider === 'auto' ? undefined : currentProvider,
|
|
139
142
|
});
|
|
140
143
|
await ctx.ui.showOverlay(modelOverlay);
|
|
141
|
-
//
|
|
142
|
-
//
|
|
144
|
+
// After overlay closes, check if the model changed (overlay calls setSetting)
|
|
145
|
+
// Apply it to the active agent immediately via setModel()
|
|
146
|
+
if (agent) {
|
|
147
|
+
const newModel = getSetting('defaultModel');
|
|
148
|
+
if (newModel && newModel !== agentModel) {
|
|
149
|
+
try {
|
|
150
|
+
agent.setModel(newModel);
|
|
151
|
+
const agentId = ctx.team ? ctx.team.getActive().id : 'default';
|
|
152
|
+
ctx.ui.print({ type: 'success', message: `Model changed: $${agentId} now using ${newModel}` });
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
ctx.ui.print({ type: 'error', message: `Failed to change model: ${err instanceof Error ? err.message : String(err)}` });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
143
159
|
return true;
|
|
144
160
|
},
|
|
145
161
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom Skills command handler
|
|
3
|
+
*
|
|
4
|
+
* Opens the Skills overlay (TabbedListOverlayV2) for browsing, creating,
|
|
5
|
+
* editing, and managing custom skills.
|
|
6
|
+
*
|
|
7
|
+
* Spec: project-docs/00-requirements/compilr-dev-cli/skills-overlay-spec.md
|
|
8
|
+
*/
|
|
9
|
+
import type { CommandHandlerV2 } from '../types.js';
|
|
10
|
+
export declare const skillCommands: CommandHandlerV2[];
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom Skills command handler
|
|
3
|
+
*
|
|
4
|
+
* Opens the Skills overlay (TabbedListOverlayV2) for browsing, creating,
|
|
5
|
+
* editing, and managing custom skills.
|
|
6
|
+
*
|
|
7
|
+
* Spec: project-docs/00-requirements/compilr-dev-cli/skills-overlay-spec.md
|
|
8
|
+
*/
|
|
9
|
+
import { promises as fs } from 'node:fs';
|
|
10
|
+
import { SkillsOverlayV2 } from '../../ui/overlay/impl/skills-overlay-v2.js';
|
|
11
|
+
import { SkillDetailOverlayV2 } from '../../ui/overlay/impl/skill-detail-overlay-v2.js';
|
|
12
|
+
import { getCurrentProject } from '../../tools/project-db.js';
|
|
13
|
+
const skillCommand = {
|
|
14
|
+
name: 'skill',
|
|
15
|
+
aliases: ['skills'],
|
|
16
|
+
description: 'Manage custom and built-in skills',
|
|
17
|
+
details: 'Browse, create, edit, and manage user-authored skills. Skills are ' +
|
|
18
|
+
'folders with SKILL.md (Anthropic Agent Skills format). Custom skills ' +
|
|
19
|
+
'can be scoped to a project or user. Built-in SDK skills are read-only.',
|
|
20
|
+
examples: [
|
|
21
|
+
{ code: '/skill', description: 'Open Skills overlay' },
|
|
22
|
+
{ code: '/skills', description: 'Alias for /skill' },
|
|
23
|
+
],
|
|
24
|
+
interactions: [
|
|
25
|
+
'←→ Switch tabs (Custom / Built-in)',
|
|
26
|
+
'↑↓ or j/k Navigate skills',
|
|
27
|
+
'Enter Open skill (view/edit/diff)',
|
|
28
|
+
'n Create new skill',
|
|
29
|
+
'f Fork SDK skill',
|
|
30
|
+
'b Bind slash command',
|
|
31
|
+
'u Unbind slash command',
|
|
32
|
+
'Space Enable/disable skill',
|
|
33
|
+
'd Delete skill',
|
|
34
|
+
'r Rename skill',
|
|
35
|
+
'/ Search skills',
|
|
36
|
+
'q/Esc Close',
|
|
37
|
+
],
|
|
38
|
+
async execute(_args, ctx) {
|
|
39
|
+
const project = getCurrentProject();
|
|
40
|
+
const overlay = new SkillsOverlayV2({
|
|
41
|
+
projectPath: project?.path ?? undefined,
|
|
42
|
+
onOpenDetail: async (filePath, skillName, scope, forkedFrom, boundCommands) => {
|
|
43
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
44
|
+
const detail = new SkillDetailOverlayV2({
|
|
45
|
+
filePath,
|
|
46
|
+
skillName,
|
|
47
|
+
scope,
|
|
48
|
+
content,
|
|
49
|
+
forkedFrom,
|
|
50
|
+
boundCommands,
|
|
51
|
+
});
|
|
52
|
+
await ctx.ui.showOverlay(detail);
|
|
53
|
+
// The overlay was shown and closed — assume modified if content was changed
|
|
54
|
+
return true;
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
// Load items async before showing
|
|
58
|
+
await overlay.loadItems();
|
|
59
|
+
await ctx.ui.showOverlay(overlay);
|
|
60
|
+
return true;
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
export const skillCommands = [skillCommand];
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Command system for the new TerminalUI-based REPL.
|
|
5
5
|
*/
|
|
6
6
|
export type { CommandContextV2, CommandHandlerV2, CommandResultV2, CommandExample } from './types.js';
|
|
7
|
-
export { registerCommand, registerCommands, getCommand, executeCommand, getCommandNames, hasCommand, clearCommands, getAutocompleteCommands, getHelpCommands, } from './registry.js';
|
|
7
|
+
export { registerCommand, registerCommands, getCommand, executeCommand, getCommandNames, hasCommand, clearCommands, getAutocompleteCommands, getHelpCommands, setSkillCommandLoader, } from './registry.js';
|
|
8
8
|
export { allCommands } from './handlers/index.js';
|
|
9
9
|
export { coreCommands } from './handlers/core.js';
|
|
10
10
|
export { settingsCommands } from './handlers/settings.js';
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Command system for the new TerminalUI-based REPL.
|
|
5
5
|
*/
|
|
6
6
|
// Registry
|
|
7
|
-
export { registerCommand, registerCommands, getCommand, executeCommand, getCommandNames, hasCommand, clearCommands, getAutocompleteCommands, getHelpCommands, } from './registry.js';
|
|
7
|
+
export { registerCommand, registerCommands, getCommand, executeCommand, getCommandNames, hasCommand, clearCommands, getAutocompleteCommands, getHelpCommands, setSkillCommandLoader, } from './registry.js';
|
|
8
8
|
// All handlers
|
|
9
9
|
export { allCommands } from './handlers/index.js';
|
|
10
10
|
// Individual handler modules (for selective imports)
|
|
@@ -43,6 +43,10 @@ export declare function getAutocompleteCommands(): {
|
|
|
43
43
|
command: string;
|
|
44
44
|
description: string;
|
|
45
45
|
}[];
|
|
46
|
+
export declare function setSkillCommandLoader(loader: () => {
|
|
47
|
+
command: string;
|
|
48
|
+
description: string;
|
|
49
|
+
}[]): void;
|
|
46
50
|
/**
|
|
47
51
|
* Get all commands formatted for help display.
|
|
48
52
|
*/
|
|
@@ -84,6 +84,7 @@ export function clearCommands() {
|
|
|
84
84
|
*/
|
|
85
85
|
export function getAutocompleteCommands() {
|
|
86
86
|
const commands = [];
|
|
87
|
+
const seen = new Set();
|
|
87
88
|
for (const [name, handler] of handlers) {
|
|
88
89
|
// Skip internal commands (tools, debug commands with underscores/camelCase)
|
|
89
90
|
if (name.includes('_') || /[A-Z]/.test(name))
|
|
@@ -92,9 +93,27 @@ export function getAutocompleteCommands() {
|
|
|
92
93
|
command: `/${name}`,
|
|
93
94
|
description: handler.description,
|
|
94
95
|
});
|
|
96
|
+
seen.add(name);
|
|
97
|
+
}
|
|
98
|
+
// Append custom skills and bindings (if loader is registered)
|
|
99
|
+
if (skillCommandLoader) {
|
|
100
|
+
for (const { command, description } of skillCommandLoader()) {
|
|
101
|
+
if (!seen.has(command)) {
|
|
102
|
+
commands.push({ command: `/${command}`, description });
|
|
103
|
+
seen.add(command);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
95
106
|
}
|
|
96
107
|
return commands.sort((a, b) => a.command.localeCompare(b.command));
|
|
97
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Register a callback that provides custom skill names + bound commands
|
|
111
|
+
* for autocomplete. Set by the REPL on startup.
|
|
112
|
+
*/
|
|
113
|
+
let skillCommandLoader = null;
|
|
114
|
+
export function setSkillCommandLoader(loader) {
|
|
115
|
+
skillCommandLoader = loader;
|
|
116
|
+
}
|
|
98
117
|
/**
|
|
99
118
|
* Get all commands formatted for help display.
|
|
100
119
|
*/
|
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -18,6 +18,7 @@ import { getModelForTier, getProviderMetadata } from './models/index.js';
|
|
|
18
18
|
import { ReplV2 } from './repl-v2.js';
|
|
19
19
|
import { AgentTeam, setActiveSharedContext } from './multi-agent/index.js';
|
|
20
20
|
import { getStyles } from './themes/index.js';
|
|
21
|
+
import { getDefaultModelForTier } from './models/index.js';
|
|
21
22
|
import { getDefaultProvider, getDefaultModel as getDefaultModelSetting, getProjectStartupMode, getLastProjectId, isCheckUpdatesEnabled, getLastUpdateCheck, recordUpdateCheck, isFirstRunComplete, setSetting, getSetting } from './settings/index.js';
|
|
22
23
|
import { checkForUpdates, performUpdate } from './utils/update-checker.js';
|
|
23
24
|
import { showAskUserSimpleOverlay } from './ui/ask-user-simple-overlay.js';
|
|
@@ -938,18 +939,13 @@ function detectProvider() {
|
|
|
938
939
|
return 'claude';
|
|
939
940
|
}
|
|
940
941
|
function getDefaultModel(provider) {
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
case 'ollama':
|
|
949
|
-
return 'llama3.2:8b';
|
|
950
|
-
default:
|
|
951
|
-
return 'claude-sonnet-4-6';
|
|
952
|
-
}
|
|
942
|
+
// Dynamic lookup from MODEL_REGISTRY (via SDK) — never goes stale
|
|
943
|
+
const model = getDefaultModelForTier(provider, 'balanced');
|
|
944
|
+
if (model)
|
|
945
|
+
return model.id;
|
|
946
|
+
// Fallback to any supported model for this provider
|
|
947
|
+
const anyModel = getDefaultModelForTier(provider, 'fast') ?? getDefaultModelForTier(provider, 'powerful');
|
|
948
|
+
return anyModel?.id ?? 'claude-sonnet-4-6';
|
|
953
949
|
}
|
|
954
950
|
// =============================================================================
|
|
955
951
|
// Run
|
package/dist/repl-helpers.d.ts
CHANGED
|
@@ -39,9 +39,37 @@ export declare function detectCompilrProject(): CompilrProjectInfo;
|
|
|
39
39
|
*/
|
|
40
40
|
export declare function hasBacklogItems(backlogPath: string | null): boolean;
|
|
41
41
|
/**
|
|
42
|
-
* Get skill prompt by name
|
|
42
|
+
* Get skill prompt by name. Delegates to SDK resolveSkillPrompt.
|
|
43
43
|
*/
|
|
44
44
|
export declare function getSkillPrompt(name: string): string | null;
|
|
45
|
+
/**
|
|
46
|
+
* Richer version of getSkillPrompt that returns attribution metadata.
|
|
47
|
+
* Used by the REPL to show binding/fork info in chat.
|
|
48
|
+
*/
|
|
49
|
+
export declare function getSkillResolution(name: string): {
|
|
50
|
+
prompt: string;
|
|
51
|
+
skillName: string;
|
|
52
|
+
isBound: boolean;
|
|
53
|
+
forkedFrom?: import('@compilr-dev/sdk').ForkedFromMarker;
|
|
54
|
+
} | null;
|
|
55
|
+
/**
|
|
56
|
+
* Get autocomplete entries for custom skills + bound commands.
|
|
57
|
+
* Delegates to SDK getAllAvailableSkills.
|
|
58
|
+
*/
|
|
59
|
+
export declare function getSkillAutocompleteEntries(): {
|
|
60
|
+
command: string;
|
|
61
|
+
description: string;
|
|
62
|
+
}[];
|
|
63
|
+
/**
|
|
64
|
+
* Check for user/project skills that collide with SDK reserved names.
|
|
65
|
+
* Shows a one-time warning at startup if collisions are found.
|
|
66
|
+
*/
|
|
67
|
+
export declare function checkSkillCollisions(ui: {
|
|
68
|
+
print: (msg: {
|
|
69
|
+
type: 'warning';
|
|
70
|
+
message: string;
|
|
71
|
+
}) => void;
|
|
72
|
+
}): void;
|
|
45
73
|
/**
|
|
46
74
|
* Select the best backlog item to build.
|
|
47
75
|
* If requestedId is provided, finds that specific item.
|
package/dist/repl-helpers.js
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
* and improve maintainability. These functions support the REPL but don't
|
|
6
6
|
* depend on REPL instance state.
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
8
|
+
import { detectCollisions, formatCollisionWarnings, resolveSkillPrompt, getAllAvailableSkills } from '@compilr-dev/sdk';
|
|
9
|
+
import { getSkillsDir } from './utils/skill-paths.js';
|
|
10
|
+
import { getProjectPath } from './utils/project-status.js';
|
|
9
11
|
import { codingSkills } from '@compilr-dev/agents-coding';
|
|
10
12
|
import { factorySkills } from '@compilr-dev/factory';
|
|
11
13
|
import * as fs from 'fs';
|
|
@@ -199,15 +201,83 @@ export function hasBacklogItems(backlogPath) {
|
|
|
199
201
|
return false;
|
|
200
202
|
}
|
|
201
203
|
}
|
|
204
|
+
/** Get the current project directory (best effort). */
|
|
205
|
+
function getProjectDir() {
|
|
206
|
+
try {
|
|
207
|
+
return getProjectPath(process.cwd());
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/** Get CLI skill sources (factory + coding). */
|
|
214
|
+
function getCliSkillSources() {
|
|
215
|
+
return { factorySkills, codingSkills };
|
|
216
|
+
}
|
|
202
217
|
/**
|
|
203
|
-
* Get skill prompt by name
|
|
218
|
+
* Get skill prompt by name. Delegates to SDK resolveSkillPrompt.
|
|
204
219
|
*/
|
|
205
220
|
export function getSkillPrompt(name) {
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
221
|
+
const resolution = resolveSkillPrompt(name, getProjectDir(), getCliSkillSources());
|
|
222
|
+
return resolution?.prompt ?? null;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Richer version of getSkillPrompt that returns attribution metadata.
|
|
226
|
+
* Used by the REPL to show binding/fork info in chat.
|
|
227
|
+
*/
|
|
228
|
+
export function getSkillResolution(name) {
|
|
229
|
+
const resolution = resolveSkillPrompt(name, getProjectDir(), getCliSkillSources());
|
|
230
|
+
if (!resolution)
|
|
231
|
+
return null;
|
|
232
|
+
return {
|
|
233
|
+
prompt: resolution.prompt,
|
|
234
|
+
skillName: resolution.skillName,
|
|
235
|
+
isBound: resolution.isBound,
|
|
236
|
+
forkedFrom: resolution.forkedFrom,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Get autocomplete entries for custom skills + bound commands.
|
|
241
|
+
* Delegates to SDK getAllAvailableSkills.
|
|
242
|
+
*/
|
|
243
|
+
export function getSkillAutocompleteEntries() {
|
|
244
|
+
const entries = getAllAvailableSkills(getProjectDir(), getCliSkillSources());
|
|
245
|
+
return entries
|
|
246
|
+
.filter((e) => e.source !== 'sdk' && e.source !== 'agents') // SDK/agents skills already in built-in commands
|
|
247
|
+
.map((e) => {
|
|
248
|
+
const desc = e.description.length > 60 ? e.description.slice(0, 57) + '...' : e.description;
|
|
249
|
+
return {
|
|
250
|
+
command: e.boundCommand ?? e.name,
|
|
251
|
+
description: e.scope ? `[${e.scope}] ${desc}` : desc,
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Check for user/project skills that collide with SDK reserved names.
|
|
257
|
+
* Shows a one-time warning at startup if collisions are found.
|
|
258
|
+
*/
|
|
259
|
+
export function checkSkillCollisions(ui) {
|
|
260
|
+
const userSkills = [];
|
|
261
|
+
for (const scope of ['project', 'user']) {
|
|
262
|
+
try {
|
|
263
|
+
const dir = getSkillsDir(scope);
|
|
264
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
265
|
+
for (const entry of entries) {
|
|
266
|
+
if (!entry.isDirectory())
|
|
267
|
+
continue;
|
|
268
|
+
userSkills.push({
|
|
269
|
+
name: entry.name,
|
|
270
|
+
scope,
|
|
271
|
+
path: path.join(dir, entry.name),
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
catch { /* dir doesn't exist */ }
|
|
276
|
+
}
|
|
277
|
+
const collisions = detectCollisions(userSkills);
|
|
278
|
+
if (collisions.length > 0) {
|
|
279
|
+
ui.print({ type: 'warning', message: formatCollisionWarnings(collisions) });
|
|
280
|
+
}
|
|
211
281
|
}
|
|
212
282
|
// =============================================================================
|
|
213
283
|
// Build Command Helpers
|
package/dist/repl-v2.js
CHANGED
|
@@ -29,7 +29,7 @@ import { getSettings, getStartupMode, syncPermissionModeFromUI, getPermissionMod
|
|
|
29
29
|
import { isReadOnlyTool } from './utils/readonly-tools.js';
|
|
30
30
|
import { renderMascotWithLogo } from './ui/mascot/renderer.js';
|
|
31
31
|
import { getStartupHighlights } from './changelog/index.js';
|
|
32
|
-
import { registerCommands, executeCommand, allCommands, getAutocompleteCommands, saveCurrentSession, saveCurrentTeam, loadProjectSession, archiveCurrentSession, convertMessagesToItems, } from './commands-v2/index.js';
|
|
32
|
+
import { registerCommands, executeCommand, allCommands, getAutocompleteCommands, setSkillCommandLoader, saveCurrentSession, saveCurrentTeam, loadProjectSession, archiveCurrentSession, convertMessagesToItems, } from './commands-v2/index.js';
|
|
33
33
|
import { getCustomCommandRegistry } from './commands/custom-registry.js';
|
|
34
34
|
import { getPlanModePrompt } from '@compilr-dev/sdk';
|
|
35
35
|
import { planRepository } from './db/repositories/index.js';
|
|
@@ -52,6 +52,7 @@ import { formatTokens } from './ui/base/index.js';
|
|
|
52
52
|
import { isMemoryInput } from './input-handlers/index.js';
|
|
53
53
|
import { addAnchor } from './anchors/index.js';
|
|
54
54
|
import { getActiveProject } from './tools/project-db.js';
|
|
55
|
+
import { getSkillResolution, getSkillAutocompleteEntries, checkSkillCollisions } from './repl-helpers.js';
|
|
55
56
|
import { getProjectSessionManager } from './session/project-session-manager.js';
|
|
56
57
|
import { ResumeOverlayV2 } from './ui/overlay/impl/resume-overlay-v2.js';
|
|
57
58
|
import { updateCacheInfo, updateHistoryEstimate, formatBreakdownCompact, formatCacheInfo, estimateTokens } from './utils/token-tracker.js';
|
|
@@ -818,6 +819,10 @@ export class ReplV2 {
|
|
|
818
819
|
// Set initial state
|
|
819
820
|
this.ui.setProjectName(this.projectName);
|
|
820
821
|
this.ui.setCommandsCallback(getAutocompleteCommands);
|
|
822
|
+
// Register skill commands for autocomplete (custom skills + bindings)
|
|
823
|
+
setSkillCommandLoader(() => getSkillAutocompleteEntries());
|
|
824
|
+
// Check for user/SDK skill name collisions (once at startup)
|
|
825
|
+
checkSkillCollisions(this.ui);
|
|
821
826
|
// Set up agent suggestions callback for $ autocomplete (if team is available)
|
|
822
827
|
if (this.team) {
|
|
823
828
|
const team = this.team; // Capture for closure
|
|
@@ -1652,8 +1657,9 @@ export class ReplV2 {
|
|
|
1652
1657
|
console.log(s.warning(' ⚠ Simulation mode (no agent)'));
|
|
1653
1658
|
}
|
|
1654
1659
|
console.log('');
|
|
1655
|
-
// Show model info
|
|
1656
|
-
|
|
1660
|
+
// Show model info (prefer live agent model over startup setting)
|
|
1661
|
+
const currentModel = this.agent ? this.agent.getModel() : this.model;
|
|
1662
|
+
console.log(s.muted('Model: ') + s.secondary(currentModel));
|
|
1657
1663
|
console.log(s.muted('Provider: ') + s.secondary(this.provider));
|
|
1658
1664
|
console.log('');
|
|
1659
1665
|
}
|
|
@@ -1788,6 +1794,26 @@ export class ReplV2 {
|
|
|
1788
1794
|
const ctx = this.createCommandContext();
|
|
1789
1795
|
const result = await executeCommand(cmd, args, ctx);
|
|
1790
1796
|
if (result === null) {
|
|
1797
|
+
// Check if it resolves to a skill (custom or bound)
|
|
1798
|
+
const resolution = getSkillResolution(cmd);
|
|
1799
|
+
if (resolution) {
|
|
1800
|
+
// Show attribution if the command was resolved via binding
|
|
1801
|
+
if (resolution.isBound) {
|
|
1802
|
+
const forkInfo = resolution.forkedFrom
|
|
1803
|
+
? ` (forked from sdk:${resolution.forkedFrom.skill}@${resolution.forkedFrom.version})`
|
|
1804
|
+
: '';
|
|
1805
|
+
this.ui.print({ type: 'info', message: `🛠 /${cmd} → ${resolution.skillName}${forkInfo}` });
|
|
1806
|
+
}
|
|
1807
|
+
this.ui.print({ type: 'user-message', text: `/${cmd}${args ? ' ' + args : ''}` });
|
|
1808
|
+
const fullPrompt = args ? `${resolution.prompt}\n\nUser request: ${args}` : resolution.prompt;
|
|
1809
|
+
if (this.agent) {
|
|
1810
|
+
await this.runAgentReal(fullPrompt);
|
|
1811
|
+
}
|
|
1812
|
+
else {
|
|
1813
|
+
await this.runAgentSimulation(fullPrompt);
|
|
1814
|
+
}
|
|
1815
|
+
return;
|
|
1816
|
+
}
|
|
1791
1817
|
// Check if it's a custom command
|
|
1792
1818
|
const customRegistry = getCustomCommandRegistry();
|
|
1793
1819
|
if (customRegistry.has(cmd)) {
|
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Delegation Status Tool - Coordinator Mode
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Queries the DelegationTracker singleton and returns formatted status.
|
|
4
|
+
* Thin wrapper over SDK's createDelegationStatusTool factory.
|
|
6
5
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
delegation_id?: string;
|
|
10
|
-
/** Filter by target agent (e.g., "dev") */
|
|
11
|
-
agent_id?: string;
|
|
12
|
-
/** Filter by status: active (pending+running), completed, failed, all. Default: active */
|
|
13
|
-
status?: 'active' | 'completed' | 'failed' | 'all';
|
|
14
|
-
}
|
|
15
|
-
export declare const delegationStatusTool: import("@compilr-dev/sdk").Tool<DelegationStatusInput>;
|
|
16
|
-
export {};
|
|
6
|
+
import type { Tool } from '@compilr-dev/agents';
|
|
7
|
+
export declare const delegationStatusTool: Tool<any>;
|
|
@@ -1,128 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Delegation Status Tool - Coordinator Mode
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Queries the DelegationTracker singleton and returns formatted status.
|
|
4
|
+
* Thin wrapper over SDK's createDelegationStatusTool factory.
|
|
6
5
|
*/
|
|
7
|
-
import {
|
|
6
|
+
import { createDelegationStatusTool } from '@compilr-dev/sdk';
|
|
8
7
|
import { getDelegationTracker } from '../multi-agent/delegation-tracker.js';
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
// =============================================================================
|
|
12
|
-
function formatDuration(from, to) {
|
|
13
|
-
const endTime = to ?? new Date();
|
|
14
|
-
const ms = endTime.getTime() - from.getTime();
|
|
15
|
-
const seconds = Math.floor(ms / 1000);
|
|
16
|
-
const minutes = Math.floor(seconds / 60);
|
|
17
|
-
const hours = Math.floor(minutes / 60);
|
|
18
|
-
if (hours > 0) {
|
|
19
|
-
return `${String(hours)}h ${String(minutes % 60)}m`;
|
|
20
|
-
}
|
|
21
|
-
else if (minutes > 0) {
|
|
22
|
-
return `${String(minutes)}m ${String(seconds % 60)}s`;
|
|
23
|
-
}
|
|
24
|
-
else {
|
|
25
|
-
return `${String(seconds)}s`;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
function formatDelegation(d) {
|
|
29
|
-
const entry = {
|
|
30
|
-
id: d.id,
|
|
31
|
-
targetAgent: d.targetAgentId,
|
|
32
|
-
task: d.task.length > 100 ? d.task.slice(0, 100) + '...' : d.task,
|
|
33
|
-
status: d.status,
|
|
34
|
-
duration: formatDuration(d.createdAt, d.completedAt),
|
|
35
|
-
};
|
|
36
|
-
if (d.todoIndex !== undefined) {
|
|
37
|
-
entry.todoIndex = d.todoIndex;
|
|
38
|
-
}
|
|
39
|
-
if (d.result) {
|
|
40
|
-
entry.result = {
|
|
41
|
-
success: d.result.success,
|
|
42
|
-
summary: d.result.summary,
|
|
43
|
-
artifactIds: d.result.artifactIds,
|
|
44
|
-
...(d.result.error ? { error: d.result.error } : {}),
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
return entry;
|
|
48
|
-
}
|
|
49
|
-
// =============================================================================
|
|
50
|
-
// Tool Definition
|
|
51
|
-
// =============================================================================
|
|
52
|
-
export const delegationStatusTool = defineTool({
|
|
53
|
-
name: 'delegation_status',
|
|
54
|
-
description: 'Query the status of tasks delegated via delegate_background. ' +
|
|
55
|
-
'Returns active delegations by default (pending and running). ' +
|
|
56
|
-
'Use delegation_id for a specific delegation, agent_id to filter by agent, ' +
|
|
57
|
-
'or status to see completed/failed/all delegations. ' +
|
|
58
|
-
'Note: Only tracks delegate_background calls, not foreground delegate.',
|
|
59
|
-
inputSchema: {
|
|
60
|
-
type: 'object',
|
|
61
|
-
properties: {
|
|
62
|
-
delegation_id: {
|
|
63
|
-
type: 'string',
|
|
64
|
-
description: 'Specific delegation ID (e.g., "del_abc12345")',
|
|
65
|
-
},
|
|
66
|
-
agent_id: {
|
|
67
|
-
type: 'string',
|
|
68
|
-
description: 'Filter by target agent (e.g., "dev", "arch")',
|
|
69
|
-
},
|
|
70
|
-
status: {
|
|
71
|
-
type: 'string',
|
|
72
|
-
enum: ['active', 'completed', 'failed', 'all'],
|
|
73
|
-
description: 'Filter by status. Default: "active" (pending + running)',
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
execute: async (input) => {
|
|
78
|
-
const tracker = await Promise.resolve(getDelegationTracker());
|
|
79
|
-
// Single delegation lookup
|
|
80
|
-
if (input.delegation_id) {
|
|
81
|
-
const delegation = tracker.getDelegation(input.delegation_id);
|
|
82
|
-
if (!delegation) {
|
|
83
|
-
return {
|
|
84
|
-
success: false,
|
|
85
|
-
error: `Delegation ${input.delegation_id} not found`,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
return {
|
|
89
|
-
success: true,
|
|
90
|
-
result: {
|
|
91
|
-
delegations: [formatDelegation(delegation)],
|
|
92
|
-
stats: tracker.getStats(),
|
|
93
|
-
},
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
// Get all delegations then filter
|
|
97
|
-
let delegations;
|
|
98
|
-
if (input.agent_id) {
|
|
99
|
-
delegations = tracker.getByAgent(input.agent_id);
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
delegations = tracker.getAll();
|
|
103
|
-
}
|
|
104
|
-
// Apply status filter
|
|
105
|
-
const filter = input.status ?? 'active';
|
|
106
|
-
if (filter !== 'all') {
|
|
107
|
-
delegations = delegations.filter((d) => {
|
|
108
|
-
switch (filter) {
|
|
109
|
-
case 'active':
|
|
110
|
-
return d.status === 'pending' || d.status === 'running';
|
|
111
|
-
case 'completed':
|
|
112
|
-
return d.status === 'completed';
|
|
113
|
-
case 'failed':
|
|
114
|
-
return d.status === 'failed';
|
|
115
|
-
default:
|
|
116
|
-
return true;
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
return {
|
|
121
|
-
success: true,
|
|
122
|
-
result: {
|
|
123
|
-
delegations: delegations.map(formatDelegation),
|
|
124
|
-
stats: tracker.getStats(),
|
|
125
|
-
},
|
|
126
|
-
};
|
|
127
|
-
},
|
|
128
|
-
});
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
9
|
+
export const delegationStatusTool = createDelegationStatusTool(getDelegationTracker());
|