@compilr-dev/cli 0.6.6 → 0.7.0

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.
Files changed (31) hide show
  1. package/dist/commands-v2/handlers/core.js +10 -1
  2. package/dist/commands-v2/handlers/index.d.ts +1 -0
  3. package/dist/commands-v2/handlers/index.js +3 -0
  4. package/dist/commands-v2/handlers/settings.js +21 -5
  5. package/dist/commands-v2/handlers/skill.d.ts +10 -0
  6. package/dist/commands-v2/handlers/skill.js +63 -0
  7. package/dist/commands-v2/index.d.ts +1 -1
  8. package/dist/commands-v2/index.js +1 -1
  9. package/dist/commands-v2/registry.d.ts +4 -0
  10. package/dist/commands-v2/registry.js +19 -0
  11. package/dist/compilr-diff-companion.vsix +0 -0
  12. package/dist/index.js +8 -12
  13. package/dist/repl-helpers.d.ts +29 -1
  14. package/dist/repl-helpers.js +77 -7
  15. package/dist/repl-v2.js +29 -3
  16. package/dist/ui/conversation.js +1 -2
  17. package/dist/ui/markdown-renderer.d.ts +43 -0
  18. package/dist/ui/markdown-renderer.js +474 -0
  19. package/dist/ui/overlay/impl/artifact-detail-overlay-v2.js +1 -2
  20. package/dist/ui/overlay/impl/document-detail-overlay-v2.js +1 -2
  21. package/dist/ui/overlay/impl/help-overlay-v2.d.ts +7 -1
  22. package/dist/ui/overlay/impl/help-overlay-v2.js +19 -2
  23. package/dist/ui/overlay/impl/skill-detail-overlay-v2.d.ts +91 -0
  24. package/dist/ui/overlay/impl/skill-detail-overlay-v2.js +863 -0
  25. package/dist/ui/overlay/impl/skill-editor-overlay.d.ts +56 -0
  26. package/dist/ui/overlay/impl/skill-editor-overlay.js +493 -0
  27. package/dist/ui/overlay/impl/skills-overlay-v2.d.ts +83 -0
  28. package/dist/ui/overlay/impl/skills-overlay-v2.js +1095 -0
  29. package/dist/utils/skill-paths.d.ts +21 -0
  30. package/dist/utils/skill-paths.js +44 -0
  31. package/package.json +7 -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 helpOverlay = new HelpOverlayV2({ getHelpCommands, getCommand });
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
  },
@@ -23,4 +23,5 @@ export * from './notifications.js';
23
23
  export * from './mcp.js';
24
24
  export * from './delegations.js';
25
25
  export * from './perf.js';
26
+ export * from './skill.js';
26
27
  export declare const allCommands: CommandHandlerV2[];
@@ -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 overlay. Choose from Claude, OpenAI, Gemini, or Ollama models. Changes within the same provider apply immediately; switching providers requires restart.',
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
- const currentModel = getSetting('defaultModel') ?? undefined;
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
- // Model changes are handled in the detail screen via setSetting()
142
- // No need to process result here
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
- switch (provider) {
942
- case 'claude':
943
- return 'claude-sonnet-4-6';
944
- case 'openai':
945
- return 'gpt-5-mini-2025-08-07';
946
- case 'gemini':
947
- return 'gemini-3-flash-preview';
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
@@ -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 from builtinSkills or codingSkills.
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.
@@ -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 { builtinSkills, platformSkills } from '@compilr-dev/sdk';
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 from builtinSkills or codingSkills.
218
+ * Get skill prompt by name. Delegates to SDK resolveSkillPrompt.
204
219
  */
205
220
  export function getSkillPrompt(name) {
206
- const skill = platformSkills.find((s) => s.name === name)
207
- ?? factorySkills.find((s) => s.name === name)
208
- ?? builtinSkills.find((s) => s.name === name)
209
- ?? codingSkills.find((s) => s.name === name);
210
- return skill?.prompt ?? null;
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
- console.log(s.muted('Model: ') + s.secondary(this.model));
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)) {
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import { Chalk } from 'chalk';
9
9
  import { marked } from 'marked';
10
- import { markedTerminal } from 'marked-terminal';
10
+ import { markedTerminal } from './markdown-renderer.js';
11
11
  import { highlight } from 'cli-highlight';
12
12
  import { getStyles } from '../themes/index.js';
13
13
  import { getThemeColors } from '../themes/index.js';
@@ -153,7 +153,6 @@ export function renderMarkdown(text) {
153
153
  const preprocessed = preprocessMarkdown(text);
154
154
  // Configure marked with theme-aware options
155
155
  const options = getThemedMarkedOptions();
156
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
157
156
  marked.use(markedTerminal(options));
158
157
  // Parse
159
158
  const rendered = marked.parse(preprocessed, { async: false });
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Terminal markdown renderer for marked.
3
+ * Drop-in replacement for `marked-terminal` — returns a marked extension.
4
+ *
5
+ * Usage:
6
+ * import { markedTerminal } from './markdown-renderer.js';
7
+ * marked.use(markedTerminal(options));
8
+ */
9
+ type ChalkFn = (text: string) => string;
10
+ export interface TerminalRendererOptions {
11
+ heading?: ChalkFn;
12
+ firstHeading?: ChalkFn;
13
+ strong?: ChalkFn;
14
+ em?: ChalkFn;
15
+ codespan?: ChalkFn;
16
+ code?: ChalkFn;
17
+ blockquote?: ChalkFn;
18
+ del?: ChalkFn;
19
+ link?: ChalkFn;
20
+ href?: ChalkFn;
21
+ html?: ChalkFn;
22
+ hr?: ChalkFn;
23
+ table?: ChalkFn;
24
+ listitem?: ChalkFn;
25
+ paragraph?: ChalkFn;
26
+ text?: ChalkFn;
27
+ width?: number;
28
+ tab?: number;
29
+ reflowText?: boolean;
30
+ showSectionPrefix?: boolean;
31
+ unescape?: boolean;
32
+ emoji?: boolean;
33
+ tableOptions?: Record<string, unknown>;
34
+ }
35
+ /**
36
+ * Returns a marked extension that renders markdown to ANSI terminal output.
37
+ * Drop-in replacement for `markedTerminal` from the `marked-terminal` package.
38
+ */
39
+ export declare function markedTerminal(options?: TerminalRendererOptions): {
40
+ renderer: Record<string, unknown>;
41
+ useNewRenderer: boolean;
42
+ };
43
+ export {};