@explorer02/cfm-survey-sdk 0.0.3 → 0.0.4
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/cli/index.js +47 -16
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +118 -341
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/questionnaire/engine.d.ts +22 -0
- package/dist/cli/questionnaire/engine.d.ts.map +1 -0
- package/dist/cli/questionnaire/engine.js +218 -0
- package/dist/cli/questionnaire/engine.js.map +1 -0
- package/dist/cli/questionnaire/questionnaire-cli.d.ts +2 -0
- package/dist/cli/questionnaire/questionnaire-cli.d.ts.map +1 -0
- package/dist/cli/questionnaire/questionnaire-cli.js +3 -0
- package/dist/cli/questionnaire/questionnaire-cli.js.map +1 -0
- package/dist/cli/questionnaire/questions.d.ts +3 -0
- package/dist/cli/questionnaire/questions.d.ts.map +1 -0
- package/dist/cli/questionnaire/questions.js +327 -0
- package/dist/cli/questionnaire/questions.js.map +1 -0
- package/dist/cli/questionnaire/runner.d.ts +3 -0
- package/dist/cli/questionnaire/runner.d.ts.map +1 -0
- package/dist/cli/questionnaire/runner.js +102 -0
- package/dist/cli/questionnaire/runner.js.map +1 -0
- package/dist/cli/questionnaire/types.d.ts +94 -0
- package/dist/cli/questionnaire/types.d.ts.map +1 -0
- package/dist/cli/questionnaire/types.js +7 -0
- package/dist/cli/questionnaire/types.js.map +1 -0
- package/package.json +1 -1
- package/postinstall.js +57 -22
- package/templates/AGENT.md +23 -21
package/dist/cli/index.js
CHANGED
|
@@ -4,37 +4,68 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
const deploy_1 = require("./deploy");
|
|
5
5
|
const init_1 = require("./init");
|
|
6
6
|
const const_1 = require("./const");
|
|
7
|
+
const engine_1 = require("./questionnaire/engine");
|
|
8
|
+
const questions_1 = require("./questionnaire/questions");
|
|
9
|
+
const c = const_1.colors;
|
|
7
10
|
const args = process.argv.slice(2);
|
|
8
11
|
const command = args[0];
|
|
9
|
-
// When a user types a command like npx cfm-sdk deploy,
|
|
10
|
-
// Node receives the arguments as an array inside process.argv:
|
|
11
|
-
// ['/usr/bin/node', 'dist/cli/index.js', 'deploy']
|
|
12
|
-
// .slice(2) chops off the first two system paths, leaving only the user's custom commands: ['deploy'].
|
|
13
|
-
// args[0] picks the first command, which in this case is "deploy".
|
|
14
12
|
async function main() {
|
|
15
|
-
|
|
13
|
+
// ── init: run the full survey configuration wizard ────────────────────────
|
|
14
|
+
if (command === 'init') {
|
|
16
15
|
try {
|
|
17
|
-
await (0,
|
|
16
|
+
await (0, init_1.runInit)();
|
|
18
17
|
}
|
|
19
|
-
catch (
|
|
20
|
-
console.error(`\n${
|
|
18
|
+
catch (err) {
|
|
19
|
+
console.error(`\n${c.red}❌ Error: ${err.message || err}${c.reset}`);
|
|
21
20
|
process.exit(1);
|
|
22
21
|
}
|
|
22
|
+
// ── questionnaire-run: child process entry point (forked by runner.ts) ────
|
|
23
|
+
// Runs the questionnaire engine in the visible terminal and sends answers
|
|
24
|
+
// back to the parent (init) via the built-in IPC channel.
|
|
23
25
|
}
|
|
24
|
-
else if (command === '
|
|
26
|
+
else if (command === 'questionnaire-run') {
|
|
25
27
|
try {
|
|
26
|
-
await (0,
|
|
28
|
+
const answers = await (0, engine_1.runEngine)(questions_1.CFM_QUESTIONS);
|
|
29
|
+
const msg = { type: 'questionnaireComplete', payload: answers };
|
|
30
|
+
if (process.send) {
|
|
31
|
+
process.send(msg, undefined, undefined, () => process.exit(0));
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
// Standalone invocation — just print the result
|
|
35
|
+
console.log(JSON.stringify(msg, null, 2));
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
const errMsg = {
|
|
41
|
+
type: 'questionnaireError',
|
|
42
|
+
payload: { message: err.message || String(err) },
|
|
43
|
+
};
|
|
44
|
+
if (process.send) {
|
|
45
|
+
process.send(errMsg, undefined, undefined, () => process.exit(1));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// ── deploy: Vercel deployment helper ─────────────────────────────────────
|
|
52
|
+
}
|
|
53
|
+
else if (command === 'deploy') {
|
|
54
|
+
try {
|
|
55
|
+
await (0, deploy_1.runDeployment)();
|
|
27
56
|
}
|
|
28
|
-
catch (
|
|
29
|
-
console.error(`\n${
|
|
57
|
+
catch (err) {
|
|
58
|
+
console.error(`\n${c.red}❌ Error: ${err.message || err}${c.reset}`);
|
|
30
59
|
process.exit(1);
|
|
31
60
|
}
|
|
61
|
+
// ── help / unknown command ────────────────────────────────────────────────
|
|
32
62
|
}
|
|
33
63
|
else {
|
|
34
|
-
console.log(`\n${
|
|
64
|
+
console.log(`\n${c.bold}${c.cyan}CFM SDK CLI Tool${c.reset}`);
|
|
35
65
|
console.log(`\nUsage:`);
|
|
36
|
-
console.log(` npx cfm-sdk init
|
|
37
|
-
console.log(` npx cfm-sdk deploy
|
|
66
|
+
console.log(` npx cfm-sdk init – Interactively configure survey theme/settings`);
|
|
67
|
+
console.log(` npx cfm-sdk deploy – Deploy the current project to Vercel`);
|
|
68
|
+
console.log(` npx cfm-sdk questionnaire-run – Run the questionnaire standalone (dev/debug)`);
|
|
38
69
|
process.exit(0);
|
|
39
70
|
}
|
|
40
71
|
}
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";;;AAEA,qCAAyC;AACzC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAmJA,wBAAsB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAwC7C"}
|
package/dist/cli/init.js
CHANGED
|
@@ -4,20 +4,30 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.runInit = runInit;
|
|
7
|
-
|
|
7
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
8
|
+
// CFM Survey SDK — Init Command
|
|
9
|
+
//
|
|
10
|
+
// Flow:
|
|
11
|
+
// 1. runQuestionnaire() forks the questionnaire-cli child process
|
|
12
|
+
// 2. Child runs all questions in the VISIBLE terminal (inherited stdio)
|
|
13
|
+
// 3. Child sends answers back via built-in Node IPC channel
|
|
14
|
+
// 4. buildSurveyConfig() transforms raw answers into survey-config.json format
|
|
15
|
+
// 5. Config is written to the project root
|
|
16
|
+
// 6. Clean completion message (no "re-invoke agent" language)
|
|
17
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
8
18
|
const fs_1 = __importDefault(require("fs"));
|
|
9
19
|
const path_1 = __importDefault(require("path"));
|
|
10
20
|
const const_1 = require("./const");
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
21
|
+
const runner_1 = require("./questionnaire/runner");
|
|
22
|
+
const engine_1 = require("./questionnaire/engine");
|
|
23
|
+
const c = const_1.colors;
|
|
24
|
+
// ── Defaults (Sprinklr branding) ─────────────────────────────────────────────
|
|
14
25
|
const DEFAULTS = {
|
|
15
26
|
companyName: 'Sprinklr',
|
|
16
27
|
surveyTitle: 'Customer Feedback Survey',
|
|
17
28
|
browserTabTitle: 'Customer Feedback Survey',
|
|
18
29
|
thankYouMessage: 'Thank you for your valuable feedback!',
|
|
19
30
|
logoUrl: 'https://www.aprimo.com/wp-content/uploads/2024/03/Sprinklr_Logo-1.png',
|
|
20
|
-
// Sprinklr-derived color palette (navy + teal)
|
|
21
31
|
colorScheme: {
|
|
22
32
|
primary: '#1A1F36',
|
|
23
33
|
secondary: '#E8F5FD',
|
|
@@ -31,375 +41,142 @@ const DEFAULTS = {
|
|
|
31
41
|
lastName: 'Agrawal',
|
|
32
42
|
email: 'unnat.agrawal@sprinklr.com',
|
|
33
43
|
},
|
|
34
|
-
debug: true,
|
|
35
|
-
deployToVercel: true,
|
|
36
44
|
};
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
rl.close();
|
|
48
|
-
}
|
|
49
|
-
/** Ask a single question and return the trimmed answer */
|
|
50
|
-
function ask(question) {
|
|
51
|
-
return new Promise((resolve) => rl.question(question, (ans) => resolve(ans.trim())));
|
|
52
|
-
}
|
|
53
|
-
/** Print an empty line */
|
|
54
|
-
const br = () => console.log('');
|
|
55
|
-
/** Print a styled section header */
|
|
56
|
-
function section(label) {
|
|
57
|
-
br();
|
|
58
|
-
console.log(`${c.bold}${c.bgBlue}${c.white} ${label} ${c.reset}`);
|
|
59
|
-
br();
|
|
60
|
-
}
|
|
61
|
-
/** Print a styled banner */
|
|
62
|
-
function printBanner() {
|
|
63
|
-
br();
|
|
64
|
-
console.log(`${c.bold}${c.cyan}╔═══════════════════════════════════════════════════════╗${c.reset}`);
|
|
65
|
-
console.log(`${c.bold}${c.cyan}║ CFM Survey SDK — Setup Wizard 🚀 ║${c.reset}`);
|
|
66
|
-
console.log(`${c.bold}${c.cyan}╚═══════════════════════════════════════════════════════╝${c.reset}`);
|
|
67
|
-
br();
|
|
68
|
-
console.log(`${c.dim}This short wizard helps configure your personalised survey.${c.reset}`);
|
|
69
|
-
console.log(`${c.dim}Every question is optional — just press ${c.bold}Enter${c.reset}${c.dim} to use the smart default.${c.reset}`);
|
|
70
|
-
br();
|
|
71
|
-
}
|
|
72
|
-
/** Print a labelled optional prompt and return raw answer */
|
|
73
|
-
async function optionalAsk(num, label, hint, defaultLabel) {
|
|
74
|
-
const defaultStr = defaultLabel ? ` ${c.dim}(default: ${defaultLabel})${c.reset}` : '';
|
|
75
|
-
const optionalTag = `${c.dim}[optional]${c.reset}`;
|
|
76
|
-
console.log(`${c.bold}${c.yellow}${num}.${c.reset} ${c.bold}${label}${c.reset} ${optionalTag}`);
|
|
77
|
-
console.log(` ${c.dim}${hint}${c.reset}${defaultStr}`);
|
|
78
|
-
const ans = await ask(` ${c.cyan}›${c.reset} `);
|
|
79
|
-
br();
|
|
80
|
-
return ans;
|
|
81
|
-
}
|
|
82
|
-
/** Print a labelled required prompt */
|
|
83
|
-
async function requiredAsk(num, label, hint, defaultLabel) {
|
|
84
|
-
const defaultStr = defaultLabel ? ` ${c.dim}(default: ${defaultLabel})${c.reset}` : '';
|
|
85
|
-
console.log(`${c.bold}${c.yellow}${num}.${c.reset} ${c.bold}${label}${c.reset} ${c.red}[recommended]${c.reset}`);
|
|
86
|
-
console.log(` ${c.dim}${hint}${c.reset}${defaultStr}`);
|
|
87
|
-
const ans = await ask(` ${c.cyan}›${c.reset} `);
|
|
88
|
-
br();
|
|
89
|
-
return ans;
|
|
90
|
-
}
|
|
91
|
-
/** Yes/No prompt — returns boolean */
|
|
92
|
-
async function yesNo(num, label, hint, defaultYes = true) {
|
|
93
|
-
const defaultStr = defaultYes ? 'y' : 'n';
|
|
94
|
-
console.log(`${c.bold}${c.yellow}${num}.${c.reset} ${c.bold}${label}${c.reset} ${c.dim}[optional]${c.reset}`);
|
|
95
|
-
console.log(` ${c.dim}${hint}${c.reset}`);
|
|
96
|
-
const ans = await ask(` ${c.cyan}›${c.reset} ${c.dim}(y/n, default: ${defaultStr})${c.reset} `);
|
|
97
|
-
br();
|
|
98
|
-
if (!ans)
|
|
99
|
-
return defaultYes;
|
|
100
|
-
return ans.toLowerCase() === 'y';
|
|
101
|
-
}
|
|
102
|
-
/** Pick from a numbered menu — returns the number typed */
|
|
103
|
-
async function menu(num, label, options) {
|
|
104
|
-
console.log(`${c.bold}${c.yellow}${num}.${c.reset} ${c.bold}${label}${c.reset}`);
|
|
105
|
-
options.forEach((opt, i) => {
|
|
106
|
-
console.log(` ${c.cyan}${i + 1})${c.reset} ${opt}`);
|
|
107
|
-
});
|
|
108
|
-
console.log(` ${c.dim}↵ Press Enter to skip / use smart default${c.reset}`);
|
|
109
|
-
const ans = await ask(` ${c.cyan}›${c.reset} `);
|
|
110
|
-
br();
|
|
111
|
-
return ans;
|
|
112
|
-
}
|
|
113
|
-
/** Validate and normalise a hex color string */
|
|
114
|
-
function normaliseHex(input, fallback) {
|
|
115
|
-
if (!input)
|
|
116
|
-
return fallback;
|
|
117
|
-
let hex = input.trim();
|
|
118
|
-
if (!hex.startsWith('#'))
|
|
119
|
-
hex = '#' + hex;
|
|
120
|
-
if (/^#[0-9A-Fa-f]{3,8}$/.test(hex))
|
|
121
|
-
return hex.toUpperCase();
|
|
122
|
-
console.log(` ${c.yellow}⚠️ Invalid hex — using default ${fallback}${c.reset}`);
|
|
123
|
-
return fallback;
|
|
124
|
-
}
|
|
125
|
-
/** Print the 5 professionally generated colour schemes */
|
|
126
|
-
function printColorSchemes(logoColor) {
|
|
127
|
-
const schemes = [
|
|
128
|
-
{
|
|
129
|
-
name: 'Industry Standard (Indigo + Amber)',
|
|
130
|
-
primary: '#4F46E5', secondary: '#E0E7FF', accent: '#F59E0B', bg: '#FFFFFF', text: '#111827',
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
name: 'Minimalist (Slate + Teal)',
|
|
134
|
-
primary: '#334155', secondary: '#F1F5F9', accent: '#0D9488', bg: '#FFFFFF', text: '#0F172A',
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
name: 'Warm Corporate (Amber + Brown)',
|
|
138
|
-
primary: '#B45309', secondary: '#FEF3C7', accent: '#D97706', bg: '#FFFBEB', text: '#1C1917',
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
name: 'Modern Dark (Violet + Green)',
|
|
142
|
-
primary: '#7C3AED', secondary: '#EDE9FE', accent: '#10B981', bg: '#FFFFFF', text: '#111827',
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
name: logoColor
|
|
146
|
-
? `Brand Match (from your logo — ${logoColor})`
|
|
147
|
-
: 'Professional Blue (Navy + Sky)',
|
|
148
|
-
primary: logoColor ?? '#1E3A5F',
|
|
149
|
-
secondary: '#DBEAFE',
|
|
150
|
-
accent: logoColor ?? '#0284C7',
|
|
151
|
-
bg: '#FFFFFF',
|
|
152
|
-
text: '#1E293B',
|
|
153
|
-
},
|
|
154
|
-
];
|
|
155
|
-
br();
|
|
156
|
-
console.log(`${c.bold}${c.underline} Here are 5 suggested color schemes:${c.reset}`);
|
|
157
|
-
br();
|
|
158
|
-
schemes.forEach((s, i) => {
|
|
159
|
-
console.log(` ${c.bold}${c.cyan}${i + 1}) ${s.name}${c.reset}`);
|
|
160
|
-
console.log(` ${c.dim}Primary:${c.reset} ${c.bold}${s.primary}${c.reset}`);
|
|
161
|
-
console.log(` ${c.dim}Secondary:${c.reset} ${s.secondary}`);
|
|
162
|
-
console.log(` ${c.dim}Accent:${c.reset} ${c.bold}${s.accent}${c.reset}`);
|
|
163
|
-
console.log(` ${c.dim}Background:${c.reset} ${s.bg} ${c.dim}Text:${c.reset} ${s.text}`);
|
|
164
|
-
br();
|
|
165
|
-
});
|
|
166
|
-
return schemes;
|
|
167
|
-
}
|
|
168
|
-
/** Print the final summary before saving */
|
|
169
|
-
function printSummary(cfg) {
|
|
170
|
-
br();
|
|
171
|
-
console.log(`${c.bold}${c.bgGreen}${c.black} ✅ Configuration Summary ${c.reset}`);
|
|
172
|
-
br();
|
|
173
|
-
const print = (key, val) => console.log(` ${c.bold}${key.padEnd(22)}${c.reset} ${c.green}${JSON.stringify(val)}${c.reset}`);
|
|
174
|
-
Object.entries(cfg).filter(([k]) => k !== 'configuredAt').forEach(([k, v]) => print(k, v));
|
|
175
|
-
br();
|
|
176
|
-
}
|
|
177
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
178
|
-
// MAIN WIZARD
|
|
179
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
180
|
-
async function runInit() {
|
|
181
|
-
initReadline();
|
|
182
|
-
printBanner();
|
|
183
|
-
// ── PHASE 0 — Mockup detection ──────────────────────────────────────────
|
|
184
|
-
section('PHASE 0 of 7 │ Mockup Detection');
|
|
185
|
-
console.log(`${c.dim}This helps the AI Agent understand whether to analyse your screenshots or design from scratch.${c.reset}`);
|
|
186
|
-
br();
|
|
187
|
-
const hasMockupStr = await optionalAsk('0', 'Did you share any UI mockup screenshots / images with the AI Agent in the IDE chat?', 'If yes, the agent will analyse them and replicate the visual design exactly.', 'n');
|
|
188
|
-
const hasMockup = hasMockupStr.toLowerCase() === 'y';
|
|
189
|
-
console.log(hasMockup
|
|
190
|
-
? ` ${c.green}✔ Great! The AI Agent will analyse your mockups for exact visual replication.${c.reset}`
|
|
191
|
-
: ` ${c.yellow}ℹ No mockups — the agent will design a clean professional UI from scratch.${c.reset}`);
|
|
192
|
-
br();
|
|
193
|
-
// ── PHASE 1 — Survey Identity ────────────────────────────────────────────
|
|
194
|
-
section('PHASE 1 of 7 │ Survey Identity');
|
|
195
|
-
console.log(`${c.dim}These details personalise the survey. All optional — smart defaults are used if skipped.${c.reset}`);
|
|
196
|
-
br();
|
|
197
|
-
const surveyTitle = (await optionalAsk('1', 'Survey Title', 'The heading displayed inside the survey page.', DEFAULTS.surveyTitle)) || DEFAULTS.surveyTitle;
|
|
198
|
-
const companyName = (await optionalAsk('2', 'Company / Organisation Name', 'Shown in the header or footer.', DEFAULTS.companyName)) || DEFAULTS.companyName;
|
|
199
|
-
const browserTabTitle = (await optionalAsk('3', 'Browser Tab Title', 'Text shown in the browser tab (the <title> tag).', DEFAULTS.browserTabTitle)) || DEFAULTS.browserTabTitle;
|
|
200
|
-
const thankYouMessage = (await optionalAsk('4', 'Thank-You Message', 'Displayed after the survey is submitted.', DEFAULTS.thankYouMessage)) || DEFAULTS.thankYouMessage;
|
|
201
|
-
// ── PHASE 2 — Logo ──────────────────────────────────────────────────────
|
|
202
|
-
section('PHASE 2 of 7 │ Logo Setup');
|
|
203
|
-
const publicDir = path_1.default.join(process.cwd(), 'public');
|
|
204
|
-
if (!fs_1.default.existsSync(publicDir)) {
|
|
205
|
-
fs_1.default.mkdirSync(publicDir, { recursive: true });
|
|
206
|
-
}
|
|
207
|
-
console.log(`${c.green}✅ A ${c.bold}public/${c.reset}${c.green} folder has been created in your project for static files like your logo.${c.reset}`);
|
|
208
|
-
br();
|
|
209
|
-
console.log(` ${c.dim}If you have a logo file (PNG / SVG / JPG), drop it into the${c.reset} ${c.bold}public/${c.reset} ${c.dim}folder now.${c.reset}`);
|
|
210
|
-
br();
|
|
211
|
-
const logoFileName = await optionalAsk('5', 'Logo filename inside public/', 'e.g. "logo.png" — Leave blank to use the default Sprinklr logo or no logo.', 'none');
|
|
212
|
-
const resolvedLogo = logoFileName || null;
|
|
213
|
-
// ── PHASE 3 — UI Layout & Customisation ─────────────────────────────────
|
|
214
|
-
section('PHASE 3 of 7 │ UI Layout & Customisation');
|
|
215
|
-
console.log(`${c.dim}Configure the visual layout of your survey. All optional.${c.reset}`);
|
|
216
|
-
console.log(`${c.bold}${c.red}Note:${c.reset}${c.dim} Your answers here override anything shown in the mockup screenshots.${c.reset}`);
|
|
217
|
-
br();
|
|
218
|
-
const showHeader = await yesNo('6', 'Show a header bar at the top of the survey?', 'e.g. company name, logo.', true);
|
|
219
|
-
const showFooter = await yesNo('7', 'Show a footer at the bottom?', 'e.g. Privacy Policy, copyright notice.', true);
|
|
220
|
-
const showProgressBar = await yesNo('8', 'Show a progress bar showing survey completion?', 'Helps users see how far along they are.', true);
|
|
221
|
-
const showLanguageSwitcher = await yesNo('9', 'Show a language switcher for multi-language support?', 'Only needed if the survey supports multiple languages.', false);
|
|
222
|
-
const showBackButton = await yesNo('10', 'Allow users to go back to previous questions?', 'Shows a "Back" button between pages.', true);
|
|
223
|
-
// Additional customisation options
|
|
224
|
-
const layoutWidthRaw = await menu('11', 'Survey content width', [
|
|
225
|
-
'Narrow (max-w-xl — compact, focussed)',
|
|
226
|
-
'Standard (max-w-3xl — balanced)',
|
|
227
|
-
'Wide (max-w-5xl — spacious, desktop-first)',
|
|
228
|
-
]);
|
|
229
|
-
const widthMap = { '1': 'narrow', '2': 'standard', '3': 'wide' };
|
|
230
|
-
const layoutWidth = widthMap[layoutWidthRaw] ?? 'standard';
|
|
231
|
-
const borderStyleRaw = await menu('12', 'Border / corner style', [
|
|
232
|
-
'Sharp corners (square, corporate feel)',
|
|
233
|
-
'Slightly rounded (modern, friendly)',
|
|
234
|
-
'Fully rounded / pill (casual, soft)',
|
|
235
|
-
]);
|
|
236
|
-
const borderMap = { '1': 'sharp', '2': 'rounded', '3': 'pill' };
|
|
237
|
-
const borderStyle = borderMap[borderStyleRaw] ?? 'rounded';
|
|
238
|
-
const fontStyleRaw = await menu('13', 'Font preference', [
|
|
239
|
-
'System font (fastest, clean)',
|
|
240
|
-
'Modern sans-serif (Inter / Roboto — recommended)',
|
|
241
|
-
'Classic serif (Times-style, formal)',
|
|
242
|
-
]);
|
|
243
|
-
const fontMap = { '1': 'system', '2': 'modern', '3': 'serif' };
|
|
244
|
-
const fontStyle = fontMap[fontStyleRaw] ?? 'modern';
|
|
245
|
-
const showQuestionNumbers = await yesNo('14', 'Show question numbers? (e.g. "Q1.", "Q2.")', 'Helps users track progress within a page.', true);
|
|
246
|
-
const showRequiredAsterisk = await yesNo('15', 'Mark required questions with an asterisk (*)?', 'Standard survey convention — highly recommended.', true);
|
|
247
|
-
const submitButtonText = (await optionalAsk('16', 'Submit button label', 'Text on the final submit button.', 'Submit')) || 'Submit';
|
|
248
|
-
const nextButtonText = (await optionalAsk('17', 'Next button label', 'Text on the "next page" button.', 'Next')) || 'Next';
|
|
249
|
-
const backButtonText = (await optionalAsk('18', 'Back button label', 'Text on the "previous page" button.', 'Back')) || 'Back';
|
|
250
|
-
const animationsEnabled = await yesNo('19', 'Enable smooth animations / transitions between pages?', 'Subtle fade transitions feel polished and modern.', true);
|
|
251
|
-
// ── PHASE 4 — Color Theme ────────────────────────────────────────────────
|
|
252
|
-
section('PHASE 4 of 7 │ Color Theme');
|
|
253
|
-
console.log(`${c.dim}Choose how the color scheme is determined. Leave blank for a smart default.${c.reset}`);
|
|
254
|
-
br();
|
|
255
|
-
const colorSourceRaw = await menu('20', 'How should the color theme be chosen?', [
|
|
256
|
-
`Extract colors from your mockup screenshots ${hasMockup ? c.green + '(you have mockups ✔)' + c.reset : c.dim + '(no mockups provided)' + c.reset}`,
|
|
257
|
-
'Extract colors from your logo',
|
|
258
|
-
'Let me choose a custom color scheme',
|
|
259
|
-
'Agent picks the best professional scheme automatically',
|
|
260
|
-
]);
|
|
45
|
+
// ── Width / border / font lookup maps ────────────────────────────────────────
|
|
46
|
+
const WIDTH_MAP = { '1': 'narrow', '2': 'standard', '3': 'wide' };
|
|
47
|
+
const BORDER_MAP = { '1': 'sharp', '2': 'rounded', '3': 'pill' };
|
|
48
|
+
const FONT_MAP = { '1': 'system', '2': 'modern', '3': 'serif' };
|
|
49
|
+
// ── Answer → SurveyConfig transformer ────────────────────────────────────────
|
|
50
|
+
function buildSurveyConfig(answers) {
|
|
51
|
+
const str = (id, def) => answers[id] || def;
|
|
52
|
+
const bool = (id, def) => typeof answers[id] === 'boolean' ? answers[id] : def;
|
|
53
|
+
// Resolve colorScheme from colorSource + sub-answers
|
|
54
|
+
const colorSourceRaw = str('colorSource', '4');
|
|
261
55
|
let colorSource = 'auto';
|
|
262
56
|
let colorScheme = { ...DEFAULTS.colorScheme };
|
|
263
|
-
if (colorSourceRaw === '1' && hasMockup) {
|
|
57
|
+
if (colorSourceRaw === '1' && bool('hasMockup', false)) {
|
|
264
58
|
colorSource = 'mockup';
|
|
265
|
-
console.log(` ${c.green}✔ The AI Agent will extract exact colors from your mockup screenshots.${c.reset}`);
|
|
266
|
-
br();
|
|
267
59
|
}
|
|
268
60
|
else if (colorSourceRaw === '2') {
|
|
269
61
|
colorSource = 'logo';
|
|
270
|
-
console.log(` ${c.green}✔ The AI Agent will derive the palette from your logo file.${c.reset}`);
|
|
271
|
-
br();
|
|
272
62
|
}
|
|
273
63
|
else if (colorSourceRaw === '3') {
|
|
274
64
|
colorSource = 'custom';
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
65
|
+
const customMode = str('colorCustomMode', '');
|
|
66
|
+
if (customMode === '1') {
|
|
67
|
+
// User picked from pre-defined schemes
|
|
68
|
+
const pick = parseInt(str('colorSchemePick', ''), 10) - 1;
|
|
69
|
+
if (pick >= 0 && pick < engine_1.COLOR_SCHEMES.length) {
|
|
70
|
+
const s = engine_1.COLOR_SCHEMES[pick];
|
|
71
|
+
colorScheme = {
|
|
72
|
+
primary: s.primary,
|
|
73
|
+
secondary: s.secondary,
|
|
74
|
+
accent: s.accent,
|
|
75
|
+
background: s.bg,
|
|
76
|
+
text: s.text,
|
|
77
|
+
buttonText: '#FFFFFF',
|
|
78
|
+
};
|
|
289
79
|
}
|
|
290
80
|
else {
|
|
291
|
-
|
|
81
|
+
// No valid pick → auto
|
|
292
82
|
colorSource = 'auto';
|
|
293
83
|
}
|
|
294
84
|
}
|
|
295
|
-
else if (
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
colorScheme = {
|
|
305
|
-
primary: normaliseHex(p, DEFAULTS.colorScheme.primary),
|
|
306
|
-
secondary: normaliseHex(s, DEFAULTS.colorScheme.secondary),
|
|
307
|
-
accent: normaliseHex(a, DEFAULTS.colorScheme.accent),
|
|
308
|
-
background: normaliseHex(bg, DEFAULTS.colorScheme.background),
|
|
309
|
-
text: normaliseHex(tx, DEFAULTS.colorScheme.text),
|
|
310
|
-
buttonText: '#FFFFFF',
|
|
311
|
-
};
|
|
85
|
+
else if (customMode === '2') {
|
|
86
|
+
// User typed their own hex values (stored under __hexColors__ key)
|
|
87
|
+
const hex = answers[engine_1.HEX_INPUTS_KEY];
|
|
88
|
+
if (hex) {
|
|
89
|
+
colorScheme = hex;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
colorSource = 'auto';
|
|
93
|
+
}
|
|
312
94
|
}
|
|
313
95
|
else {
|
|
314
96
|
colorSource = 'auto';
|
|
315
|
-
console.log(` ${c.yellow}ℹ Skipped — agent will auto-generate the best color scheme.${c.reset}`);
|
|
316
97
|
}
|
|
317
98
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
const lastName = (await requiredAsk('22', 'Test Last Name', 'Used to replace {{LAST_NAME}} in survey questions.', DEFAULTS.placeholders.lastName)) || DEFAULTS.placeholders.lastName;
|
|
330
|
-
const email = (await requiredAsk('23', 'Test Email Address', 'Used to replace {{EMAIL_ADDRESS}} in survey questions.', DEFAULTS.placeholders.email)) || DEFAULTS.placeholders.email;
|
|
331
|
-
br();
|
|
332
|
-
console.log(`${c.bold}${c.yellow}24.${c.reset} ${c.bold}Enable Debug / Test Mode?${c.reset} ${c.red}[recommended]${c.reset}`);
|
|
333
|
-
console.log(` ${c.dim}Debug mode shows extra technical information in the browser console.${c.reset}`);
|
|
334
|
-
console.log(` ${c.dim}✅ Turn ON while building and testing your survey.${c.reset}`);
|
|
335
|
-
console.log(` ${c.dim}❌ Turn OFF before going live (production mode).${c.reset}`);
|
|
336
|
-
const debugStr = await ask(` ${c.cyan}›${c.reset} ${c.dim}(y/n, default: y)${c.reset} `);
|
|
337
|
-
br();
|
|
338
|
-
const debug = !debugStr || debugStr.toLowerCase() !== 'n';
|
|
339
|
-
// ── PHASE 6 — Deployment ────────────────────────────────────────────────
|
|
340
|
-
section('PHASE 6 of 7 │ Deployment');
|
|
341
|
-
console.log(`${c.dim}Once the survey is built and tested, the agent can publish it live automatically.${c.reset}`);
|
|
342
|
-
br();
|
|
343
|
-
const deployToVercel = await yesNo('25', 'Automatically deploy to Vercel when the build is ready?', 'This publishes your survey live on the internet. You can also do this later.', true);
|
|
344
|
-
// ── PHASE 7 — Summary & Confirmation ───────────────────────────────────
|
|
345
|
-
section('PHASE 7 of 7 │ Review & Confirm');
|
|
346
|
-
const config = {
|
|
347
|
-
hasMockup,
|
|
348
|
-
surveyTitle,
|
|
349
|
-
companyName,
|
|
350
|
-
browserTabTitle,
|
|
351
|
-
thankYouMessage,
|
|
99
|
+
// Back button text: only meaningful if showBackButton is true
|
|
100
|
+
const showBackButton = bool('showBackButton', true);
|
|
101
|
+
const backText = showBackButton
|
|
102
|
+
? str('backButtonText', 'Back')
|
|
103
|
+
: 'Back'; // stored but won't be rendered
|
|
104
|
+
return {
|
|
105
|
+
hasMockup: bool('hasMockup', false),
|
|
106
|
+
surveyTitle: str('surveyTitle', DEFAULTS.surveyTitle),
|
|
107
|
+
companyName: str('companyName', DEFAULTS.companyName),
|
|
108
|
+
browserTabTitle: str('browserTabTitle', DEFAULTS.browserTabTitle),
|
|
109
|
+
thankYouMessage: str('thankYouMessage', DEFAULTS.thankYouMessage),
|
|
352
110
|
logo: {
|
|
353
|
-
fileName:
|
|
354
|
-
defaultUrl:
|
|
111
|
+
fileName: str('logoFileName', '') || null,
|
|
112
|
+
defaultUrl: str('logoFileName', '') ? null : DEFAULTS.logoUrl,
|
|
355
113
|
},
|
|
356
114
|
layout: {
|
|
357
|
-
showHeader,
|
|
358
|
-
showFooter,
|
|
359
|
-
showProgressBar,
|
|
360
|
-
showLanguageSwitcher,
|
|
115
|
+
showHeader: bool('showHeader', true),
|
|
116
|
+
showFooter: bool('showFooter', true),
|
|
117
|
+
showProgressBar: bool('showProgressBar', true),
|
|
118
|
+
showLanguageSwitcher: bool('showLanguageSwitcher', false),
|
|
361
119
|
showBackButton,
|
|
362
|
-
width: layoutWidth,
|
|
363
|
-
borderStyle,
|
|
364
|
-
fontStyle,
|
|
365
|
-
showQuestionNumbers,
|
|
366
|
-
showRequiredAsterisk,
|
|
367
|
-
animationsEnabled,
|
|
120
|
+
width: WIDTH_MAP[str('layoutWidth', '')] ?? 'standard',
|
|
121
|
+
borderStyle: BORDER_MAP[str('borderStyle', '')] ?? 'rounded',
|
|
122
|
+
fontStyle: FONT_MAP[str('fontStyle', '')] ?? 'modern',
|
|
123
|
+
showQuestionNumbers: bool('showQuestionNumbers', true),
|
|
124
|
+
showRequiredAsterisk: bool('showRequiredAsterisk', true),
|
|
125
|
+
animationsEnabled: bool('animationsEnabled', true),
|
|
368
126
|
},
|
|
369
127
|
buttons: {
|
|
370
|
-
submit: submitButtonText,
|
|
371
|
-
next: nextButtonText,
|
|
372
|
-
back:
|
|
128
|
+
submit: str('submitButtonText', 'Submit'),
|
|
129
|
+
next: str('nextButtonText', 'Next'),
|
|
130
|
+
back: backText,
|
|
373
131
|
},
|
|
374
132
|
colorSource,
|
|
375
133
|
colorScheme: colorSource === 'auto' ? DEFAULTS.colorScheme : colorScheme,
|
|
376
|
-
placeholders: {
|
|
377
|
-
|
|
378
|
-
|
|
134
|
+
placeholders: {
|
|
135
|
+
firstName: str('firstName', DEFAULTS.placeholders.firstName),
|
|
136
|
+
lastName: str('lastName', DEFAULTS.placeholders.lastName),
|
|
137
|
+
email: str('email', DEFAULTS.placeholders.email),
|
|
138
|
+
},
|
|
139
|
+
debug: bool('debug', true),
|
|
140
|
+
deployToVercel: bool('deployToVercel', true),
|
|
379
141
|
configuredAt: new Date().toISOString(),
|
|
380
142
|
};
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
143
|
+
}
|
|
144
|
+
// ── Main export ───────────────────────────────────────────────────────────────
|
|
145
|
+
async function runInit() {
|
|
146
|
+
// Ensure public/ directory exists for logo uploads
|
|
147
|
+
const publicDir = path_1.default.join(process.cwd(), 'public');
|
|
148
|
+
if (!fs_1.default.existsSync(publicDir)) {
|
|
149
|
+
fs_1.default.mkdirSync(publicDir, { recursive: true });
|
|
150
|
+
console.log(`\n${c.green}✅ Created ${c.bold}public/${c.reset}${c.green} folder for logo and static files.${c.reset}`);
|
|
151
|
+
}
|
|
152
|
+
// ── Launch the interactive terminal questionnaire ─────────────────────────
|
|
153
|
+
// runQuestionnaire() forks questionnaire-cli.js as a child process.
|
|
154
|
+
// The child inherits stdin/stdout/stderr (visible terminal), runs all
|
|
155
|
+
// questions interactively, then returns answers via Node.js IPC.
|
|
156
|
+
// The agent process blocks here until all questions are answered.
|
|
157
|
+
let answers;
|
|
158
|
+
try {
|
|
159
|
+
answers = await (0, runner_1.runQuestionnaire)();
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
163
|
+
console.error(`\n${c.red}❌ Questionnaire failed: ${msg}${c.reset}\n`);
|
|
164
|
+
console.log(`${c.yellow}⚠️ Using all Sprinklr defaults. Re-run ${c.bold}npx cfm-sdk init${c.reset}${c.yellow} to reconfigure.${c.reset}\n`);
|
|
165
|
+
answers = {};
|
|
389
166
|
}
|
|
167
|
+
// ── Build configuration object ────────────────────────────────────────────
|
|
168
|
+
const config = buildSurveyConfig(answers);
|
|
169
|
+
// ── Print summary ─────────────────────────────────────────────────────────
|
|
170
|
+
(0, engine_1.printSummary)(config);
|
|
171
|
+
// ── Write survey-config.json ──────────────────────────────────────────────
|
|
390
172
|
const configPath = path_1.default.join(process.cwd(), 'survey-config.json');
|
|
391
173
|
fs_1.default.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
console.log(
|
|
396
|
-
console.log(
|
|
397
|
-
console.log(`${c.bold}${c.cyan}║
|
|
398
|
-
console.log(`${c.bold}${c.cyan}
|
|
399
|
-
console.log(`${c.bold}${c.cyan}║ 2. Read survey-config.json for your preferences ║${c.reset}`);
|
|
400
|
-
console.log(`${c.bold}${c.cyan}║ 3. Build the survey UI from scratch ║${c.reset}`);
|
|
401
|
-
console.log(`${c.bold}${c.cyan}║ 4. Verify and${deployToVercel ? ' deploy to Vercel automatically ' : ' ask you before deploying '}║${c.reset}`);
|
|
402
|
-
console.log(`${c.bold}${c.cyan}╚════════════════════════════════════════════════════════╝${c.reset}`);
|
|
403
|
-
br();
|
|
174
|
+
// ── Completion message — no "invoke agent again" language ─────────────────
|
|
175
|
+
// The agent is still running and will automatically read this output and
|
|
176
|
+
// continue to the next phase (Phase 3: read survey-config.json, build UI).
|
|
177
|
+
console.log(`\n${c.bold}${c.green}✅ Configuration saved to:${c.reset} ${c.underline}${configPath}${c.reset}`);
|
|
178
|
+
console.log(`\n${c.bold}${c.cyan}╔════════════════════════════════════════════════════════╗${c.reset}`);
|
|
179
|
+
console.log(`${c.bold}${c.cyan}║ 🎉 Setup complete. Proceeding with survey build... ║${c.reset}`);
|
|
180
|
+
console.log(`${c.bold}${c.cyan}╚════════════════════════════════════════════════════════╝${c.reset}\n`);
|
|
404
181
|
}
|
|
405
182
|
//# sourceMappingURL=init.js.map
|