@compilr-dev/cli 0.6.0 → 0.6.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/.tsbuildinfo.app +1 -1
- package/dist/.tsbuildinfo.data +1 -1
- package/dist/.tsbuildinfo.domain +1 -1
- package/dist/agent.d.ts +2 -0
- package/dist/agent.js +66 -1
- package/dist/commands-v2/handlers/project.d.ts +1 -0
- package/dist/commands-v2/handlers/project.js +36 -2
- package/dist/commands-v2/handlers/team.js +23 -3
- package/dist/compilr-diff-companion.vsix +0 -0
- package/dist/entitlements/index.d.ts +23 -0
- package/dist/entitlements/index.js +110 -0
- package/dist/guide/cli-guide-entries.d.ts +15 -0
- package/dist/guide/cli-guide-entries.js +99 -0
- package/dist/guide/index.d.ts +5 -4
- package/dist/guide/index.js +4 -3
- package/dist/guide/shared-content.js +188 -21
- package/dist/handlers/permission-handler.js +10 -3
- package/dist/index.js +18 -0
- package/dist/repl-v2.d.ts +16 -0
- package/dist/repl-v2.js +51 -17
- package/dist/tools/db-tools.d.ts +1 -1
- package/dist/tools/platform-adapter.d.ts +1 -1
- package/dist/tools/platform-adapter.js +6 -1
- package/dist/tools.js +6 -1
- package/dist/ui/overlay/impl/app-model-overlay-v2.d.ts +57 -0
- package/dist/ui/overlay/impl/app-model-overlay-v2.js +232 -0
- package/dist/ui/overlay/impl/custom-agent-form-overlay-v2.d.ts +23 -1
- package/dist/ui/overlay/impl/custom-agent-form-overlay-v2.js +203 -47
- package/dist/ui/overlay/impl/model-overlay-v2.js +2 -2
- package/dist/ui/overlay/impl/new-overlay-v2.d.ts +2 -2
- package/dist/ui/overlay/impl/new-overlay-v2.js +10 -17
- package/dist/ui/overlay/impl/team-overlay-v2.js +2 -2
- package/dist/ui/overlay/index.d.ts +1 -0
- package/dist/ui/overlay/index.js +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App Model Overlay V2
|
|
3
|
+
*
|
|
4
|
+
* Terminal visualization of the ApplicationModel (from @compilr-dev/factory).
|
|
5
|
+
* Three tabs: Entities (list with detail), Relationships (map), Summary (stats).
|
|
6
|
+
*
|
|
7
|
+
* Not a replacement for the desktop SVG viewer — text-based tables and lists
|
|
8
|
+
* for CLI users who want to inspect the model structure.
|
|
9
|
+
*/
|
|
10
|
+
import * as terminal from '../../terminal.js';
|
|
11
|
+
import { TabbedListOverlayV2, BaseScreen, stay, popScreen, isEscape, isCtrlC, isClose, renderBorder, wrapText, truncate, } from '../../base/index.js';
|
|
12
|
+
import { parseKeyEvent } from '../key-utils.js';
|
|
13
|
+
// =============================================================================
|
|
14
|
+
// Tab Definitions
|
|
15
|
+
// =============================================================================
|
|
16
|
+
const MODEL_TABS = [
|
|
17
|
+
{ id: 'entities', label: 'Entities' },
|
|
18
|
+
{ id: 'relationships', label: 'Relationships' },
|
|
19
|
+
{ id: 'summary', label: 'Summary' },
|
|
20
|
+
];
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// Main Overlay
|
|
23
|
+
// =============================================================================
|
|
24
|
+
export class AppModelOverlayV2 extends TabbedListOverlayV2 {
|
|
25
|
+
type = 'inline';
|
|
26
|
+
id = 'app-model-viewer';
|
|
27
|
+
model = null;
|
|
28
|
+
parseError = null;
|
|
29
|
+
constructor(options) {
|
|
30
|
+
// Parse model and build list items
|
|
31
|
+
let model = null;
|
|
32
|
+
let parseError = null;
|
|
33
|
+
let items = [];
|
|
34
|
+
try {
|
|
35
|
+
model = JSON.parse(options.modelJson);
|
|
36
|
+
items = buildListItems(model);
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
parseError = `Failed to parse model: ${e instanceof Error ? e.message : String(e)}`;
|
|
40
|
+
}
|
|
41
|
+
// Compute column widths for aligned rendering
|
|
42
|
+
const maxEntityName = model
|
|
43
|
+
? Math.max(8, ...model.entities.map((e) => e.name.length))
|
|
44
|
+
: 12;
|
|
45
|
+
const maxRelLabel = items
|
|
46
|
+
.filter((i) => i.tab === 'relationships')
|
|
47
|
+
.reduce((max, i) => Math.max(max, i.label.length), 12);
|
|
48
|
+
const maxSummaryLabel = items
|
|
49
|
+
.filter((i) => i.tab === 'summary')
|
|
50
|
+
.reduce((max, i) => Math.max(max, i.label.length), 12);
|
|
51
|
+
super({
|
|
52
|
+
title: `Application Model — ${options.projectName}`,
|
|
53
|
+
tabs: MODEL_TABS,
|
|
54
|
+
items,
|
|
55
|
+
pageSize: 15,
|
|
56
|
+
filterByTab: (item, tabId) => tabId === 'all' || item.tab === tabId,
|
|
57
|
+
getSearchText: (item) => `${item.label} ${item.detail}`,
|
|
58
|
+
renderItem: (item, isSelected, s) => {
|
|
59
|
+
const prefix = isSelected ? s.primary('›') : ' ';
|
|
60
|
+
if (item.tab === 'entities') {
|
|
61
|
+
const entity = item.entity;
|
|
62
|
+
const fields = entity ? String(entity.fields.length).padStart(2) : ' 0';
|
|
63
|
+
const rels = entity ? String(entity.relationships.length) : '0';
|
|
64
|
+
const name = item.label.padEnd(maxEntityName + 2);
|
|
65
|
+
const desc = entity?.description ? s.muted(truncate(entity.description, 30)) : '';
|
|
66
|
+
return `${prefix} ${isSelected ? s.primary(name) : name} ${s.secondary(`${fields} fields · ${rels} rels`)} ${desc}`;
|
|
67
|
+
}
|
|
68
|
+
if (item.tab === 'relationships') {
|
|
69
|
+
const label = item.label.padEnd(maxRelLabel + 2);
|
|
70
|
+
return `${prefix} ${isSelected ? s.primary(label) : label} ${s.secondary(item.detail)}`;
|
|
71
|
+
}
|
|
72
|
+
// summary
|
|
73
|
+
const label = (item.label + ':').padEnd(maxSummaryLabel + 3);
|
|
74
|
+
return `${prefix} ${s.secondary(label)} ${isSelected ? s.primary(item.detail) : item.detail}`;
|
|
75
|
+
},
|
|
76
|
+
footerHints: () => '↑↓ Navigate · Enter Detail · Tab/← → Tabs · / Search · q Close',
|
|
77
|
+
});
|
|
78
|
+
this.model = model;
|
|
79
|
+
this.parseError = parseError;
|
|
80
|
+
}
|
|
81
|
+
createDetailScreen(item) {
|
|
82
|
+
if (item.entity) {
|
|
83
|
+
return new EntityDetailScreen(item.entity, this.getStyles());
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// =============================================================================
|
|
89
|
+
// Entity Detail Screen
|
|
90
|
+
// =============================================================================
|
|
91
|
+
class EntityDetailScreen extends BaseScreen {
|
|
92
|
+
entity;
|
|
93
|
+
styles;
|
|
94
|
+
scrollOffset = 0;
|
|
95
|
+
constructor(entity, styles) {
|
|
96
|
+
super();
|
|
97
|
+
this.entity = entity;
|
|
98
|
+
this.styles = styles;
|
|
99
|
+
}
|
|
100
|
+
render() {
|
|
101
|
+
const s = this.styles;
|
|
102
|
+
const cols = terminal.getTerminalWidth();
|
|
103
|
+
const e = this.entity;
|
|
104
|
+
const lines = [];
|
|
105
|
+
// Header
|
|
106
|
+
lines.push(renderBorder(cols, s));
|
|
107
|
+
lines.push(` ${s.primaryBold(e.name)}`);
|
|
108
|
+
lines.push('');
|
|
109
|
+
if (e.description) {
|
|
110
|
+
for (const wrapped of wrapText(e.description, cols - 6)) {
|
|
111
|
+
lines.push(` ${s.secondary(wrapped)}`);
|
|
112
|
+
}
|
|
113
|
+
lines.push('');
|
|
114
|
+
}
|
|
115
|
+
// Info line
|
|
116
|
+
lines.push(` ${s.muted('Plural:')} ${e.pluralName} ${s.muted('Views:')} ${e.views.join(', ')}`);
|
|
117
|
+
lines.push('');
|
|
118
|
+
// Fields table
|
|
119
|
+
lines.push(` ${s.primaryBold('Fields')} ${s.muted(`(${String(e.fields.length)})`)}`);
|
|
120
|
+
lines.push(` ${s.muted('─'.repeat(Math.min(cols - 4, 60)))}`);
|
|
121
|
+
const nameWidth = Math.max(12, ...e.fields.map((f) => f.name.length)) + 1;
|
|
122
|
+
for (const field of e.fields) {
|
|
123
|
+
const name = field.name.padEnd(nameWidth);
|
|
124
|
+
const type = field.type.padEnd(10);
|
|
125
|
+
const req = field.required ? s.primary('*') : ' ';
|
|
126
|
+
const enums = field.enumValues ? s.muted(` [${field.enumValues.join(', ')}]`) : '';
|
|
127
|
+
const def = field.defaultValue !== undefined ? s.muted(` = ${String(field.defaultValue)}`) : '';
|
|
128
|
+
lines.push(` ${req} ${name} ${s.secondary(type)}${enums}${def}`);
|
|
129
|
+
}
|
|
130
|
+
// Relationships
|
|
131
|
+
if (e.relationships.length > 0) {
|
|
132
|
+
lines.push('');
|
|
133
|
+
lines.push(` ${s.primaryBold('Relationships')} ${s.muted(`(${String(e.relationships.length)})`)}`);
|
|
134
|
+
lines.push(` ${s.muted('─'.repeat(Math.min(cols - 4, 60)))}`);
|
|
135
|
+
for (const rel of e.relationships) {
|
|
136
|
+
const arrow = rel.type === 'hasMany' ? '──▸' : '◂──';
|
|
137
|
+
const label = rel.type === 'hasMany' ? 'has many' : 'belongs to';
|
|
138
|
+
const via = rel.fieldName ? s.muted(` via ${rel.fieldName}`) : '';
|
|
139
|
+
lines.push(` ${e.name} ${arrow} ${s.primary(rel.target)} ${s.muted(label)}${via}`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
lines.push('');
|
|
143
|
+
lines.push(` ${s.muted('↑↓ Scroll · Esc Back')}`);
|
|
144
|
+
lines.push(renderBorder(cols, s));
|
|
145
|
+
return lines;
|
|
146
|
+
}
|
|
147
|
+
handleKey(data) {
|
|
148
|
+
if (isEscape(data) || isCtrlC(data) || isClose(data)) {
|
|
149
|
+
return popScreen();
|
|
150
|
+
}
|
|
151
|
+
const key = parseKeyEvent(data);
|
|
152
|
+
if (key.name === 'up' && this.scrollOffset > 0) {
|
|
153
|
+
this.scrollOffset--;
|
|
154
|
+
return stay();
|
|
155
|
+
}
|
|
156
|
+
if (key.name === 'down') {
|
|
157
|
+
this.scrollOffset++;
|
|
158
|
+
return stay();
|
|
159
|
+
}
|
|
160
|
+
return stay();
|
|
161
|
+
}
|
|
162
|
+
getMinHeight() {
|
|
163
|
+
return 15;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// =============================================================================
|
|
167
|
+
// Build list items from model
|
|
168
|
+
// =============================================================================
|
|
169
|
+
function buildListItems(model) {
|
|
170
|
+
const items = [];
|
|
171
|
+
// Entity items
|
|
172
|
+
for (const entity of model.entities) {
|
|
173
|
+
items.push({
|
|
174
|
+
id: `entity-${entity.name}`,
|
|
175
|
+
tab: 'entities',
|
|
176
|
+
label: entity.name,
|
|
177
|
+
detail: `${String(entity.fields.length)} fields, ${String(entity.relationships.length)} relationships`,
|
|
178
|
+
entity,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
// Relationship items (flattened from all entities)
|
|
182
|
+
for (const entity of model.entities) {
|
|
183
|
+
for (const rel of entity.relationships) {
|
|
184
|
+
const arrow = rel.type === 'hasMany' ? '→' : '←';
|
|
185
|
+
items.push({
|
|
186
|
+
id: `rel-${entity.name}-${rel.target}-${rel.type}`,
|
|
187
|
+
tab: 'relationships',
|
|
188
|
+
label: `${entity.name} ${arrow} ${rel.target}`,
|
|
189
|
+
detail: rel.type === 'hasMany' ? `has many ${rel.target}` : `belongs to ${rel.target}`,
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Summary items
|
|
194
|
+
const totalFields = model.entities.reduce((sum, e) => sum + e.fields.length, 0);
|
|
195
|
+
const totalRels = model.entities.reduce((sum, e) => sum + e.relationships.length, 0);
|
|
196
|
+
const requiredFields = model.entities.reduce((sum, e) => sum + e.fields.filter((f) => f.required).length, 0);
|
|
197
|
+
const enumFields = model.entities.reduce((sum, e) => sum + e.fields.filter((f) => f.type === 'enum').length, 0);
|
|
198
|
+
// Identity
|
|
199
|
+
items.push({ id: 'sum-name', tab: 'summary', label: 'Application', detail: model.identity.name }, { id: 'sum-desc', tab: 'summary', label: 'Description', detail: truncate(model.identity.description, 60) }, { id: 'sum-version', tab: 'summary', label: 'Version', detail: model.identity.version });
|
|
200
|
+
// Data model stats
|
|
201
|
+
items.push({ id: 'sum-sep1', tab: 'summary', label: '── Data Model', detail: '' }, { id: 'sum-entities', tab: 'summary', label: 'Entities', detail: String(model.entities.length) }, { id: 'sum-fields', tab: 'summary', label: 'Total Fields', detail: `${String(totalFields)} (${String(requiredFields)} required, ${String(enumFields)} enums)` }, { id: 'sum-rels', tab: 'summary', label: 'Relationships', detail: String(totalRels) });
|
|
202
|
+
// Configuration
|
|
203
|
+
const configItems = [];
|
|
204
|
+
if (model.layout?.shell) {
|
|
205
|
+
configItems.push({ id: 'sum-layout', tab: 'summary', label: 'Layout', detail: model.layout.shell });
|
|
206
|
+
}
|
|
207
|
+
if (model.techStack?.toolkit) {
|
|
208
|
+
configItems.push({ id: 'sum-toolkit', tab: 'summary', label: 'Toolkit', detail: model.techStack.toolkit });
|
|
209
|
+
}
|
|
210
|
+
if (model.theme?.primaryColor) {
|
|
211
|
+
configItems.push({ id: 'sum-color', tab: 'summary', label: 'Primary Color', detail: model.theme.primaryColor });
|
|
212
|
+
}
|
|
213
|
+
const featureList = [];
|
|
214
|
+
if (model.features?.dashboard)
|
|
215
|
+
featureList.push('Dashboard');
|
|
216
|
+
if (model.features?.auth)
|
|
217
|
+
featureList.push('Auth');
|
|
218
|
+
if (model.features?.userProfiles)
|
|
219
|
+
featureList.push('Profiles');
|
|
220
|
+
if (model.features?.settings)
|
|
221
|
+
featureList.push('Settings');
|
|
222
|
+
if (model.features?.darkMode)
|
|
223
|
+
featureList.push('Dark Mode');
|
|
224
|
+
if (featureList.length > 0) {
|
|
225
|
+
configItems.push({ id: 'sum-features', tab: 'summary', label: 'Features', detail: featureList.join(', ') });
|
|
226
|
+
}
|
|
227
|
+
if (configItems.length > 0) {
|
|
228
|
+
items.push({ id: 'sum-sep2', tab: 'summary', label: '── Configuration', detail: '' });
|
|
229
|
+
items.push(...configItems);
|
|
230
|
+
}
|
|
231
|
+
return items;
|
|
232
|
+
}
|
|
@@ -20,7 +20,7 @@ interface FormField {
|
|
|
20
20
|
value: string;
|
|
21
21
|
error?: string;
|
|
22
22
|
}
|
|
23
|
-
type WizardStep = 'basic' | 'tools' | 'skills' | 'tier';
|
|
23
|
+
type WizardStep = 'template-select' | 'basic' | 'tools' | 'skills' | 'tier' | 'prompt';
|
|
24
24
|
interface FormState {
|
|
25
25
|
fields: FormField[];
|
|
26
26
|
activeFieldIndex: number;
|
|
@@ -35,20 +35,37 @@ interface FormState {
|
|
|
35
35
|
skillListIndex: number;
|
|
36
36
|
selectedModelTier: ModelTier;
|
|
37
37
|
tierListIndex: number;
|
|
38
|
+
systemPromptAddition: string;
|
|
39
|
+
templateListIndex: number;
|
|
40
|
+
saveAsTemplate: boolean;
|
|
41
|
+
templateName: string;
|
|
42
|
+
}
|
|
43
|
+
export interface TemplateOption {
|
|
44
|
+
id: string;
|
|
45
|
+
name: string;
|
|
46
|
+
displayName: string;
|
|
47
|
+
specialty: string;
|
|
48
|
+
personality?: string;
|
|
49
|
+
systemPromptAddition?: string;
|
|
38
50
|
}
|
|
39
51
|
export interface CustomAgentFormOptions {
|
|
40
52
|
/** Existing custom agents (for duplicate check) */
|
|
41
53
|
existingCustomAgents: CustomAgentDefinition[];
|
|
42
54
|
/** Current team agent IDs (for duplicate check) */
|
|
43
55
|
teamAgentIds: string[];
|
|
56
|
+
/** Available templates to load from */
|
|
57
|
+
templates?: TemplateOption[];
|
|
44
58
|
}
|
|
45
59
|
export interface CustomAgentFormResult {
|
|
46
60
|
cancelled: boolean;
|
|
61
|
+
/** Template name to save as (if user requested) */
|
|
62
|
+
saveAsTemplate?: string;
|
|
47
63
|
agent?: {
|
|
48
64
|
id: string;
|
|
49
65
|
displayName: string;
|
|
50
66
|
specialty: string;
|
|
51
67
|
personality?: string;
|
|
68
|
+
systemPromptAddition?: string;
|
|
52
69
|
toolConfig: ToolConfig;
|
|
53
70
|
enabledSkills: string[];
|
|
54
71
|
modelTier: ModelTier;
|
|
@@ -59,8 +76,11 @@ export declare class CustomAgentFormOverlayV2 extends BaseOverlayV2<FormState, C
|
|
|
59
76
|
readonly id = "custom-agent-form-overlay-v2";
|
|
60
77
|
private readonly existingCustomAgents;
|
|
61
78
|
private readonly teamAgentIds;
|
|
79
|
+
private readonly templates;
|
|
62
80
|
constructor(options: CustomAgentFormOptions);
|
|
63
81
|
protected renderContent(context: RenderContext): string[];
|
|
82
|
+
private renderTemplateSelectStep;
|
|
83
|
+
private handleTemplateSelectKey;
|
|
64
84
|
private renderBasicStep;
|
|
65
85
|
private renderToolsStep;
|
|
66
86
|
private renderGroupItem;
|
|
@@ -72,6 +92,8 @@ export declare class CustomAgentFormOverlayV2 extends BaseOverlayV2<FormState, C
|
|
|
72
92
|
private handleSkillsStepKey;
|
|
73
93
|
private renderTierStep;
|
|
74
94
|
private handleTierStepKey;
|
|
95
|
+
private renderPromptStep;
|
|
96
|
+
private handlePromptStepKey;
|
|
75
97
|
private nextField;
|
|
76
98
|
private prevField;
|
|
77
99
|
private validateBasicInfo;
|