@compilr-dev/cli 0.8.10 → 0.9.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.
- package/CHANGELOG.md +35 -0
- package/dist/agent.d.ts +9 -0
- package/dist/agent.js +1 -0
- package/dist/commands-v2/handlers/project.js +88 -229
- package/dist/commands-v2/handlers/skill.js +10 -6
- package/dist/commands-v2/handlers/team.d.ts +19 -1
- package/dist/commands-v2/handlers/team.js +178 -3
- package/dist/compilr-diff-companion.vsix +0 -0
- package/dist/index.js +55 -3
- package/dist/multi-agent/agent-edit.d.ts +75 -0
- package/dist/multi-agent/agent-edit.js +84 -0
- package/dist/multi-agent/capability-loader.d.ts +15 -5
- package/dist/multi-agent/capability-loader.js +18 -8
- package/dist/multi-agent/custom-agents.d.ts +12 -0
- package/dist/multi-agent/custom-agents.js +22 -1
- package/dist/repl-helpers.d.ts +6 -1
- package/dist/repl-helpers.js +14 -7
- package/dist/repl-v2.d.ts +10 -0
- package/dist/repl-v2.js +43 -2
- package/dist/ui/overlay/impl/agent-edit-overlay-v2.d.ts +105 -0
- package/dist/ui/overlay/impl/agent-edit-overlay-v2.js +364 -0
- package/dist/ui/overlay/impl/custom-agent-form-overlay-v2.d.ts +1 -8
- package/dist/ui/overlay/impl/custom-agent-form-overlay-v2.js +16 -120
- package/dist/ui/overlay/impl/project-edit-overlay-v2.d.ts +2 -1
- package/dist/ui/overlay/impl/project-edit-overlay-v2.js +26 -19
- package/dist/ui/overlay/impl/skills-overlay-v2.d.ts +42 -2
- package/dist/ui/overlay/impl/skills-overlay-v2.js +238 -185
- package/dist/ui/overlay/impl/team-overlay-v2.d.ts +1 -2
- package/dist/ui/overlay/impl/team-overlay-v2.js +6 -9
- package/dist/ui/terminal-types.d.ts +8 -0
- package/package.json +2 -2
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* Multi-step wizard for creating custom agents.
|
|
5
5
|
* Step 1: Basic Info (Agent ID, Display Name, Specialty, Personality)
|
|
6
6
|
* Step 2: Tool Profile (select profile or customize tool groups)
|
|
7
|
-
* Step 3: Skills (select which skills to enable)
|
|
8
7
|
* Step 4: Model Tier (select fast/balanced/powerful)
|
|
9
8
|
*/
|
|
10
9
|
import { BaseOverlayV2 } from '../../base/index.js';
|
|
@@ -20,7 +19,7 @@ interface FormField {
|
|
|
20
19
|
value: string;
|
|
21
20
|
error?: string;
|
|
22
21
|
}
|
|
23
|
-
type WizardStep = 'template-select' | 'basic' | 'tools' | '
|
|
22
|
+
type WizardStep = 'template-select' | 'basic' | 'tools' | 'tier' | 'prompt';
|
|
24
23
|
interface FormState {
|
|
25
24
|
fields: FormField[];
|
|
26
25
|
activeFieldIndex: number;
|
|
@@ -31,8 +30,6 @@ interface FormState {
|
|
|
31
30
|
profileListIndex: number;
|
|
32
31
|
groupListIndex: number;
|
|
33
32
|
inGroupSelection: boolean;
|
|
34
|
-
enabledSkills: Set<string>;
|
|
35
|
-
skillListIndex: number;
|
|
36
33
|
selectedModelTier: ModelTier;
|
|
37
34
|
tierListIndex: number;
|
|
38
35
|
systemPromptAddition: string;
|
|
@@ -67,7 +64,6 @@ export interface CustomAgentFormResult {
|
|
|
67
64
|
personality?: string;
|
|
68
65
|
systemPromptAddition?: string;
|
|
69
66
|
toolConfig: ToolConfig;
|
|
70
|
-
enabledSkills: string[];
|
|
71
67
|
modelTier: ModelTier;
|
|
72
68
|
};
|
|
73
69
|
}
|
|
@@ -84,12 +80,9 @@ export declare class CustomAgentFormOverlayV2 extends BaseOverlayV2<FormState, C
|
|
|
84
80
|
private renderBasicStep;
|
|
85
81
|
private renderToolsStep;
|
|
86
82
|
private renderGroupItem;
|
|
87
|
-
private renderSkillsStep;
|
|
88
|
-
private getAvailableTools;
|
|
89
83
|
handleKey(key: KeyEvent): OverlayAction<CustomAgentFormResult>;
|
|
90
84
|
private handleBasicStepKey;
|
|
91
85
|
private handleToolsStepKey;
|
|
92
|
-
private handleSkillsStepKey;
|
|
93
86
|
private renderTierStep;
|
|
94
87
|
private handleTierStepKey;
|
|
95
88
|
private renderPromptStep;
|
|
@@ -4,11 +4,10 @@
|
|
|
4
4
|
* Multi-step wizard for creating custom agents.
|
|
5
5
|
* Step 1: Basic Info (Agent ID, Display Name, Specialty, Personality)
|
|
6
6
|
* Step 2: Tool Profile (select profile or customize tool groups)
|
|
7
|
-
* Step 3: Skills (select which skills to enable)
|
|
8
7
|
* Step 4: Model Tier (select fast/balanced/powerful)
|
|
9
8
|
*/
|
|
10
9
|
import { BaseOverlayV2, renderBorder, wrapText } from '../../base/index.js';
|
|
11
|
-
import { validateAgentId, isAgentIdTaken, PREDEFINED_ROLE_IDS, TOOL_GROUPS, PROFILE_INFO, getGroupsByTier, createDefaultToolConfig,
|
|
10
|
+
import { validateAgentId, isAgentIdTaken, PREDEFINED_ROLE_IDS, TOOL_GROUPS, PROFILE_INFO, getGroupsByTier, createDefaultToolConfig, } from '@compilr-dev/sdk';
|
|
12
11
|
import { MODEL_TIERS, TIER_INFO } from '../../../models/index.js';
|
|
13
12
|
// Profile list for selection — derived from SDK's PROFILE_INFO
|
|
14
13
|
const PROFILE_LIST = Object.keys(PROFILE_INFO);
|
|
@@ -67,8 +66,6 @@ export class CustomAgentFormOverlayV2 extends BaseOverlayV2 {
|
|
|
67
66
|
profileListIndex: 0,
|
|
68
67
|
groupListIndex: 0,
|
|
69
68
|
inGroupSelection: false,
|
|
70
|
-
enabledSkills: new Set(),
|
|
71
|
-
skillListIndex: 0,
|
|
72
69
|
selectedModelTier: 'balanced',
|
|
73
70
|
tierListIndex: 1, // Default to balanced (index 1)
|
|
74
71
|
templateListIndex: 0,
|
|
@@ -89,8 +86,6 @@ export class CustomAgentFormOverlayV2 extends BaseOverlayV2 {
|
|
|
89
86
|
return this.renderBasicStep(context);
|
|
90
87
|
case 'tools':
|
|
91
88
|
return this.renderToolsStep(context);
|
|
92
|
-
case 'skills':
|
|
93
|
-
return this.renderSkillsStep(context);
|
|
94
89
|
case 'tier':
|
|
95
90
|
return this.renderTierStep(context);
|
|
96
91
|
case 'prompt':
|
|
@@ -187,7 +182,7 @@ export class CustomAgentFormOverlayV2 extends BaseOverlayV2 {
|
|
|
187
182
|
const border = renderBorder(context.width, s);
|
|
188
183
|
// Header with step indicator
|
|
189
184
|
lines.push(border);
|
|
190
|
-
lines.push(` ${s.primaryBold('Create Custom Agent')} ${s.muted('- Step 1/
|
|
185
|
+
lines.push(` ${s.primaryBold('Create Custom Agent')} ${s.muted('- Step 1/4: Basic Info')}`);
|
|
191
186
|
lines.push(border);
|
|
192
187
|
lines.push('');
|
|
193
188
|
// Render each field
|
|
@@ -239,7 +234,7 @@ export class CustomAgentFormOverlayV2 extends BaseOverlayV2 {
|
|
|
239
234
|
const border = renderBorder(context.width, s);
|
|
240
235
|
// Header
|
|
241
236
|
lines.push(border);
|
|
242
|
-
lines.push(` ${s.primaryBold('Create Custom Agent')} ${s.muted('- Step 2/
|
|
237
|
+
lines.push(` ${s.primaryBold('Create Custom Agent')} ${s.muted('- Step 2/4: Tool Profile')}`);
|
|
243
238
|
lines.push(border);
|
|
244
239
|
lines.push('');
|
|
245
240
|
if (!this.state.inGroupSelection) {
|
|
@@ -278,9 +273,15 @@ export class CustomAgentFormOverlayV2 extends BaseOverlayV2 {
|
|
|
278
273
|
const groupId = direct[i];
|
|
279
274
|
this.renderGroupItem(lines, groupId, i, s);
|
|
280
275
|
}
|
|
281
|
-
|
|
276
|
+
/*
|
|
277
|
+
The parenthetical used to read "(via use_tool)". That named an invocation mechanism
|
|
278
|
+
the person choosing tool groups cannot act on, and `use_tool` is not something they
|
|
279
|
+
will see in the agent's own tool list — the registry routes these transparently. The
|
|
280
|
+
section name already says which tier these belong to, so the mechanism is dropped
|
|
281
|
+
rather than restated.
|
|
282
|
+
*/
|
|
282
283
|
lines.push('');
|
|
283
|
-
lines.push(` ${s.muted('─── Meta-Registry Tools
|
|
284
|
+
lines.push(` ${s.muted('─── Meta-Registry Tools ───')}`);
|
|
284
285
|
for (let i = 0; i < meta.length; i++) {
|
|
285
286
|
const groupId = meta[i];
|
|
286
287
|
this.renderGroupItem(lines, groupId, direct.length + i, s);
|
|
@@ -302,48 +303,6 @@ export class CustomAgentFormOverlayV2 extends BaseOverlayV2 {
|
|
|
302
303
|
const readOnlyBadge = group.readOnly ? s.muted(' (read-only)') : '';
|
|
303
304
|
lines.push(` ${marker} ${labelStyle(group.label)}${readOnlyBadge}`);
|
|
304
305
|
}
|
|
305
|
-
renderSkillsStep(context) {
|
|
306
|
-
const s = context.styles;
|
|
307
|
-
const lines = [];
|
|
308
|
-
const border = renderBorder(context.width, s);
|
|
309
|
-
// Header
|
|
310
|
-
lines.push(border);
|
|
311
|
-
lines.push(` ${s.primaryBold('Create Custom Agent')} ${s.muted('- Step 3/5: Skills')}`);
|
|
312
|
-
lines.push(border);
|
|
313
|
-
lines.push('');
|
|
314
|
-
lines.push(` ${s.primary('Select skills to enable:')}`);
|
|
315
|
-
lines.push(` ${s.muted('(Leave empty for all skills, or select specific skills)')}`);
|
|
316
|
-
lines.push('');
|
|
317
|
-
// Get available tools for compatibility check
|
|
318
|
-
const availableTools = this.getAvailableTools();
|
|
319
|
-
const categories = getSkillsByCategory();
|
|
320
|
-
let globalIndex = 0;
|
|
321
|
-
for (const [category, skills] of Object.entries(categories)) {
|
|
322
|
-
lines.push(` ${s.muted(`─── ${category.charAt(0).toUpperCase() + category.slice(1)} ───`)}`);
|
|
323
|
-
for (const skillName of skills) {
|
|
324
|
-
const compatibility = checkSkillCompatibility(skillName, availableTools);
|
|
325
|
-
const isSelected = globalIndex === this.state.skillListIndex;
|
|
326
|
-
const isEnabled = this.state.enabledSkills.has(skillName);
|
|
327
|
-
const isCompatible = compatibility.compatible;
|
|
328
|
-
const marker = isEnabled ? s.success('[x]') : '[ ]';
|
|
329
|
-
const labelStyle = isSelected ? s.primaryBold : s.secondary;
|
|
330
|
-
// Soft warning for incompatible skills (not blocking)
|
|
331
|
-
const warningBadge = !isCompatible
|
|
332
|
-
? s.warning(` ⚠ may need: ${compatibility.missingRequired.slice(0, 2).join(', ')}${compatibility.missingRequired.length > 2 ? '...' : ''}`)
|
|
333
|
-
: '';
|
|
334
|
-
lines.push(` ${marker} ${labelStyle(skillName)}${warningBadge}`);
|
|
335
|
-
globalIndex++;
|
|
336
|
-
}
|
|
337
|
-
lines.push('');
|
|
338
|
-
}
|
|
339
|
-
lines.push(border);
|
|
340
|
-
lines.push(s.muted(' ↑/↓ Navigate Space Toggle a Toggle All Enter Next ← Back Esc Cancel'));
|
|
341
|
-
lines.push(border);
|
|
342
|
-
return lines;
|
|
343
|
-
}
|
|
344
|
-
getAvailableTools() {
|
|
345
|
-
return getToolsForProfile(this.state.selectedProfile, this.state.selectedProfile === 'custom' ? Array.from(this.state.customGroups) : undefined);
|
|
346
|
-
}
|
|
347
306
|
handleKey(key) {
|
|
348
307
|
// Escape - cancel
|
|
349
308
|
if (key.name === 'escape') {
|
|
@@ -360,8 +319,6 @@ export class CustomAgentFormOverlayV2 extends BaseOverlayV2 {
|
|
|
360
319
|
return this.handleBasicStepKey(key);
|
|
361
320
|
case 'tools':
|
|
362
321
|
return this.handleToolsStepKey(key);
|
|
363
|
-
case 'skills':
|
|
364
|
-
return this.handleSkillsStepKey(key);
|
|
365
322
|
case 'tier':
|
|
366
323
|
return this.handleTierStepKey(key);
|
|
367
324
|
case 'prompt':
|
|
@@ -495,8 +452,7 @@ export class CustomAgentFormOverlayV2 extends BaseOverlayV2 {
|
|
|
495
452
|
this.state.groupListIndex = 0;
|
|
496
453
|
}
|
|
497
454
|
else {
|
|
498
|
-
|
|
499
|
-
this.state.currentStep = 'skills';
|
|
455
|
+
this.state.currentStep = 'tier';
|
|
500
456
|
}
|
|
501
457
|
return this.rerender();
|
|
502
458
|
}
|
|
@@ -535,77 +491,19 @@ export class CustomAgentFormOverlayV2 extends BaseOverlayV2 {
|
|
|
535
491
|
// Don't proceed without any groups
|
|
536
492
|
return this.noAction();
|
|
537
493
|
}
|
|
538
|
-
|
|
539
|
-
this.state.currentStep = 'skills';
|
|
494
|
+
this.state.currentStep = 'tier';
|
|
540
495
|
return this.rerender();
|
|
541
496
|
}
|
|
542
497
|
}
|
|
543
498
|
return this.noAction();
|
|
544
499
|
}
|
|
545
|
-
handleSkillsStepKey(key) {
|
|
546
|
-
const skillNames = getDefinedSkillNames();
|
|
547
|
-
const totalSkills = skillNames.length;
|
|
548
|
-
// Left arrow - go back to tools step
|
|
549
|
-
if (key.name === 'left') {
|
|
550
|
-
this.state.currentStep = 'tools';
|
|
551
|
-
return this.rerender();
|
|
552
|
-
}
|
|
553
|
-
// Up/Down - navigate skills
|
|
554
|
-
if (key.name === 'up') {
|
|
555
|
-
if (this.state.skillListIndex > 0) {
|
|
556
|
-
this.state.skillListIndex--;
|
|
557
|
-
}
|
|
558
|
-
return this.rerender();
|
|
559
|
-
}
|
|
560
|
-
if (key.name === 'down') {
|
|
561
|
-
if (this.state.skillListIndex < totalSkills - 1) {
|
|
562
|
-
this.state.skillListIndex++;
|
|
563
|
-
}
|
|
564
|
-
return this.rerender();
|
|
565
|
-
}
|
|
566
|
-
// Space - toggle skill
|
|
567
|
-
if (key.name === 'space') {
|
|
568
|
-
const flatSkills = Object.values(getSkillsByCategory()).flat();
|
|
569
|
-
const skillName = flatSkills[this.state.skillListIndex];
|
|
570
|
-
// Allow toggling regardless of compatibility (soft warning only)
|
|
571
|
-
if (this.state.enabledSkills.has(skillName)) {
|
|
572
|
-
this.state.enabledSkills.delete(skillName);
|
|
573
|
-
}
|
|
574
|
-
else {
|
|
575
|
-
this.state.enabledSkills.add(skillName);
|
|
576
|
-
}
|
|
577
|
-
return this.rerender();
|
|
578
|
-
}
|
|
579
|
-
// 'a' - toggle all skills
|
|
580
|
-
if (key.char === 'a') {
|
|
581
|
-
const flatSkills = Object.values(getSkillsByCategory()).flat();
|
|
582
|
-
const allEnabled = flatSkills.every(skillName => this.state.enabledSkills.has(skillName));
|
|
583
|
-
if (allEnabled) {
|
|
584
|
-
// Clear all
|
|
585
|
-
this.state.enabledSkills.clear();
|
|
586
|
-
}
|
|
587
|
-
else {
|
|
588
|
-
// Enable all
|
|
589
|
-
for (const skillName of flatSkills) {
|
|
590
|
-
this.state.enabledSkills.add(skillName);
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
return this.rerender();
|
|
594
|
-
}
|
|
595
|
-
// Enter - go to tier step
|
|
596
|
-
if (key.name === 'return') {
|
|
597
|
-
this.state.currentStep = 'tier';
|
|
598
|
-
return this.rerender();
|
|
599
|
-
}
|
|
600
|
-
return this.noAction();
|
|
601
|
-
}
|
|
602
500
|
renderTierStep(context) {
|
|
603
501
|
const s = context.styles;
|
|
604
502
|
const lines = [];
|
|
605
503
|
const border = renderBorder(context.width, s);
|
|
606
504
|
// Header
|
|
607
505
|
lines.push(border);
|
|
608
|
-
lines.push(` ${s.primaryBold('Create Custom Agent')} ${s.muted('- Step 4
|
|
506
|
+
lines.push(` ${s.primaryBold('Create Custom Agent')} ${s.muted('- Step 3/4: Model Tier')}`);
|
|
609
507
|
lines.push(border);
|
|
610
508
|
lines.push('');
|
|
611
509
|
lines.push(` ${s.primary('Select the default model tier for this agent:')}`);
|
|
@@ -634,9 +532,9 @@ export class CustomAgentFormOverlayV2 extends BaseOverlayV2 {
|
|
|
634
532
|
return lines;
|
|
635
533
|
}
|
|
636
534
|
handleTierStepKey(key) {
|
|
637
|
-
// Left arrow - go back to
|
|
535
|
+
// Left arrow - go back to the tools step
|
|
638
536
|
if (key.name === 'left') {
|
|
639
|
-
this.state.currentStep = '
|
|
537
|
+
this.state.currentStep = 'tools';
|
|
640
538
|
return this.rerender();
|
|
641
539
|
}
|
|
642
540
|
// Up/Down - navigate tiers
|
|
@@ -818,7 +716,6 @@ export class CustomAgentFormOverlayV2 extends BaseOverlayV2 {
|
|
|
818
716
|
personality: getFieldValue('personality') || undefined,
|
|
819
717
|
systemPromptAddition: this.state.systemPromptAddition.trim() || undefined,
|
|
820
718
|
toolConfig: createDefaultToolConfig(),
|
|
821
|
-
enabledSkills: [],
|
|
822
719
|
modelTier: 'balanced', // Default tier
|
|
823
720
|
},
|
|
824
721
|
});
|
|
@@ -844,7 +741,6 @@ export class CustomAgentFormOverlayV2 extends BaseOverlayV2 {
|
|
|
844
741
|
personality: getFieldValue('personality') || undefined,
|
|
845
742
|
systemPromptAddition: this.state.systemPromptAddition.trim() || undefined,
|
|
846
743
|
toolConfig,
|
|
847
|
-
enabledSkills: Array.from(this.state.enabledSkills),
|
|
848
744
|
modelTier: this.state.selectedModelTier,
|
|
849
745
|
},
|
|
850
746
|
});
|
|
@@ -7,8 +7,9 @@
|
|
|
7
7
|
import { BaseOverlayV2 } from '../../base/index.js';
|
|
8
8
|
import type { RenderContext, OverlayAction, KeyEvent } from '../types.js';
|
|
9
9
|
import { type Project } from '../../../db/repositories/index.js';
|
|
10
|
+
import { type ProjectPatch } from '@compilr-dev/sdk';
|
|
10
11
|
interface EditableField {
|
|
11
|
-
key:
|
|
12
|
+
key: keyof ProjectPatch;
|
|
12
13
|
label: string;
|
|
13
14
|
value: string;
|
|
14
15
|
placeholder?: string;
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { BaseOverlayV2, renderBorder } from '../../base/index.js';
|
|
8
8
|
import { projectRepository } from '../../../db/repositories/index.js';
|
|
9
9
|
import * as terminal from '../../terminal.js';
|
|
10
|
+
import { buildProjectUpdate } from '@compilr-dev/sdk';
|
|
10
11
|
// =============================================================================
|
|
11
12
|
// Status Labels
|
|
12
13
|
// =============================================================================
|
|
@@ -25,10 +26,21 @@ export class ProjectEditOverlayV2 extends BaseOverlayV2 {
|
|
|
25
26
|
constructor(project) {
|
|
26
27
|
super({
|
|
27
28
|
project,
|
|
29
|
+
/*
|
|
30
|
+
⚠️ THE SAME FIELDS DESKTOP EDITS (Phase 5 parity). This carried five; Desktop's document
|
|
31
|
+
carried eleven, so a project edited in the app showed a language and a framework the
|
|
32
|
+
terminal could neither see nor change. Parity is on the DATA MODEL — the presentation stays
|
|
33
|
+
a field list, because a terminal has no document.
|
|
34
|
+
*/
|
|
28
35
|
fields: [
|
|
29
36
|
{ key: 'displayName', label: 'Display Name', value: project.displayName, placeholder: 'Project display name' },
|
|
30
37
|
{ key: 'description', label: 'Description', value: project.description || '', placeholder: 'Brief description' },
|
|
31
38
|
{ key: 'path', label: 'Path', value: project.path || '', placeholder: '/path/to/project' },
|
|
39
|
+
{ key: 'docsPath', label: 'Docs Path', value: project.docsPath || '', placeholder: 'defaults to the project folder' },
|
|
40
|
+
{ key: 'language', label: 'Language', value: project.language || '', placeholder: 'TypeScript' },
|
|
41
|
+
{ key: 'framework', label: 'Framework', value: project.framework || '', placeholder: 'React' },
|
|
42
|
+
{ key: 'packageManager', label: 'Package Manager', value: project.packageManager || '', placeholder: 'npm' },
|
|
43
|
+
{ key: 'runtimeVersion', label: 'Runtime', value: project.runtimeVersion || '', placeholder: '22' },
|
|
32
44
|
{ key: 'gitRemote', label: 'Git Remote', value: project.gitRemote || '', placeholder: 'https://github.com/...' },
|
|
33
45
|
{ key: 'gitBranch', label: 'Git Branch', value: project.gitBranch || '', placeholder: 'main' },
|
|
34
46
|
],
|
|
@@ -163,28 +175,23 @@ export class ProjectEditOverlayV2 extends BaseOverlayV2 {
|
|
|
163
175
|
return this.noAction();
|
|
164
176
|
}
|
|
165
177
|
saveAndClose() {
|
|
166
|
-
|
|
167
|
-
|
|
178
|
+
/*
|
|
179
|
+
⚠️ THE SDK'S MAPPING, NOT A SECOND ONE. This used to hand-write its own snake_case mapping,
|
|
180
|
+
and it had drifted from Desktop's: `field.value || undefined` turned an empty string into
|
|
181
|
+
"leave alone", so a git remote could be SET here but never CLEARED. An empty field now means
|
|
182
|
+
what it looks like it means.
|
|
183
|
+
*/
|
|
184
|
+
const patch = {};
|
|
168
185
|
for (const field of this.state.fields) {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
else if (field.key === 'gitRemote') {
|
|
176
|
-
updates.git_remote = field.value || undefined;
|
|
177
|
-
}
|
|
178
|
-
else if (field.key === 'gitBranch') {
|
|
179
|
-
updates.git_branch = field.value || undefined;
|
|
180
|
-
}
|
|
181
|
-
else {
|
|
182
|
-
// field.key === 'path'
|
|
183
|
-
updates.path = field.value || undefined;
|
|
184
|
-
}
|
|
186
|
+
patch[field.key] = field.value;
|
|
187
|
+
}
|
|
188
|
+
const built = buildProjectUpdate(patch);
|
|
189
|
+
if (!built.ok) {
|
|
190
|
+
this.state.error = built.error;
|
|
191
|
+
return this.rerender();
|
|
185
192
|
}
|
|
186
193
|
try {
|
|
187
|
-
projectRepository.update(this.state.project.id,
|
|
194
|
+
projectRepository.update(this.state.project.id, built.input);
|
|
188
195
|
return this.close({ saved: true, projectId: this.state.project.id });
|
|
189
196
|
}
|
|
190
197
|
catch (err) {
|
|
@@ -15,14 +15,21 @@
|
|
|
15
15
|
* Spec: project-docs/00-requirements/compilr-dev-cli/skills-overlay-spec.md
|
|
16
16
|
*/
|
|
17
17
|
import { TabbedListOverlayV2, BaseScreen } from '../../base/index.js';
|
|
18
|
-
import { type CustomSkill } from '@compilr-dev/sdk';
|
|
18
|
+
import { type SkillReachability, type CustomSkill } from '@compilr-dev/sdk';
|
|
19
19
|
import { type SkillScope } from '../../../utils/skill-paths.js';
|
|
20
20
|
/** Unified item for the list — custom skills have full data, built-in have name+description only */
|
|
21
21
|
interface SkillItem {
|
|
22
22
|
name: string;
|
|
23
23
|
description: string;
|
|
24
24
|
scope: 'project' | 'user' | 'sdk' | 'binding';
|
|
25
|
-
|
|
25
|
+
/**
|
|
26
|
+
* ⚠️ THE TWO ANTHROPIC SWITCHES, NOT `enabled`. This used to be `skill.enabled !== false`, and
|
|
27
|
+
* `enabled` is not part of the format — zero of 50 Anthropic-authored skills carry it. A skill
|
|
28
|
+
* shelved in Desktop writes `user-invocable: false` and no `enabled` key at all, so the old
|
|
29
|
+
* expression read it back as ON: the CLI showed a shelved skill as live, and the resolver (which
|
|
30
|
+
* already uses skillReachability) disagreed with the list in front of the user.
|
|
31
|
+
*/
|
|
32
|
+
reach: SkillReachability;
|
|
26
33
|
/** Validation issues (empty = valid) */
|
|
27
34
|
issues: string[];
|
|
28
35
|
/** Full CustomSkill data (null for built-in) */
|
|
@@ -45,17 +52,38 @@ interface SkillItem {
|
|
|
45
52
|
export interface SkillsOverlayV2Options {
|
|
46
53
|
/** Project root path (for project-scoped skills) */
|
|
47
54
|
projectPath?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Extra prompt sources, supplied by the app layer because that is where they are configured.
|
|
57
|
+
* The same set passed to the resolver, so this tab and `getSkillPrompt` cannot disagree
|
|
58
|
+
* about what exists.
|
|
59
|
+
*/
|
|
60
|
+
skillSources?: import('@compilr-dev/sdk').SkillSources;
|
|
48
61
|
/** Callback to open the skill detail overlay (view/edit/diff). Returns true if modified. */
|
|
49
62
|
onOpenDetail?: (filePath: string, skillName: string, scope: string, forkedFrom?: import('@compilr-dev/sdk').ForkedFromMarker, boundCommands?: string[]) => Promise<boolean>;
|
|
50
63
|
}
|
|
51
64
|
export interface SkillsOverlayV2Result {
|
|
52
65
|
dismissed: boolean;
|
|
53
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* The shipped macros this tab offers.
|
|
69
|
+
*
|
|
70
|
+
* ⚠️ IT USED TO OFFER EIGHT IT CANNOT RUN. This walked `platformMacros` directly and added every
|
|
71
|
+
* one, including the canvas family — which `getSkillPrompt` REFUSES, because a terminal cannot
|
|
72
|
+
* draw a canvas. So the Built-in tab listed `canvas`, `infographic`, `carousel`, `board`,
|
|
73
|
+
* `canvas-styles` and the three reference ones, and selecting any of them got nothing. That is
|
|
74
|
+
* the same "offered, then answers Unknown command" defect the CLI had already fixed for
|
|
75
|
+
* disabled skills, in a second place nobody checked.
|
|
76
|
+
*
|
|
77
|
+
* It now asks the SDK, declaring what this host can render. The resolver's refusal and this
|
|
78
|
+
* list are therefore two consequences of one rule rather than two rules that can disagree.
|
|
79
|
+
*/
|
|
80
|
+
export declare function loadBuiltinMacros(projectPath?: string, sources?: import('@compilr-dev/sdk').SkillSources): SkillItem[];
|
|
54
81
|
export declare class SkillsOverlayV2 extends TabbedListOverlayV2<SkillItem, SkillsOverlayV2Result> {
|
|
55
82
|
readonly type: "inline";
|
|
56
83
|
readonly id = "skills-overlay-v2";
|
|
57
84
|
private allItems;
|
|
58
85
|
private readonly projectPath?;
|
|
86
|
+
private readonly skillSources?;
|
|
59
87
|
private readonly onOpenDetail?;
|
|
60
88
|
constructor(options: SkillsOverlayV2Options);
|
|
61
89
|
/**
|
|
@@ -73,6 +101,18 @@ export declare class SkillsOverlayV2 extends TabbedListOverlayV2<SkillItem, Skil
|
|
|
73
101
|
pushScreen?: BaseScreen;
|
|
74
102
|
};
|
|
75
103
|
private createSkill;
|
|
104
|
+
/**
|
|
105
|
+
* Shelve a skill, or bring it back.
|
|
106
|
+
*
|
|
107
|
+
* ⚠️ WRITES THE TWO ANTHROPIC SWITCHES AND REMOVES THE LEGACY KEY (D-1), THROUGH THE SDK'S
|
|
108
|
+
* PATCHER RATHER THAN A REGEX (D-2). The old version rewrote frontmatter line by line, which
|
|
109
|
+
* destroys comments — measured on our own template: 17 lines to 7, all 9 comment lines to 0.
|
|
110
|
+
*
|
|
111
|
+
* One key for two switches is lossy by construction: a skill set to "agents only" in Desktop is
|
|
112
|
+
* shelved and then restored to BOTH. That is why the list renders the real state beside the name
|
|
113
|
+
* — the flattening is visible, not silent — and why the two-switch editor lives in the host that
|
|
114
|
+
* has a document to put it in.
|
|
115
|
+
*/
|
|
76
116
|
private toggleSkill;
|
|
77
117
|
private deleteSkill;
|
|
78
118
|
private renameSkill;
|