@hale-bopp/valentino-engine 2.2.0 → 2.3.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 (82) hide show
  1. package/README.md +61 -0
  2. package/dist/bin/commands/cockpit.d.ts +16 -0
  3. package/dist/bin/commands/cockpit.d.ts.map +1 -0
  4. package/dist/bin/commands/cockpit.js +205 -0
  5. package/dist/bin/commands/cockpit.js.map +1 -0
  6. package/dist/bin/commands/theme-audit.d.ts +7 -0
  7. package/dist/bin/commands/theme-audit.d.ts.map +1 -0
  8. package/dist/bin/commands/theme-audit.js +70 -0
  9. package/dist/bin/commands/theme-audit.js.map +1 -0
  10. package/dist/bin/commands/validate.d.ts.map +1 -1
  11. package/dist/bin/commands/validate.js +94 -1
  12. package/dist/bin/commands/validate.js.map +1 -1
  13. package/dist/bin/valentino.js +14 -0
  14. package/dist/bin/valentino.js.map +1 -1
  15. package/dist/cockpit-server.d.ts +17 -0
  16. package/dist/cockpit-server.d.ts.map +1 -0
  17. package/dist/cockpit-server.js +505 -0
  18. package/dist/cockpit-server.js.map +1 -0
  19. package/dist/cockpit-web/index.html +979 -0
  20. package/dist/core/cockpit-api.d.ts +99 -0
  21. package/dist/core/cockpit-api.d.ts.map +1 -0
  22. package/dist/core/cockpit-api.js +269 -0
  23. package/dist/core/cockpit-api.js.map +1 -0
  24. package/dist/core/cockpit-repl.d.ts +51 -0
  25. package/dist/core/cockpit-repl.d.ts.map +1 -0
  26. package/dist/core/cockpit-repl.js +217 -0
  27. package/dist/core/cockpit-repl.js.map +1 -0
  28. package/dist/core/contrast-usage-probe.d.ts +84 -0
  29. package/dist/core/contrast-usage-probe.d.ts.map +1 -0
  30. package/dist/core/contrast-usage-probe.js +244 -0
  31. package/dist/core/contrast-usage-probe.js.map +1 -0
  32. package/dist/core/contrast-usage-probe.test.d.ts +2 -0
  33. package/dist/core/contrast-usage-probe.test.d.ts.map +1 -0
  34. package/dist/core/contrast-usage-probe.test.js +186 -0
  35. package/dist/core/contrast-usage-probe.test.js.map +1 -0
  36. package/dist/core/intent-parser.d.ts +67 -0
  37. package/dist/core/intent-parser.d.ts.map +1 -0
  38. package/dist/core/intent-parser.js +485 -0
  39. package/dist/core/intent-parser.js.map +1 -0
  40. package/dist/core/openrouter-client.d.ts +38 -0
  41. package/dist/core/openrouter-client.d.ts.map +1 -0
  42. package/dist/core/openrouter-client.js +123 -0
  43. package/dist/core/openrouter-client.js.map +1 -0
  44. package/dist/core/page-status.d.ts +15 -1
  45. package/dist/core/page-status.d.ts.map +1 -1
  46. package/dist/core/page-status.js +21 -0
  47. package/dist/core/page-status.js.map +1 -1
  48. package/dist/core/project-adapter.d.ts +73 -0
  49. package/dist/core/project-adapter.d.ts.map +1 -0
  50. package/dist/core/project-adapter.js +364 -0
  51. package/dist/core/project-adapter.js.map +1 -0
  52. package/dist/core/schema-export.d.ts +32 -0
  53. package/dist/core/schema-export.d.ts.map +1 -0
  54. package/dist/core/schema-export.js +493 -0
  55. package/dist/core/schema-export.js.map +1 -0
  56. package/dist/core/theme-audit.d.ts +104 -0
  57. package/dist/core/theme-audit.d.ts.map +1 -0
  58. package/dist/core/theme-audit.js +127 -0
  59. package/dist/core/theme-audit.js.map +1 -0
  60. package/dist/core/theme-audit.test.d.ts +2 -0
  61. package/dist/core/theme-audit.test.d.ts.map +1 -0
  62. package/dist/core/theme-audit.test.js +198 -0
  63. package/dist/core/theme-audit.test.js.map +1 -0
  64. package/dist/core/url-import.d.ts +41 -0
  65. package/dist/core/url-import.d.ts.map +1 -0
  66. package/dist/core/url-import.js +207 -0
  67. package/dist/core/url-import.js.map +1 -0
  68. package/dist/core/video-import.d.ts +46 -0
  69. package/dist/core/video-import.d.ts.map +1 -0
  70. package/dist/core/video-import.js +192 -0
  71. package/dist/core/video-import.js.map +1 -0
  72. package/dist/core/visual-import.d.ts +42 -0
  73. package/dist/core/visual-import.d.ts.map +1 -0
  74. package/dist/core/visual-import.js +227 -0
  75. package/dist/core/visual-import.js.map +1 -0
  76. package/dist/index.d.ts +25 -2
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +25 -1
  79. package/dist/index.js.map +1 -1
  80. package/dist/mcp/index.js +32 -0
  81. package/dist/mcp/index.js.map +1 -1
  82. package/package.json +9 -3
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Cockpit API — Intent-to-action layer for the Valentino Conversational Cockpit.
3
+ * Feature #778 (Il Sarto Parla), PBI #779 (Phase 0).
4
+ *
5
+ * Wraps editor.ts CRUD operations with a structured intent-based interface
6
+ * that an LLM can produce and an operator can review.
7
+ *
8
+ * Pure functions, no I/O, no LLM client — the consumer wires in the LLM.
9
+ */
10
+ import type { PageSpecV1, SectionSpec } from './types.js';
11
+ export type CockpitActionAddSection = {
12
+ action: 'add-section';
13
+ section: SectionSpec;
14
+ atIndex?: number;
15
+ };
16
+ export type CockpitActionEditSection = {
17
+ action: 'edit-section';
18
+ sectionIndex: number;
19
+ patch: Record<string, unknown>;
20
+ };
21
+ export type CockpitActionRemoveSection = {
22
+ action: 'remove-section';
23
+ sectionIndex: number;
24
+ };
25
+ export type CockpitActionMoveSection = {
26
+ action: 'move-section';
27
+ fromIndex: number;
28
+ toIndex: number;
29
+ };
30
+ export type CockpitActionEditPage = {
31
+ action: 'edit-page';
32
+ patch: Partial<Omit<PageSpecV1, 'version' | 'sections'>>;
33
+ };
34
+ export type CockpitActionQuery = {
35
+ action: 'query';
36
+ query: CockpitQuery;
37
+ };
38
+ export type CockpitAction = CockpitActionAddSection | CockpitActionEditSection | CockpitActionRemoveSection | CockpitActionMoveSection | CockpitActionEditPage | CockpitActionQuery;
39
+ export type CockpitQuery = {
40
+ type: 'list-sections';
41
+ } | {
42
+ type: 'get-section';
43
+ index: number;
44
+ } | {
45
+ type: 'describe-page';
46
+ } | {
47
+ type: 'list-section-types';
48
+ } | {
49
+ type: 'get-editor-schema';
50
+ sectionType: string;
51
+ } | {
52
+ type: 'validate';
53
+ };
54
+ export type CockpitWarning = {
55
+ source: 'editor' | 'rhythm' | 'integrity' | 'validation';
56
+ message: string;
57
+ };
58
+ export type CockpitActionResult = {
59
+ success: boolean;
60
+ spec: PageSpecV1;
61
+ warnings: CockpitWarning[];
62
+ /** For query actions, the query result data */
63
+ data?: unknown;
64
+ };
65
+ /**
66
+ * Execute a cockpit action on a PageSpec.
67
+ * Returns the (possibly updated) spec + validation warnings.
68
+ *
69
+ * All mutations are immutable — the original spec is never modified.
70
+ * All mutations are validated post-execution (rhythm, integrity, spec validation).
71
+ */
72
+ export declare function executeCockpitAction(spec: PageSpecV1, action: CockpitAction): CockpitActionResult;
73
+ export type CockpitBatchResult = {
74
+ spec: PageSpecV1;
75
+ results: CockpitActionResult[];
76
+ totalWarnings: number;
77
+ };
78
+ /**
79
+ * Execute multiple cockpit actions in sequence.
80
+ * Each action operates on the result of the previous one.
81
+ * Stops on first failure unless `continueOnError` is true.
82
+ */
83
+ export declare function executeCockpitBatch(spec: PageSpecV1, actions: CockpitAction[], continueOnError?: boolean): CockpitBatchResult;
84
+ /**
85
+ * Generate a human-readable description of a cockpit action.
86
+ * Useful for showing the operator what the LLM intends to do before executing.
87
+ */
88
+ export declare function describeCockpitAction(action: CockpitAction): string;
89
+ /**
90
+ * Registry of all valid section types for the cockpit.
91
+ * Used for validation and LLM context.
92
+ */
93
+ export declare const COCKPIT_SECTION_TYPES: readonly string[];
94
+ /**
95
+ * Validate that a cockpit action is structurally correct before execution.
96
+ * Returns a list of validation errors (empty = valid).
97
+ */
98
+ export declare function validateCockpitAction(action: CockpitAction, spec: PageSpecV1): string[];
99
+ //# sourceMappingURL=cockpit-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cockpit-api.d.ts","sourceRoot":"","sources":["../../src/core/cockpit-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,269 @@
1
+ /**
2
+ * Cockpit API — Intent-to-action layer for the Valentino Conversational Cockpit.
3
+ * Feature #778 (Il Sarto Parla), PBI #779 (Phase 0).
4
+ *
5
+ * Wraps editor.ts CRUD operations with a structured intent-based interface
6
+ * that an LLM can produce and an operator can review.
7
+ *
8
+ * Pure functions, no I/O, no LLM client — the consumer wires in the LLM.
9
+ */
10
+ import { validatePageSpec } from './page-spec.js';
11
+ import { addSection, removeSection, moveSection, applySectionPatch, applyPagePatch, generateEditorSchema, getEditableSectionTypes, } from './editor.js';
12
+ import { probeRhythm } from './rhythm.js';
13
+ import { probeSectionIntegrity } from './section-integrity.js';
14
+ // ---------------------------------------------------------------------------
15
+ // Validation — pre-flight + post-flight checks
16
+ // ---------------------------------------------------------------------------
17
+ function collectWarnings(spec, editorWarnings) {
18
+ const warnings = [];
19
+ for (const w of editorWarnings) {
20
+ warnings.push({ source: 'editor', message: `${w.field}: ${w.message}` });
21
+ }
22
+ if (!validatePageSpec(spec)) {
23
+ warnings.push({ source: 'validation', message: 'PageSpecV1 validation failed' });
24
+ }
25
+ const rhythmResult = probeRhythm(spec);
26
+ for (const w of rhythmResult.warnings) {
27
+ warnings.push({ source: 'rhythm', message: w.message });
28
+ }
29
+ const integrityResult = probeSectionIntegrity(spec.sections);
30
+ for (const w of integrityResult.warnings) {
31
+ warnings.push({ source: 'integrity', message: w.message });
32
+ }
33
+ return warnings;
34
+ }
35
+ // ---------------------------------------------------------------------------
36
+ // Query execution
37
+ // ---------------------------------------------------------------------------
38
+ function executeQuery(spec, query) {
39
+ switch (query.type) {
40
+ case 'list-sections':
41
+ return {
42
+ success: true,
43
+ spec,
44
+ warnings: [],
45
+ data: spec.sections.map((s, i) => ({
46
+ index: i,
47
+ type: s.type,
48
+ ...(('titleKey' in s && s.titleKey) ? { titleKey: s.titleKey } : {}),
49
+ })),
50
+ };
51
+ case 'get-section': {
52
+ const section = spec.sections[query.index];
53
+ if (!section) {
54
+ return {
55
+ success: false,
56
+ spec,
57
+ warnings: [{ source: 'editor', message: `Section index ${query.index} out of bounds` }],
58
+ };
59
+ }
60
+ return { success: true, spec, warnings: [], data: section };
61
+ }
62
+ case 'describe-page':
63
+ return {
64
+ success: true,
65
+ spec,
66
+ warnings: [],
67
+ data: {
68
+ id: spec.id,
69
+ profile: spec.profile,
70
+ titleKey: spec.titleKey,
71
+ themeId: spec.themeId,
72
+ sectionCount: spec.sections.length,
73
+ sectionTypes: spec.sections.map(s => s.type),
74
+ },
75
+ };
76
+ case 'list-section-types':
77
+ return {
78
+ success: true,
79
+ spec,
80
+ warnings: [],
81
+ data: getEditableSectionTypes(),
82
+ };
83
+ case 'get-editor-schema': {
84
+ const schema = generateEditorSchema(query.sectionType);
85
+ if (!schema) {
86
+ return {
87
+ success: false,
88
+ spec,
89
+ warnings: [{ source: 'editor', message: `Unknown section type: ${query.sectionType}` }],
90
+ };
91
+ }
92
+ return { success: true, spec, warnings: [], data: schema };
93
+ }
94
+ case 'validate': {
95
+ const warnings = collectWarnings(spec, []);
96
+ return {
97
+ success: warnings.length === 0,
98
+ spec,
99
+ warnings,
100
+ data: { valid: warnings.length === 0, warningCount: warnings.length },
101
+ };
102
+ }
103
+ }
104
+ }
105
+ // ---------------------------------------------------------------------------
106
+ // Action execution — the core cockpit engine
107
+ // ---------------------------------------------------------------------------
108
+ /**
109
+ * Execute a cockpit action on a PageSpec.
110
+ * Returns the (possibly updated) spec + validation warnings.
111
+ *
112
+ * All mutations are immutable — the original spec is never modified.
113
+ * All mutations are validated post-execution (rhythm, integrity, spec validation).
114
+ */
115
+ export function executeCockpitAction(spec, action) {
116
+ switch (action.action) {
117
+ case 'add-section': {
118
+ const newSpec = addSection(spec, action.section, action.atIndex);
119
+ const warnings = collectWarnings(newSpec, []);
120
+ return { success: true, spec: newSpec, warnings };
121
+ }
122
+ case 'edit-section': {
123
+ const { spec: newSpec, warnings: editorWarnings } = applySectionPatch(spec, action.sectionIndex, action.patch);
124
+ const warnings = collectWarnings(newSpec, editorWarnings);
125
+ return { success: editorWarnings.length === 0, spec: newSpec, warnings };
126
+ }
127
+ case 'remove-section': {
128
+ if (action.sectionIndex < 0 || action.sectionIndex >= spec.sections.length) {
129
+ return {
130
+ success: false,
131
+ spec,
132
+ warnings: [{ source: 'editor', message: `Section index ${action.sectionIndex} out of bounds` }],
133
+ };
134
+ }
135
+ const newSpec = removeSection(spec, action.sectionIndex);
136
+ const warnings = collectWarnings(newSpec, []);
137
+ return { success: true, spec: newSpec, warnings };
138
+ }
139
+ case 'move-section': {
140
+ const newSpec = moveSection(spec, action.fromIndex, action.toIndex);
141
+ if (newSpec === spec) {
142
+ return {
143
+ success: false,
144
+ spec,
145
+ warnings: [{ source: 'editor', message: `Invalid move: ${action.fromIndex} → ${action.toIndex}` }],
146
+ };
147
+ }
148
+ const warnings = collectWarnings(newSpec, []);
149
+ return { success: true, spec: newSpec, warnings };
150
+ }
151
+ case 'edit-page': {
152
+ const newSpec = applyPagePatch(spec, action.patch);
153
+ const warnings = collectWarnings(newSpec, []);
154
+ return { success: true, spec: newSpec, warnings };
155
+ }
156
+ case 'query':
157
+ return executeQuery(spec, action.query);
158
+ }
159
+ }
160
+ /**
161
+ * Execute multiple cockpit actions in sequence.
162
+ * Each action operates on the result of the previous one.
163
+ * Stops on first failure unless `continueOnError` is true.
164
+ */
165
+ export function executeCockpitBatch(spec, actions, continueOnError = false) {
166
+ let currentSpec = spec;
167
+ const results = [];
168
+ let totalWarnings = 0;
169
+ for (const action of actions) {
170
+ const result = executeCockpitAction(currentSpec, action);
171
+ results.push(result);
172
+ totalWarnings += result.warnings.length;
173
+ currentSpec = result.spec;
174
+ if (!result.success && !continueOnError)
175
+ break;
176
+ }
177
+ return { spec: currentSpec, results, totalWarnings };
178
+ }
179
+ // ---------------------------------------------------------------------------
180
+ // Action description — human-readable summary for operator review
181
+ // ---------------------------------------------------------------------------
182
+ /**
183
+ * Generate a human-readable description of a cockpit action.
184
+ * Useful for showing the operator what the LLM intends to do before executing.
185
+ */
186
+ export function describeCockpitAction(action) {
187
+ switch (action.action) {
188
+ case 'add-section':
189
+ return `Add ${action.section.type} section${action.atIndex != null ? ` at position ${action.atIndex}` : ' at the end'}`;
190
+ case 'edit-section':
191
+ return `Edit section #${action.sectionIndex}: update ${Object.keys(action.patch).join(', ')}`;
192
+ case 'remove-section':
193
+ return `Remove section #${action.sectionIndex}`;
194
+ case 'move-section':
195
+ return `Move section from position ${action.fromIndex} to ${action.toIndex}`;
196
+ case 'edit-page':
197
+ return `Edit page properties: ${Object.keys(action.patch).join(', ')}`;
198
+ case 'query':
199
+ return `Query: ${action.query.type}`;
200
+ }
201
+ }
202
+ // ---------------------------------------------------------------------------
203
+ // Action parsing — parse natural language intent into structured action
204
+ // ---------------------------------------------------------------------------
205
+ /**
206
+ * Registry of all valid section types for the cockpit.
207
+ * Used for validation and LLM context.
208
+ */
209
+ export const COCKPIT_SECTION_TYPES = [
210
+ 'hero', 'cards', 'comparison', 'cta', 'form', 'manifesto', 'spacer',
211
+ 'showcase-intro', 'component-showcase',
212
+ 'agent-dashboard', 'agent-graph', 'agent-list',
213
+ 'data-list', 'action-form',
214
+ 'stats', 'how-it-works',
215
+ 'advisor', 'mermaid-diagram', 'valentino-catalog',
216
+ ];
217
+ /**
218
+ * Validate that a cockpit action is structurally correct before execution.
219
+ * Returns a list of validation errors (empty = valid).
220
+ */
221
+ export function validateCockpitAction(action, spec) {
222
+ const errors = [];
223
+ switch (action.action) {
224
+ case 'add-section':
225
+ if (!action.section || !action.section.type) {
226
+ errors.push('add-section requires a section with a type');
227
+ }
228
+ else if (!COCKPIT_SECTION_TYPES.includes(action.section.type)) {
229
+ errors.push(`Unknown section type: ${action.section.type}`);
230
+ }
231
+ if (action.atIndex != null && (action.atIndex < 0 || action.atIndex > spec.sections.length)) {
232
+ errors.push(`atIndex ${action.atIndex} out of bounds (0..${spec.sections.length})`);
233
+ }
234
+ break;
235
+ case 'edit-section':
236
+ if (action.sectionIndex < 0 || action.sectionIndex >= spec.sections.length) {
237
+ errors.push(`sectionIndex ${action.sectionIndex} out of bounds (0..${spec.sections.length - 1})`);
238
+ }
239
+ if (!action.patch || Object.keys(action.patch).length === 0) {
240
+ errors.push('edit-section requires a non-empty patch');
241
+ }
242
+ break;
243
+ case 'remove-section':
244
+ if (action.sectionIndex < 0 || action.sectionIndex >= spec.sections.length) {
245
+ errors.push(`sectionIndex ${action.sectionIndex} out of bounds (0..${spec.sections.length - 1})`);
246
+ }
247
+ break;
248
+ case 'move-section':
249
+ if (action.fromIndex < 0 || action.fromIndex >= spec.sections.length) {
250
+ errors.push(`fromIndex ${action.fromIndex} out of bounds`);
251
+ }
252
+ if (action.toIndex < 0 || action.toIndex >= spec.sections.length) {
253
+ errors.push(`toIndex ${action.toIndex} out of bounds`);
254
+ }
255
+ break;
256
+ case 'edit-page':
257
+ if (!action.patch || Object.keys(action.patch).length === 0) {
258
+ errors.push('edit-page requires a non-empty patch');
259
+ }
260
+ break;
261
+ case 'query':
262
+ if (!action.query || !action.query.type) {
263
+ errors.push('query requires a query with a type');
264
+ }
265
+ break;
266
+ }
267
+ return errors;
268
+ }
269
+ //# sourceMappingURL=cockpit-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cockpit-api.js","sourceRoot":"","sources":["../../src/core/cockpit-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Cockpit REPL — Interactive conversational loop for operators.
3
+ * Feature #778 (Il Sarto Parla), PBI #780 (Phase 1).
4
+ *
5
+ * Reads operator input, parses intent, executes action, shows results.
6
+ * Uses Node readline for terminal I/O.
7
+ */
8
+ import type { PageSpecV1 } from './types.js';
9
+ import type { IntentLlmCallback } from './intent-parser.js';
10
+ export type ReplOptions = {
11
+ /** Initial page spec to work with */
12
+ spec: PageSpecV1;
13
+ /** Optional LLM callback for smarter intent parsing */
14
+ llm?: IntentLlmCallback;
15
+ /** Optional callback when spec changes (e.g., auto-save) */
16
+ onSpecChange?: (spec: PageSpecV1) => void;
17
+ /** Custom prompt string (default: "valentino> ") */
18
+ prompt?: string;
19
+ /** Output stream (default: process.stdout) */
20
+ output?: NodeJS.WritableStream;
21
+ /** Input stream (default: process.stdin) */
22
+ input?: NodeJS.ReadableStream;
23
+ };
24
+ export type ReplSession = {
25
+ /** Current page spec */
26
+ spec: PageSpecV1;
27
+ /** Action history for undo */
28
+ history: PageSpecV1[];
29
+ /** Number of actions executed */
30
+ actionCount: number;
31
+ };
32
+ /**
33
+ * Process a single REPL input line.
34
+ * Returns the output text to display.
35
+ * Mutates session in-place (spec, history, actionCount).
36
+ */
37
+ export declare function processReplInput(input: string, session: ReplSession, llm?: IntentLlmCallback): Promise<{
38
+ output: string;
39
+ exit: boolean;
40
+ }>;
41
+ /**
42
+ * Start the interactive REPL.
43
+ * This is the main entry point for `valentino cockpit --interactive`.
44
+ */
45
+ export declare function startRepl(options: ReplOptions): Promise<void>;
46
+ /**
47
+ * Create a REPL session without starting I/O.
48
+ * Useful for testing or embedding in other tools.
49
+ */
50
+ export declare function createReplSession(spec: PageSpecV1): ReplSession;
51
+ //# sourceMappingURL=cockpit-repl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cockpit-repl.d.ts","sourceRoot":"","sources":["../../src/core/cockpit-repl.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAa5D,MAAM,MAAM,WAAW,GAAG;IACtB,qCAAqC;IACrC,IAAI,EAAE,UAAU,CAAC;IACjB,uDAAuD;IACvD,GAAG,CAAC,EAAE,iBAAiB,CAAC;IACxB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IAC1C,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACtB,wBAAwB;IACxB,IAAI,EAAE,UAAU,CAAC;IACjB,8BAA8B;IAC9B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;CACvB,CAAC;AA0FF;;;;GAIG;AACH,wBAAsB,gBAAgB,CAClC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,EACpB,GAAG,CAAC,EAAE,iBAAiB,GACxB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAmF5C;AAED;;;GAGG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA2CnE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,CAM/D"}
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Cockpit REPL — Interactive conversational loop for operators.
3
+ * Feature #778 (Il Sarto Parla), PBI #780 (Phase 1).
4
+ *
5
+ * Reads operator input, parses intent, executes action, shows results.
6
+ * Uses Node readline for terminal I/O.
7
+ */
8
+ import { createInterface } from 'readline';
9
+ import { executeCockpitAction, validateCockpitAction, } from './cockpit-api.js';
10
+ import { parseIntent } from './intent-parser.js';
11
+ // ---------------------------------------------------------------------------
12
+ // Output formatting
13
+ // ---------------------------------------------------------------------------
14
+ function formatWarnings(warnings) {
15
+ if (warnings.length === 0)
16
+ return '';
17
+ return warnings.map(w => {
18
+ const icon = w.source === 'validation' ? ' \u274C' : ' \u26A0 ';
19
+ return `${icon} [${w.source}] ${w.message}`;
20
+ }).join('\n');
21
+ }
22
+ function formatQueryData(data) {
23
+ if (data === null || data === undefined)
24
+ return '';
25
+ if (Array.isArray(data)) {
26
+ return data.map((item, i) => {
27
+ if (typeof item === 'object' && item !== null) {
28
+ const parts = Object.entries(item).map(([k, v]) => `${k}: ${v}`);
29
+ return ` ${i}. ${parts.join(', ')}`;
30
+ }
31
+ return ` ${i}. ${item}`;
32
+ }).join('\n');
33
+ }
34
+ if (typeof data === 'object') {
35
+ return Object.entries(data)
36
+ .map(([k, v]) => ` ${k}: ${JSON.stringify(v)}`)
37
+ .join('\n');
38
+ }
39
+ return String(data);
40
+ }
41
+ function formatResult(result) {
42
+ const parts = [];
43
+ if (result.success) {
44
+ parts.push(' \u2705 Done');
45
+ }
46
+ else {
47
+ parts.push(' \u274C Failed');
48
+ }
49
+ const warningText = formatWarnings(result.warnings);
50
+ if (warningText)
51
+ parts.push(warningText);
52
+ if (result.data !== undefined) {
53
+ parts.push(formatQueryData(result.data));
54
+ }
55
+ return parts.join('\n');
56
+ }
57
+ // ---------------------------------------------------------------------------
58
+ // Built-in commands
59
+ // ---------------------------------------------------------------------------
60
+ const BUILTIN_COMMANDS = {
61
+ 'help': 'Show available commands',
62
+ 'undo': 'Undo last action',
63
+ 'history': 'Show action history count',
64
+ 'json': 'Print current spec as JSON',
65
+ 'save': 'Print spec JSON (pipe to file)',
66
+ 'exit': 'Exit the cockpit',
67
+ 'quit': 'Exit the cockpit',
68
+ };
69
+ function showHelp() {
70
+ return [
71
+ '',
72
+ ' Valentino Cockpit — Il Sarto Parla',
73
+ '',
74
+ ' Parla in linguaggio naturale (IT/EN):',
75
+ ' "mostrami le sezioni" \u2192 lista sezioni',
76
+ ' "descrivi la pagina" \u2192 panoramica pagina',
77
+ ' "valida" \u2192 validazione completa',
78
+ ' "aggiungi una sezione stats" \u2192 aggiunge stats',
79
+ ' "rimuovi la cta" \u2192 rimuove prima CTA',
80
+ ' "sposta sezione 3 a 1" \u2192 riordina',
81
+ ' "cambia il titolo dell\'hero in X" \u2192 modifica campo',
82
+ '',
83
+ ' Comandi built-in:',
84
+ ...Object.entries(BUILTIN_COMMANDS).map(([cmd, desc]) => ` ${cmd.padEnd(12)} ${desc}`),
85
+ '',
86
+ ].join('\n');
87
+ }
88
+ // ---------------------------------------------------------------------------
89
+ // REPL engine
90
+ // ---------------------------------------------------------------------------
91
+ /**
92
+ * Process a single REPL input line.
93
+ * Returns the output text to display.
94
+ * Mutates session in-place (spec, history, actionCount).
95
+ */
96
+ export async function processReplInput(input, session, llm) {
97
+ const trimmed = input.trim();
98
+ if (!trimmed) {
99
+ return { output: '', exit: false };
100
+ }
101
+ // Built-in commands
102
+ switch (trimmed.toLowerCase()) {
103
+ case 'help':
104
+ case '?':
105
+ return { output: showHelp(), exit: false };
106
+ case 'exit':
107
+ case 'quit':
108
+ case 'esci':
109
+ return { output: ' Arrivederci.', exit: true };
110
+ case 'undo':
111
+ case 'annulla': {
112
+ if (session.history.length === 0) {
113
+ return { output: ' Nothing to undo.', exit: false };
114
+ }
115
+ session.spec = session.history.pop();
116
+ return { output: ' \u2705 Undo successful.', exit: false };
117
+ }
118
+ case 'history':
119
+ case 'cronologia':
120
+ return { output: ` ${session.actionCount} actions executed, ${session.history.length} undoable.`, exit: false };
121
+ case 'json':
122
+ case 'save':
123
+ return { output: JSON.stringify(session.spec, null, 2), exit: false };
124
+ }
125
+ // Parse intent
126
+ const parseResult = await parseIntent(trimmed, session.spec, llm);
127
+ if (!parseResult.intent) {
128
+ return {
129
+ output: ' \u2753 Non ho capito. Prova "help" per vedere i comandi disponibili.',
130
+ exit: false,
131
+ };
132
+ }
133
+ const { action, confidence, description } = parseResult.intent;
134
+ // Show what we understood
135
+ let output = ` \u2192 ${description}`;
136
+ if (confidence === 'low') {
137
+ output += ' (low confidence)';
138
+ }
139
+ if (parseResult.fallbackReason) {
140
+ output += `\n \u26A0 Fallback: ${parseResult.fallbackReason}`;
141
+ }
142
+ // Pre-flight validation
143
+ const preErrors = validateCockpitAction(action, session.spec);
144
+ if (preErrors.length > 0) {
145
+ output += '\n \u274C Validation errors:';
146
+ for (const e of preErrors) {
147
+ output += `\n ${e}`;
148
+ }
149
+ return { output, exit: false };
150
+ }
151
+ // For mutations: save undo point
152
+ if (action.action !== 'query') {
153
+ session.history.push(structuredClone(session.spec));
154
+ }
155
+ // Execute
156
+ const result = executeCockpitAction(session.spec, action);
157
+ output += '\n' + formatResult(result);
158
+ // Update spec
159
+ if (result.success && action.action !== 'query') {
160
+ session.spec = result.spec;
161
+ session.actionCount++;
162
+ }
163
+ return { output, exit: false };
164
+ }
165
+ /**
166
+ * Start the interactive REPL.
167
+ * This is the main entry point for `valentino cockpit --interactive`.
168
+ */
169
+ export async function startRepl(options) {
170
+ const promptStr = options.prompt || 'valentino> ';
171
+ const output = options.output || process.stdout;
172
+ const session = {
173
+ spec: structuredClone(options.spec),
174
+ history: [],
175
+ actionCount: 0,
176
+ };
177
+ const rl = createInterface({
178
+ input: options.input || process.stdin,
179
+ output: output,
180
+ prompt: promptStr,
181
+ });
182
+ output.write('\n \uD83C\uDFA8 Valentino Cockpit — Il Sarto Parla\n');
183
+ output.write(` Page: ${session.spec.id} (${session.spec.sections.length} sections)\n`);
184
+ output.write(' Type "help" for commands, or speak naturally.\n\n');
185
+ rl.prompt();
186
+ rl.on('line', async (line) => {
187
+ const { output: text, exit } = await processReplInput(line, session, options.llm);
188
+ if (text)
189
+ output.write(text + '\n');
190
+ if (exit) {
191
+ if (options.onSpecChange && session.actionCount > 0) {
192
+ options.onSpecChange(session.spec);
193
+ }
194
+ rl.close();
195
+ return;
196
+ }
197
+ output.write('\n');
198
+ rl.prompt();
199
+ });
200
+ rl.on('close', () => {
201
+ if (options.onSpecChange && session.actionCount > 0) {
202
+ options.onSpecChange(session.spec);
203
+ }
204
+ });
205
+ }
206
+ /**
207
+ * Create a REPL session without starting I/O.
208
+ * Useful for testing or embedding in other tools.
209
+ */
210
+ export function createReplSession(spec) {
211
+ return {
212
+ spec: structuredClone(spec),
213
+ history: [],
214
+ actionCount: 0,
215
+ };
216
+ }
217
+ //# sourceMappingURL=cockpit-repl.js.map