create-cogenta 0.1.6 → 0.2.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/blueprint-defaults.d.ts +58 -0
- package/dist/blueprint-defaults.d.ts.map +1 -0
- package/dist/blueprint-defaults.js +111 -0
- package/dist/blueprint-defaults.js.map +1 -0
- package/dist/blueprints/association.d.ts.map +1 -1
- package/dist/blueprints/association.js +50 -1
- package/dist/blueprints/association.js.map +1 -1
- package/dist/blueprints/blog.d.ts.map +1 -1
- package/dist/blueprints/blog.js +26 -0
- package/dist/blueprints/blog.js.map +1 -1
- package/dist/blueprints/content-pack.d.ts +9 -1
- package/dist/blueprints/content-pack.d.ts.map +1 -1
- package/dist/blueprints/content-pack.js +18 -0
- package/dist/blueprints/content-pack.js.map +1 -1
- package/dist/blueprints/documentation.d.ts.map +1 -1
- package/dist/blueprints/documentation.js +45 -1
- package/dist/blueprints/documentation.js.map +1 -1
- package/dist/blueprints/magazine.d.ts.map +1 -1
- package/dist/blueprints/magazine.js +34 -0
- package/dist/blueprints/magazine.js.map +1 -1
- package/dist/blueprints/portfolio.d.ts.map +1 -1
- package/dist/blueprints/portfolio.js +26 -0
- package/dist/blueprints/portfolio.js.map +1 -1
- package/dist/blueprints/restaurant.d.ts.map +1 -1
- package/dist/blueprints/restaurant.js +50 -1
- package/dist/blueprints/restaurant.js.map +1 -1
- package/dist/blueprints/saas.d.ts.map +1 -1
- package/dist/blueprints/saas.js +50 -1
- package/dist/blueprints/saas.js.map +1 -1
- package/dist/blueprints/vitrine.d.ts.map +1 -1
- package/dist/blueprints/vitrine.js +36 -0
- package/dist/blueprints/vitrine.js.map +1 -1
- package/dist/config-file.d.ts.map +1 -1
- package/dist/config-file.js +22 -0
- package/dist/config-file.js.map +1 -1
- package/dist/document-step.d.ts +35 -0
- package/dist/document-step.d.ts.map +1 -0
- package/dist/document-step.js +53 -0
- package/dist/document-step.js.map +1 -0
- package/dist/plan-flow.d.ts +51 -0
- package/dist/plan-flow.d.ts.map +1 -0
- package/dist/plan-flow.js +77 -0
- package/dist/plan-flow.js.map +1 -0
- package/dist/recap.d.ts +3 -0
- package/dist/recap.d.ts.map +1 -1
- package/dist/recap.js +26 -2
- package/dist/recap.js.map +1 -1
- package/dist/scaffold.d.ts +37 -0
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +113 -9
- package/dist/scaffold.js.map +1 -1
- package/dist/skin-flow.d.ts +22 -8
- package/dist/skin-flow.d.ts.map +1 -1
- package/dist/skin-flow.js +57 -29
- package/dist/skin-flow.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/wizard.d.ts +19 -3
- package/dist/wizard.d.ts.map +1 -1
- package/dist/wizard.js +254 -45
- package/dist/wizard.js.map +1 -1
- package/package.json +9 -9
package/dist/skin-flow.js
CHANGED
|
@@ -1,55 +1,83 @@
|
|
|
1
1
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { generateSkinCandidates } from '@cogenta/agents';
|
|
4
4
|
import { renderSkinPreview } from './skin-preview.js';
|
|
5
5
|
const DEFAULT_MAX_REGENERATIONS = 3;
|
|
6
|
-
async function
|
|
7
|
-
const
|
|
8
|
-
await mkdir(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
async function writePreviews(candidates, siteName, targetDir) {
|
|
7
|
+
const root = join(targetDir, '.cogenta', 'skin-preview');
|
|
8
|
+
await mkdir(root, { recursive: true });
|
|
9
|
+
await Promise.all(candidates.map(async (candidate) => {
|
|
10
|
+
const directory = join(root, candidate.id);
|
|
11
|
+
await mkdir(directory, { recursive: true });
|
|
12
|
+
const pages = renderSkinPreview(candidate.tokens, siteName);
|
|
13
|
+
await Promise.all(pages.map((page) => writeFile(join(directory, page.filename), page.html, 'utf8')));
|
|
14
|
+
}));
|
|
15
|
+
return root;
|
|
12
16
|
}
|
|
13
17
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* `--yes
|
|
20
|
-
*
|
|
18
|
+
* L19 task 3, in the installer: "l'utilisateur voit et choisit explicitement
|
|
19
|
+
* entre deux et cinq gabarits proposés, jamais un seul choix imposé."
|
|
20
|
+
*
|
|
21
|
+
* The shape of the round is what it was in L9 task 7 — generate, preview on
|
|
22
|
+
* three real pages, then accept / regenerate / fall back to the default,
|
|
23
|
+
* bounded so a non-interactive `--yes` run (whose `Prompter.choice` always
|
|
24
|
+
* answers with its default) never loops. What changed is that a round now
|
|
25
|
+
* produces several designs rather than one, each validated against contract
|
|
26
|
+
* D by `generateSkin`'s own loop, and the accept step is a pick among them.
|
|
27
|
+
*
|
|
28
|
+
* A round that cannot produce at least two distinct valid designs is not
|
|
29
|
+
* offered as a choice: it falls through to the next round, and eventually to
|
|
30
|
+
* the default skin, saying why. Presenting one option as if it were a
|
|
31
|
+
* decision is the failure mode this task exists to remove.
|
|
21
32
|
*/
|
|
22
33
|
export async function chooseSkin(options) {
|
|
23
34
|
const maxRegenerations = options.maxRegenerations ?? DEFAULT_MAX_REGENERATIONS;
|
|
24
35
|
let lastReason = 'no attempt was made';
|
|
25
36
|
for (let round = 1; round <= maxRegenerations; round++) {
|
|
26
|
-
options.out.detail(`Generating
|
|
27
|
-
const result = await
|
|
37
|
+
options.out.detail(`Generating design proposals from your description (round ${round}/${maxRegenerations})…`);
|
|
38
|
+
const result = await generateSkinCandidates({
|
|
28
39
|
client: options.client,
|
|
29
40
|
model: options.model,
|
|
30
41
|
description: options.description,
|
|
31
42
|
blueprintLabel: options.blueprintLabel,
|
|
43
|
+
...(options.candidateCount === undefined ? {} : { count: options.candidateCount }),
|
|
32
44
|
});
|
|
45
|
+
for (const failure of result.failures) {
|
|
46
|
+
options.out.warn(`The "${failure.label}" design was not offered: ${failure.reason}.`);
|
|
47
|
+
}
|
|
33
48
|
if (!result.ok) {
|
|
34
|
-
lastReason =
|
|
49
|
+
lastReason = `no usable choice of designs was produced: ${result.reason}`;
|
|
35
50
|
options.out.warn(lastReason);
|
|
36
51
|
break;
|
|
37
52
|
}
|
|
38
|
-
const
|
|
39
|
-
options.out.ok(
|
|
40
|
-
const
|
|
41
|
-
{
|
|
42
|
-
{ label: 'Regenerate (try again)', value: 'regenerate' },
|
|
43
|
-
{ label: 'Use the default skin instead', value: 'default' },
|
|
44
|
-
], 0);
|
|
45
|
-
if (choice === 'accept') {
|
|
46
|
-
return { kind: 'generated', tokens: result.tokens, attempts: result.attempts };
|
|
53
|
+
const previewRoot = await writePreviews(result.candidates, options.siteName, options.targetDir);
|
|
54
|
+
options.out.ok(`${result.candidates.length} designs generated and validated. Previews: ${previewRoot}`);
|
|
55
|
+
for (const candidate of result.candidates) {
|
|
56
|
+
options.out.detail(` ${candidate.label} — ${previewRoot}${join('', candidate.id)}`);
|
|
47
57
|
}
|
|
58
|
+
const choice = await options.prompter.choice('Which design do you want? (open the previews above to compare)', [
|
|
59
|
+
...result.candidates.map((candidate) => ({
|
|
60
|
+
label: candidate.label,
|
|
61
|
+
value: { kind: 'candidate', candidate },
|
|
62
|
+
hint: candidate.rationale,
|
|
63
|
+
})),
|
|
64
|
+
{ label: 'None of these — propose new ones', value: 'regenerate' },
|
|
65
|
+
{ label: 'None of these — use the default skin', value: 'default' },
|
|
66
|
+
], 0);
|
|
48
67
|
if (choice === 'default') {
|
|
49
|
-
return { kind: 'default', reason: 'the default skin was chosen over the generated
|
|
68
|
+
return { kind: 'default', reason: 'the default skin was chosen over the generated ones' };
|
|
69
|
+
}
|
|
70
|
+
if (choice !== 'regenerate') {
|
|
71
|
+
return {
|
|
72
|
+
kind: 'generated',
|
|
73
|
+
tokens: choice.candidate.tokens,
|
|
74
|
+
attempts: choice.candidate.attempts,
|
|
75
|
+
candidateId: choice.candidate.id,
|
|
76
|
+
candidateLabel: choice.candidate.label,
|
|
77
|
+
offered: result.candidates.length,
|
|
78
|
+
};
|
|
50
79
|
}
|
|
51
|
-
|
|
52
|
-
lastReason = `${maxRegenerations} regeneration round${maxRegenerations === 1 ? '' : 's'} were used without accepting a result`;
|
|
80
|
+
lastReason = `${maxRegenerations} regeneration round${maxRegenerations === 1 ? '' : 's'} were used without picking a design`;
|
|
53
81
|
}
|
|
54
82
|
return { kind: 'default', reason: lastReason };
|
|
55
83
|
}
|
package/dist/skin-flow.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skin-flow.js","sourceRoot":"","sources":["../src/skin-flow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"skin-flow.js","sourceRoot":"","sources":["../src/skin-flow.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -14,6 +14,14 @@ export interface WizardAnswers {
|
|
|
14
14
|
/** Free text (sector, mood, audience, brand colours) driving AI skin generation (L9 task 7). Empty or absent: generation is skipped, the default skin is used. */
|
|
15
15
|
readonly siteDescription?: string;
|
|
16
16
|
readonly adminEmail: string;
|
|
17
|
+
/**
|
|
18
|
+
* Specification documents to read before anything else (L19 task 6).
|
|
19
|
+
* Absent — which is the default everywhere, including `--yes` — and the
|
|
20
|
+
* installer behaves exactly as it did before L19 existed (R2).
|
|
21
|
+
*/
|
|
22
|
+
readonly documentPaths?: readonly string[];
|
|
23
|
+
/** Answers to L19 task 8's per-site-type recommendations, by setting id. Unanswered ids fall back to the recommendation. */
|
|
24
|
+
readonly blueprintSettings?: Readonly<Record<string, boolean>>;
|
|
17
25
|
}
|
|
18
26
|
export declare function defaultAnswers(targetDir: string, siteName: string): WizardAnswers;
|
|
19
27
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD,yGAAyG;AACzG,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,cAAc,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAA;IACxD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAA;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,kKAAkK;IAClK,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD,yGAAyG;AACzG,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,cAAc,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAA;IACxD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,WAAW,EAAE,aAAa,CAAA;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,kKAAkK;IAClK,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1C,4HAA4H;IAC5H,QAAQ,CAAC,iBAAiB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CAC/D;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CAWjF"}
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA2BA,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,QAAgB;IAChE,OAAO;QACL,SAAS;QACT,QAAQ;QACR,OAAO,EAAE,uBAAuB;QAChC,aAAa,EAAE,IAAI;QACnB,WAAW,EAAE,OAAO;QACpB,cAAc,EAAE,QAAQ;QACxB,WAAW,EAAE,MAAM;QACnB,UAAU,EAAE,mBAAmB;KAChC,CAAA;AACH,CAAC"}
|
package/dist/wizard.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SitePlanDraft } from '@cogenta/agents';
|
|
1
2
|
import type { Output } from '@cogenta/cli';
|
|
2
3
|
import type { Prompter } from './prompts.js';
|
|
3
4
|
export interface RunWizardOptions {
|
|
@@ -7,11 +8,26 @@ export interface RunWizardOptions {
|
|
|
7
8
|
readonly out: Output;
|
|
8
9
|
readonly configPath?: string;
|
|
9
10
|
readonly env?: Record<string, string | undefined>;
|
|
11
|
+
/** Where a relative document path typed by the user is resolved from. Defaults to `process.cwd()`. */
|
|
12
|
+
readonly cwd?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Test seam only — the same one `llm-setup.ts` already carries. It lets a
|
|
15
|
+
* test drive the whole installer, document step included, without a key
|
|
16
|
+
* and without the network, rather than mocking a shared module.
|
|
17
|
+
*/
|
|
18
|
+
readonly fetchImpl?: typeof fetch;
|
|
10
19
|
}
|
|
11
20
|
/**
|
|
12
|
-
* The whole
|
|
13
|
-
*
|
|
14
|
-
*
|
|
21
|
+
* The whole wizard, orchestrated. Returns a process exit code: `0` a working
|
|
22
|
+
* site, `1` the environment or the install failed, `2` a `--config` file was
|
|
23
|
+
* invalid.
|
|
24
|
+
*
|
|
25
|
+
* L19 inserts one optional step ahead of everything else — read a
|
|
26
|
+
* specification document, propose a plan, let a human approve it item by
|
|
27
|
+
* item — and changes nothing about the run that declines it. With no
|
|
28
|
+
* provider configured, or with `--yes`, that step is never entered and the
|
|
29
|
+
* site produced is the one this installer produced before L19 existed.
|
|
15
30
|
*/
|
|
16
31
|
export declare function runWizard(options: RunWizardOptions): Promise<number>;
|
|
32
|
+
export type { SitePlanDraft };
|
|
17
33
|
//# sourceMappingURL=wizard.d.ts.map
|
package/dist/wizard.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"wizard.d.ts","sourceRoot":"","sources":["../src/wizard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,aAAa,EAAE,MAAM,iBAAiB,CAAA;AACvE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAkB1C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAM5C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;IACjD,sGAAsG;IACtG,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CAClC;AAkLD;;;;;;;;;;GAUG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CA+K1E;AAsGD,YAAY,EAAE,aAAa,EAAE,CAAA"}
|
package/dist/wizard.js
CHANGED
|
@@ -1,35 +1,91 @@
|
|
|
1
|
+
import { blueprintSettings, inferBlueprint, resolveBlueprintSettings, } from './blueprint-defaults.js';
|
|
1
2
|
import { BLUEPRINT_CONTENT_PACKS } from './blueprints/content-packs.js';
|
|
2
3
|
import { BLUEPRINTS, resolveBlueprint } from './blueprints/registry.js';
|
|
3
4
|
import { loadConfigFile } from './config-file.js';
|
|
5
|
+
import { collectDocuments, readDocuments } from './document-step.js';
|
|
4
6
|
import { checkEnvironment } from './environment.js';
|
|
5
7
|
import { createProviderClient, LLM_PROVIDERS, validateApiKey, } from './llm-setup.js';
|
|
8
|
+
import { runPlanFlow } from './plan-flow.js';
|
|
6
9
|
import { printRecap } from './recap.js';
|
|
7
10
|
import { scaffoldSite } from './scaffold.js';
|
|
8
11
|
import { chooseSkin } from './skin-flow.js';
|
|
9
12
|
import { defaultAnswers } from './types.js';
|
|
10
|
-
|
|
13
|
+
/**
|
|
14
|
+
* The provider question, asked before everything else now.
|
|
15
|
+
*
|
|
16
|
+
* It moved for one reason: L19's document step needs a model, and the lot
|
|
17
|
+
* puts that step "avant même de poser les questions actuelles". Nothing else
|
|
18
|
+
* changed about it — `none` is still the default, still the first option,
|
|
19
|
+
* and answering it still leaves an installer that asks nothing further about
|
|
20
|
+
* AI and produces the same site it always did (R2).
|
|
21
|
+
*/
|
|
22
|
+
async function collectLlmSetup(prompter, fetchImpl) {
|
|
23
|
+
const provider = await prompter.choice('LLM provider (optional — Cogenta works fully without one)', LLM_PROVIDERS.map((entry) => ({ label: entry.label, value: entry.id })), 0);
|
|
24
|
+
if (provider === 'none')
|
|
25
|
+
return { provider };
|
|
26
|
+
const option = LLM_PROVIDERS.find((entry) => entry.id === provider);
|
|
27
|
+
const model = await prompter.text('Model', option?.defaultModel ?? '');
|
|
28
|
+
const apiKey = await prompter.text('API key', '');
|
|
29
|
+
if (apiKey === '')
|
|
30
|
+
return { provider, model };
|
|
31
|
+
const validation = await validateApiKey({
|
|
32
|
+
provider,
|
|
33
|
+
apiKey,
|
|
34
|
+
model,
|
|
35
|
+
...(fetchImpl === undefined ? {} : { fetchImpl }),
|
|
36
|
+
});
|
|
37
|
+
return { provider, model, apiKey, validation };
|
|
38
|
+
}
|
|
39
|
+
async function collectAnswers(prompter, out, targetDir, siteName, detectedDatabases, llm, prefill) {
|
|
11
40
|
const defaults = defaultAnswers(targetDir, siteName);
|
|
41
|
+
if (prefill.because.length > 0) {
|
|
42
|
+
out.heading('Pre-filled from your document');
|
|
43
|
+
out.line('Every answer below is only a suggestion. Change any of them.');
|
|
44
|
+
for (const line of prefill.because)
|
|
45
|
+
out.detail(line);
|
|
46
|
+
}
|
|
12
47
|
const name = await prompter.text('Site name', defaults.siteName);
|
|
13
48
|
const url = await prompter.text('Site URL', defaults.siteUrl);
|
|
14
|
-
const locale = await prompter.text('Primary language (locale code)', defaults.defaultLocale);
|
|
15
|
-
const
|
|
49
|
+
const locale = await prompter.text('Primary language (locale code)', prefill.defaultLocale ?? defaults.defaultLocale);
|
|
50
|
+
const blueprintIndex = Math.max(0, BLUEPRINTS.findIndex((entry) => entry.id === (prefill.blueprintId ?? defaults.blueprintId)));
|
|
51
|
+
const blueprintId = await prompter.choice('Site type', BLUEPRINTS.map((entry) => ({ label: entry.label, value: entry.id })), blueprintIndex);
|
|
52
|
+
// Postgres and MySQL are always offered, not only when a local server is
|
|
53
|
+
// detected — a real site is as likely to point at a managed remote
|
|
54
|
+
// database (Neon, PlanetScale, a hosting provider's MySQL) as at one
|
|
55
|
+
// running on this machine, and hiding the option entirely made those two
|
|
56
|
+
// of the three supported drivers unreachable from the wizard.
|
|
16
57
|
const databaseChoices = [
|
|
17
|
-
{ label: 'SQLite (default —
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
:
|
|
21
|
-
|
|
58
|
+
{ label: 'SQLite (default — no separate database server needed)', value: 'sqlite' },
|
|
59
|
+
{
|
|
60
|
+
label: detectedDatabases.postgres ? 'Postgres (detected locally)' : 'Postgres',
|
|
61
|
+
value: 'postgres',
|
|
62
|
+
},
|
|
63
|
+
{ label: detectedDatabases.mysql ? 'MySQL (detected locally)' : 'MySQL', value: 'mysql' },
|
|
22
64
|
];
|
|
23
65
|
const databaseDriver = await prompter.choice('Database', databaseChoices, 0);
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
66
|
+
let databaseUrl;
|
|
67
|
+
if (databaseDriver === 'postgres' && !detectedDatabases.postgres) {
|
|
68
|
+
databaseUrl = await prompter.text('Postgres connection URL', '');
|
|
69
|
+
}
|
|
70
|
+
else if (databaseDriver === 'mysql' && !detectedDatabases.mysql) {
|
|
71
|
+
databaseUrl = await prompter.text('MySQL connection URL', '');
|
|
72
|
+
}
|
|
73
|
+
// Only asked when no document already answered it: a plan carries its own
|
|
74
|
+
// designs, generated from the brief, and asking for the same information
|
|
75
|
+
// twice is how an installer earns its reputation.
|
|
76
|
+
let siteDescription = prefill.siteDescription;
|
|
77
|
+
if (llm.provider !== 'none' && prefill.siteDescription === undefined) {
|
|
78
|
+
siteDescription = await prompter.text('Site description for AI design generation (sector, mood, audience, brand colours — leave blank to skip and keep the default skin)', '');
|
|
79
|
+
}
|
|
80
|
+
// L19 task 8 — the per-site-type recommendations, confirmed one at a time.
|
|
81
|
+
const recommendations = blueprintSettings(blueprintId);
|
|
82
|
+
const settingAnswers = {};
|
|
83
|
+
if (recommendations.settings.length > 0) {
|
|
84
|
+
out.heading('Defaults for this kind of site');
|
|
85
|
+
for (const setting of recommendations.settings) {
|
|
86
|
+
out.detail(setting.why);
|
|
87
|
+
settingAnswers[setting.id] = await prompter.confirm(setting.question, setting.recommended);
|
|
88
|
+
}
|
|
33
89
|
}
|
|
34
90
|
const adminEmail = await prompter.text('Admin email', defaults.adminEmail);
|
|
35
91
|
return {
|
|
@@ -39,21 +95,50 @@ async function collectAnswers(prompter, targetDir, siteName, detectedDatabases)
|
|
|
39
95
|
defaultLocale: locale,
|
|
40
96
|
blueprintId,
|
|
41
97
|
databaseDriver,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
...(
|
|
98
|
+
...(databaseUrl === undefined || databaseUrl === '' ? {} : { databaseUrl }),
|
|
99
|
+
llmProvider: llm.provider,
|
|
100
|
+
...(llm.model === undefined || llm.model === '' ? {} : { llmModel: llm.model }),
|
|
101
|
+
...(llm.apiKey === undefined || llm.apiKey === '' ? {} : { llmApiKey: llm.apiKey }),
|
|
45
102
|
...(siteDescription === undefined || siteDescription === '' ? {} : { siteDescription }),
|
|
46
103
|
adminEmail,
|
|
104
|
+
blueprintSettings: settingAnswers,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function prefillFrom(plan) {
|
|
108
|
+
if (plan === undefined || plan.kind === 'failed')
|
|
109
|
+
return { because: [] };
|
|
110
|
+
const brief = plan.draft.brief;
|
|
111
|
+
const locale = (plan.kind === 'reviewed' ? plan.approved.locales[0] : undefined) ?? brief.languages[0];
|
|
112
|
+
const blueprintId = inferBlueprint(brief);
|
|
113
|
+
const because = [];
|
|
114
|
+
if (locale !== undefined)
|
|
115
|
+
because.push(`Language “${locale}” — from the brief.`);
|
|
116
|
+
if (blueprintId !== undefined) {
|
|
117
|
+
because.push(`Site type “${blueprintId}” — matched from what the brief describes.`);
|
|
118
|
+
}
|
|
119
|
+
because.push(`Design description — the brief's own summary.`);
|
|
120
|
+
return {
|
|
121
|
+
...(locale === undefined ? {} : { defaultLocale: locale }),
|
|
122
|
+
...(blueprintId === undefined ? {} : { blueprintId }),
|
|
123
|
+
siteDescription: brief.summary,
|
|
124
|
+
because,
|
|
47
125
|
};
|
|
48
126
|
}
|
|
49
127
|
/**
|
|
50
|
-
* The whole
|
|
51
|
-
*
|
|
52
|
-
*
|
|
128
|
+
* The whole wizard, orchestrated. Returns a process exit code: `0` a working
|
|
129
|
+
* site, `1` the environment or the install failed, `2` a `--config` file was
|
|
130
|
+
* invalid.
|
|
131
|
+
*
|
|
132
|
+
* L19 inserts one optional step ahead of everything else — read a
|
|
133
|
+
* specification document, propose a plan, let a human approve it item by
|
|
134
|
+
* item — and changes nothing about the run that declines it. With no
|
|
135
|
+
* provider configured, or with `--yes`, that step is never entered and the
|
|
136
|
+
* site produced is the one this installer produced before L19 existed.
|
|
53
137
|
*/
|
|
54
138
|
export async function runWizard(options) {
|
|
55
139
|
const { out, prompter } = options;
|
|
56
140
|
const env = options.env ?? process.env;
|
|
141
|
+
const cwd = options.cwd ?? process.cwd();
|
|
57
142
|
const environment = await checkEnvironment({ targetDir: options.targetDir, env });
|
|
58
143
|
out.heading('Environment');
|
|
59
144
|
for (const check of environment.checks) {
|
|
@@ -71,6 +156,8 @@ export async function runWizard(options) {
|
|
|
71
156
|
return 1;
|
|
72
157
|
}
|
|
73
158
|
let answers;
|
|
159
|
+
let llm;
|
|
160
|
+
let plan;
|
|
74
161
|
if (options.configPath !== undefined) {
|
|
75
162
|
try {
|
|
76
163
|
answers = await loadConfigFile(options.configPath, options.targetDir);
|
|
@@ -80,40 +167,61 @@ export async function runWizard(options) {
|
|
|
80
167
|
prompter.close();
|
|
81
168
|
return 2;
|
|
82
169
|
}
|
|
170
|
+
llm = {
|
|
171
|
+
provider: answers.llmProvider,
|
|
172
|
+
...(answers.llmModel === undefined ? {} : { model: answers.llmModel }),
|
|
173
|
+
...(answers.llmApiKey === undefined ? {} : { apiKey: answers.llmApiKey }),
|
|
174
|
+
};
|
|
175
|
+
if (llm.provider !== 'none' && llm.apiKey !== undefined && llm.apiKey !== '') {
|
|
176
|
+
llm = {
|
|
177
|
+
...llm,
|
|
178
|
+
validation: await validateApiKey({
|
|
179
|
+
provider: llm.provider,
|
|
180
|
+
apiKey: llm.apiKey,
|
|
181
|
+
model: llm.model ?? '',
|
|
182
|
+
...(options.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
183
|
+
}),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
plan = await runDocumentStepFromConfig({
|
|
187
|
+
answers,
|
|
188
|
+
llm,
|
|
189
|
+
out,
|
|
190
|
+
cwd,
|
|
191
|
+
...(options.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
192
|
+
});
|
|
83
193
|
}
|
|
84
194
|
else {
|
|
85
|
-
|
|
195
|
+
llm = await collectLlmSetup(prompter, options.fetchImpl);
|
|
196
|
+
plan = await runDocumentStepInteractively({
|
|
197
|
+
llm,
|
|
198
|
+
prompter,
|
|
199
|
+
out,
|
|
200
|
+
cwd,
|
|
201
|
+
...(options.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
202
|
+
});
|
|
203
|
+
answers = await collectAnswers(prompter, out, options.targetDir, options.siteName, {
|
|
86
204
|
postgres: environment.detectedDatabases.includes('postgres'),
|
|
87
205
|
mysql: environment.detectedDatabases.includes('mysql'),
|
|
88
|
-
});
|
|
206
|
+
}, llm, prefillFrom(plan));
|
|
89
207
|
}
|
|
90
208
|
const resolvedBlueprint = resolveBlueprint(answers.blueprintId);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
llmModel = answers.llmModel ?? option?.defaultModel ?? '';
|
|
98
|
-
keyValidation = await validateApiKey({
|
|
99
|
-
provider: answers.llmProvider,
|
|
100
|
-
apiKey: answers.llmApiKey,
|
|
101
|
-
model: llmModel,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
// "Aperçu proposé sur trois pages types, avec possibilité de régénérer ou
|
|
105
|
-
// d'ajuster" (L9 task 7) needs the prompter, so it stays open until here —
|
|
106
|
-
// only a blueprint with a real content pack writes a `theme.tokens.json` a
|
|
107
|
-
// generated skin could replace.
|
|
209
|
+
const keyValidation = llm.validation;
|
|
210
|
+
const llmModel = llm.model ?? '';
|
|
211
|
+
// A reviewed plan already carries the design its owner picked, so the
|
|
212
|
+
// separate skin round is skipped rather than asking the same question a
|
|
213
|
+
// second time. Everything else about it is unchanged from L9 task 7.
|
|
214
|
+
const approvedSkin = plan?.kind === 'reviewed' ? plan.approved.skin : undefined;
|
|
108
215
|
let skinOutcome;
|
|
109
|
-
if (
|
|
216
|
+
if (approvedSkin === undefined &&
|
|
217
|
+
BLUEPRINT_CONTENT_PACKS[resolvedBlueprint.blueprint.id] !== undefined &&
|
|
110
218
|
answers.llmProvider !== 'none' &&
|
|
111
219
|
answers.llmApiKey !== undefined &&
|
|
112
220
|
answers.llmApiKey !== '' &&
|
|
113
221
|
keyValidation?.valid === true &&
|
|
114
222
|
answers.siteDescription !== undefined &&
|
|
115
223
|
answers.siteDescription !== '') {
|
|
116
|
-
out.heading('
|
|
224
|
+
out.heading('Design proposals');
|
|
117
225
|
skinOutcome = await chooseSkin({
|
|
118
226
|
prompter,
|
|
119
227
|
out,
|
|
@@ -121,6 +229,7 @@ export async function runWizard(options) {
|
|
|
121
229
|
provider: answers.llmProvider,
|
|
122
230
|
apiKey: answers.llmApiKey,
|
|
123
231
|
model: llmModel,
|
|
232
|
+
...(options.fetchImpl === undefined ? {} : { fetchImpl: options.fetchImpl }),
|
|
124
233
|
}),
|
|
125
234
|
model: llmModel,
|
|
126
235
|
description: answers.siteDescription,
|
|
@@ -130,11 +239,17 @@ export async function runWizard(options) {
|
|
|
130
239
|
});
|
|
131
240
|
}
|
|
132
241
|
prompter.close();
|
|
242
|
+
const confirmed = resolveBlueprintSettings(resolvedBlueprint.blueprint.id, answers.blueprintSettings ?? {});
|
|
243
|
+
const approved = plan?.kind === 'reviewed' ? plan.approved : undefined;
|
|
244
|
+
const locales = approved !== undefined && approved.locales.length > 0
|
|
245
|
+
? [...new Set([answers.defaultLocale, ...approved.locales])]
|
|
246
|
+
: [answers.defaultLocale];
|
|
133
247
|
const scaffold = await scaffoldSite({
|
|
134
248
|
targetDir: answers.targetDir,
|
|
135
249
|
siteName: answers.siteName,
|
|
136
250
|
siteUrl: answers.siteUrl,
|
|
137
251
|
defaultLocale: answers.defaultLocale,
|
|
252
|
+
locales,
|
|
138
253
|
databaseDriver: answers.databaseDriver,
|
|
139
254
|
...(answers.databaseUrl === undefined ? {} : { databaseUrl: answers.databaseUrl }),
|
|
140
255
|
...(answers.llmProvider === 'none'
|
|
@@ -142,7 +257,24 @@ export async function runWizard(options) {
|
|
|
142
257
|
: { llm: { provider: answers.llmProvider, model: answers.llmModel ?? '' } }),
|
|
143
258
|
adminEmail: answers.adminEmail,
|
|
144
259
|
blueprintId: resolvedBlueprint.blueprint.id,
|
|
145
|
-
|
|
260
|
+
security: { pageMaxAge: confirmed.pageMaxAge, hstsMaxAge: confirmed.hstsMaxAge },
|
|
261
|
+
seedDemoContent: confirmed.seedDemoContent,
|
|
262
|
+
...(approvedSkin === undefined
|
|
263
|
+
? skinOutcome?.kind === 'generated'
|
|
264
|
+
? { skinTokens: skinOutcome.tokens }
|
|
265
|
+
: {}
|
|
266
|
+
: { skinTokens: approvedSkin }),
|
|
267
|
+
...(approved === undefined
|
|
268
|
+
? {}
|
|
269
|
+
: {
|
|
270
|
+
approvedCollections: approved.collections,
|
|
271
|
+
approvedDemoContent: approved.demoContent,
|
|
272
|
+
}),
|
|
273
|
+
// A proposal nobody reviewed is stored, never applied.
|
|
274
|
+
...(plan?.kind === 'deferred' ? { sitePlan: { draft: plan.draft } } : {}),
|
|
275
|
+
...(plan?.kind === 'reviewed'
|
|
276
|
+
? { sitePlan: { draft: plan.draft, decisions: plan.decisions } }
|
|
277
|
+
: {}),
|
|
146
278
|
}, env);
|
|
147
279
|
printRecap({
|
|
148
280
|
answers,
|
|
@@ -151,7 +283,84 @@ export async function runWizard(options) {
|
|
|
151
283
|
scaffold,
|
|
152
284
|
...(keyValidation === undefined ? {} : { keyValidation }),
|
|
153
285
|
...(skinOutcome === undefined ? {} : { skinOutcome }),
|
|
286
|
+
...(plan === undefined ? {} : { plan }),
|
|
154
287
|
}, out);
|
|
155
288
|
return scaffold.migrateExitCode === 0 && scaffold.usersExitCode === 0 ? 0 : 1;
|
|
156
289
|
}
|
|
290
|
+
function canPlan(llm) {
|
|
291
|
+
return (llm.provider !== 'none' &&
|
|
292
|
+
llm.apiKey !== undefined &&
|
|
293
|
+
llm.apiKey !== '' &&
|
|
294
|
+
llm.validation?.valid === true);
|
|
295
|
+
}
|
|
296
|
+
async function planFrom(input) {
|
|
297
|
+
if (input.documents.length === 0 || input.llm.provider === 'none')
|
|
298
|
+
return undefined;
|
|
299
|
+
const provider = input.llm.provider;
|
|
300
|
+
return runPlanFlow({
|
|
301
|
+
prompter: input.prompter,
|
|
302
|
+
out: input.out,
|
|
303
|
+
client: createProviderClient({
|
|
304
|
+
provider,
|
|
305
|
+
apiKey: input.llm.apiKey ?? '',
|
|
306
|
+
model: input.llm.model ?? '',
|
|
307
|
+
...(input.fetchImpl === undefined ? {} : { fetchImpl: input.fetchImpl }),
|
|
308
|
+
}),
|
|
309
|
+
model: input.llm.model ?? '',
|
|
310
|
+
documents: input.documents,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
async function runDocumentStepInteractively(input) {
|
|
314
|
+
// Never even asked without a working provider: a question whose only
|
|
315
|
+
// possible answer is "no" is noise, and R2 means that answer must remain
|
|
316
|
+
// a complete, unremarkable path through this installer.
|
|
317
|
+
if (!canPlan(input.llm))
|
|
318
|
+
return undefined;
|
|
319
|
+
const collected = await collectDocuments({
|
|
320
|
+
prompter: input.prompter,
|
|
321
|
+
out: input.out,
|
|
322
|
+
cwd: input.cwd,
|
|
323
|
+
});
|
|
324
|
+
return planFrom({ ...input, documents: collected.documents });
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* `--config` with a `documents` list. The same analysis runs, but the review
|
|
328
|
+
* cannot: `Prompter.confirm` answers its own default in a non-interactive
|
|
329
|
+
* run, and `runPlanFlow`'s default is "do not review". The plan is therefore
|
|
330
|
+
* saved as a draft, and the site is scaffolded exactly as the rest of the
|
|
331
|
+
* config file describes.
|
|
332
|
+
*/
|
|
333
|
+
async function runDocumentStepFromConfig(input) {
|
|
334
|
+
const paths = input.answers.documentPaths ?? [];
|
|
335
|
+
if (paths.length === 0)
|
|
336
|
+
return undefined;
|
|
337
|
+
if (!canPlan(input.llm)) {
|
|
338
|
+
input.out.warn('Documents were listed but no working LLM provider is configured, so they were not read. The site was created from the rest of the config file.');
|
|
339
|
+
return undefined;
|
|
340
|
+
}
|
|
341
|
+
const read = await readDocuments(paths, input.cwd);
|
|
342
|
+
for (const failure of read.failures)
|
|
343
|
+
input.out.bad(failure);
|
|
344
|
+
if (read.documents.length === 0)
|
|
345
|
+
return undefined;
|
|
346
|
+
return planFrom({
|
|
347
|
+
documents: read.documents,
|
|
348
|
+
llm: input.llm,
|
|
349
|
+
out: input.out,
|
|
350
|
+
...(input.fetchImpl === undefined ? {} : { fetchImpl: input.fetchImpl }),
|
|
351
|
+
// A prompter that always declines: this path must never claim consent.
|
|
352
|
+
prompter: {
|
|
353
|
+
async text(_question, defaultValue) {
|
|
354
|
+
return defaultValue;
|
|
355
|
+
},
|
|
356
|
+
async choice(_question, choices, defaultIndex) {
|
|
357
|
+
return (choices[defaultIndex] ?? choices[0])?.value;
|
|
358
|
+
},
|
|
359
|
+
async confirm(_question, defaultValue) {
|
|
360
|
+
return defaultValue;
|
|
361
|
+
},
|
|
362
|
+
close() { },
|
|
363
|
+
},
|
|
364
|
+
});
|
|
365
|
+
}
|
|
157
366
|
//# sourceMappingURL=wizard.js.map
|