@contentful/experience-design-system-cli 2.32.1-dev-build-6b922ec.0 → 2.32.1-dev-build-b78fe18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +1 -2
- package/dist/src/credentials-store.d.ts +23 -0
- package/dist/src/index.js +846 -1339
- package/dist/src/setup/analytics-prompt.d.ts +13 -0
- package/dist/src/setup/auto-filter-prompt.d.ts +13 -0
- package/dist/src/setup/command.d.ts +13 -4
- package/dist/src/setup/composition-mode-prompt.d.ts +14 -0
- package/dist/src/setup/debug-mode-prompt.d.ts +11 -0
- package/package.json +6 -7
- package/dist/src/doctor/checks.d.ts +0 -5
- package/dist/src/doctor/command.d.ts +0 -7
- package/dist/src/doctor/report.d.ts +0 -12
- package/dist/src/lib/agent-definitions.d.ts +0 -7
- package/dist/src/setup/lib/checks.d.ts +0 -69
- package/dist/src/setup/lib/layout.d.ts +0 -34
- package/dist/src/setup/lib/prompt-input.d.ts +0 -17
- package/dist/src/setup/lib/shell.d.ts +0 -15
- package/dist/src/setup/lib/types.d.ts +0 -55
- package/dist/src/setup/lib/yes-no-prompt.d.ts +0 -8
- package/dist/src/setup/steps/coding-agent.d.ts +0 -2
- package/dist/src/setup/steps/contentful.d.ts +0 -2
- package/dist/src/setup/steps/preferences/analytics.d.ts +0 -5
- package/dist/src/setup/steps/preferences/auto-filter.d.ts +0 -4
- package/dist/src/setup/steps/preferences/concurrency.d.ts +0 -3
- package/dist/src/setup/steps/preferences/custom-prompts.d.ts +0 -8
- package/dist/src/setup/steps/preferences/debug.d.ts +0 -4
- package/dist/src/setup/steps/preferences/index.d.ts +0 -41
- package/dist/src/setup/steps/preferences/no-color.d.ts +0 -3
- package/dist/src/setup/steps/prerequisites/build.d.ts +0 -2
- package/dist/src/setup/steps/prerequisites/index.d.ts +0 -8
- package/dist/src/setup/steps/prerequisites/node.d.ts +0 -4
- package/dist/src/setup/steps/prerequisites/pnpm.d.ts +0 -2
- package/dist/src/setup/tui/SetupScreen.d.ts +0 -30
- package/dist/src/setup/tui/SetupStepper.d.ts +0 -7
- package/dist/src/setup/tui/usePromptInput.d.ts +0 -19
package/dist/src/index.js
CHANGED
|
@@ -297,10 +297,10 @@ function codexBedrockConfigArgs() {
|
|
|
297
297
|
const region = process.env.AWS_REGION?.trim() || process.env.AWS_DEFAULT_REGION?.trim() || DEFAULT_CODEX_BEDROCK_REGION;
|
|
298
298
|
return ["-c", "model_provider=amazon-bedrock", "-c", `model_providers.amazon-bedrock.region=${region}`];
|
|
299
299
|
}
|
|
300
|
-
function buildArgs(agent,
|
|
300
|
+
function buildArgs(agent, prompt2, model, promptViaStdin = false, bedrock = false) {
|
|
301
301
|
const resolvedModel = resolveAgentModel(agent, model, bedrock);
|
|
302
302
|
const modelArg = resolvedModel ? ["--model", resolvedModel] : [];
|
|
303
|
-
const promptArg = promptViaStdin ? [] : [
|
|
303
|
+
const promptArg = promptViaStdin ? [] : [prompt2];
|
|
304
304
|
switch (agent) {
|
|
305
305
|
case "claude":
|
|
306
306
|
return ["--print", ...modelArg, ...promptArg];
|
|
@@ -320,11 +320,11 @@ function buildArgs(agent, prompt, model, promptViaStdin = false, bedrock = false
|
|
|
320
320
|
}
|
|
321
321
|
}
|
|
322
322
|
async function runAgent(options) {
|
|
323
|
-
const { agent, prompt, timeoutMs, model, onOutput, promptViaStdin, onDebugEvent } = options;
|
|
323
|
+
const { agent, prompt: prompt2, timeoutMs, model, onOutput, promptViaStdin, onDebugEvent } = options;
|
|
324
324
|
const bedrock = options.bedrock ?? process.env.EDS_BEDROCK === "1";
|
|
325
325
|
const binary = resolveBinary(agent);
|
|
326
|
-
const
|
|
327
|
-
const args = buildArgs(agent,
|
|
326
|
+
const useStdin2 = !!promptViaStdin;
|
|
327
|
+
const args = buildArgs(agent, prompt2, model, useStdin2, bedrock);
|
|
328
328
|
const startedAt = Date.now();
|
|
329
329
|
onDebugEvent?.("run.start", {
|
|
330
330
|
agent,
|
|
@@ -332,8 +332,8 @@ async function runAgent(options) {
|
|
|
332
332
|
model,
|
|
333
333
|
bedrock: !!bedrock,
|
|
334
334
|
timeoutMs,
|
|
335
|
-
promptLen:
|
|
336
|
-
promptHead:
|
|
335
|
+
promptLen: prompt2.length,
|
|
336
|
+
promptHead: prompt2.slice(0, 500)
|
|
337
337
|
});
|
|
338
338
|
return new Promise((resolve27) => {
|
|
339
339
|
const bedrockEnv = bedrock ? BEDROCK_ENV_BY_AGENT[agent] : void 0;
|
|
@@ -341,10 +341,10 @@ async function runAgent(options) {
|
|
|
341
341
|
stdio: ["pipe", "pipe", "pipe"],
|
|
342
342
|
...bedrockEnv ? { env: { ...process.env, ...bedrockEnv } } : {}
|
|
343
343
|
});
|
|
344
|
-
if (
|
|
344
|
+
if (useStdin2 && child.stdin) {
|
|
345
345
|
child.stdin.on("error", () => {
|
|
346
346
|
});
|
|
347
|
-
child.stdin.write(
|
|
347
|
+
child.stdin.write(prompt2, () => {
|
|
348
348
|
child.stdin?.end();
|
|
349
349
|
});
|
|
350
350
|
} else {
|
|
@@ -13370,10 +13370,10 @@ function parseJsonBody(body) {
|
|
|
13370
13370
|
const p = asRecord(parsed);
|
|
13371
13371
|
if (!p) return null;
|
|
13372
13372
|
const details = asRecord(p.details) ?? {};
|
|
13373
|
-
const
|
|
13374
|
-
const codeRaw =
|
|
13375
|
-
const messageRaw =
|
|
13376
|
-
const cycleRaw =
|
|
13373
|
+
const pick2 = (k) => p[k] !== void 0 ? p[k] : details[k];
|
|
13374
|
+
const codeRaw = pick2("code") ?? asRecord(p.sys)?.id;
|
|
13375
|
+
const messageRaw = pick2("message");
|
|
13376
|
+
const cycleRaw = pick2("cycle");
|
|
13377
13377
|
const out = {};
|
|
13378
13378
|
if (typeof codeRaw === "string") out.code = codeRaw;
|
|
13379
13379
|
if (typeof messageRaw === "string") out.message = messageRaw;
|
|
@@ -29780,13 +29780,13 @@ __export(push_creds_prompt_exports, {
|
|
|
29780
29780
|
});
|
|
29781
29781
|
import React29 from "react";
|
|
29782
29782
|
async function promptForPushCredentials(opts = {}) {
|
|
29783
|
-
const { render: render7, Box:
|
|
29784
|
-
const { useState:
|
|
29783
|
+
const { render: render7, Box: Box50, Text: Text52 } = await import("ink");
|
|
29784
|
+
const { useState: useState29 } = await import("react");
|
|
29785
29785
|
const { CredentialsStep: CredentialsStep2 } = await Promise.resolve().then(() => (init_CredentialsStep(), CredentialsStep_exports));
|
|
29786
29786
|
return new Promise((resolve27, reject) => {
|
|
29787
29787
|
let app = null;
|
|
29788
29788
|
function App2() {
|
|
29789
|
-
const [done, setDone] =
|
|
29789
|
+
const [done, setDone] = useState29(false);
|
|
29790
29790
|
const handle = (spaceId, environmentId, cmaToken, host) => {
|
|
29791
29791
|
if (done) return;
|
|
29792
29792
|
setDone(true);
|
|
@@ -29796,7 +29796,7 @@ async function promptForPushCredentials(opts = {}) {
|
|
|
29796
29796
|
});
|
|
29797
29797
|
};
|
|
29798
29798
|
if (done) {
|
|
29799
|
-
return React29.createElement(
|
|
29799
|
+
return React29.createElement(Box50, null, React29.createElement(Text52, null, ""));
|
|
29800
29800
|
}
|
|
29801
29801
|
return React29.createElement(CredentialsStep2, {
|
|
29802
29802
|
summary: opts.summary ?? "Enter Contentful credentials to push this run. Press Enter on each field to advance.",
|
|
@@ -29821,1116 +29821,11 @@ var init_push_creds_prompt = __esm({
|
|
|
29821
29821
|
}
|
|
29822
29822
|
});
|
|
29823
29823
|
|
|
29824
|
-
// packages/experience-design-system-cli/src/lib/agent-definitions.ts
|
|
29825
|
-
var AGENT_DEFS;
|
|
29826
|
-
var init_agent_definitions = __esm({
|
|
29827
|
-
"packages/experience-design-system-cli/src/lib/agent-definitions.ts"() {
|
|
29828
|
-
"use strict";
|
|
29829
|
-
AGENT_DEFS = [
|
|
29830
|
-
{ name: "Claude Code", binary: "claude", installHint: "npm install -g @anthropic-ai/claude-code && claude login" },
|
|
29831
|
-
{ name: "OpenAI Codex", binary: "codex", installHint: "npm install -g @openai/codex (requires OPENAI_API_KEY)" },
|
|
29832
|
-
{ name: "OpenCode", binary: "opencode", installHint: "npm install -g opencode-ai && opencode auth" },
|
|
29833
|
-
{ name: "GitHub Copilot", binary: "copilot", installHint: "npm install -g @github/copilot && copilot" }
|
|
29834
|
-
];
|
|
29835
|
-
}
|
|
29836
|
-
});
|
|
29837
|
-
|
|
29838
|
-
// packages/experience-design-system-cli/src/setup/lib/shell.ts
|
|
29839
|
-
import { execFile as execFile5, spawn as spawn5 } from "node:child_process";
|
|
29840
|
-
import { appendFile as appendFile2, readFile as readFile27, access as access10 } from "node:fs/promises";
|
|
29841
|
-
import { homedir as homedir9 } from "node:os";
|
|
29842
|
-
import { join as join26 } from "node:path";
|
|
29843
|
-
import { promisify as promisify2 } from "node:util";
|
|
29844
|
-
async function binaryExists(name) {
|
|
29845
|
-
try {
|
|
29846
|
-
await execFileAsync2("which", [name]);
|
|
29847
|
-
return true;
|
|
29848
|
-
} catch {
|
|
29849
|
-
return false;
|
|
29850
|
-
}
|
|
29851
|
-
}
|
|
29852
|
-
async function pathExists5(path) {
|
|
29853
|
-
return access10(path).then(() => true).catch(() => false);
|
|
29854
|
-
}
|
|
29855
|
-
function runSpawn(cmd, args, opts = {}) {
|
|
29856
|
-
return new Promise((resolve27) => {
|
|
29857
|
-
const child = spawn5(cmd, args, {
|
|
29858
|
-
cwd: opts.cwd,
|
|
29859
|
-
env: opts.env ?? process.env,
|
|
29860
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
29861
|
-
});
|
|
29862
|
-
let settled = false;
|
|
29863
|
-
let stdout = "";
|
|
29864
|
-
let stderr = "";
|
|
29865
|
-
const settle = (result) => {
|
|
29866
|
-
if (settled) return;
|
|
29867
|
-
settled = true;
|
|
29868
|
-
resolve27(result);
|
|
29869
|
-
};
|
|
29870
|
-
child.on("error", (err) => settle({ exitCode: 1, stdout: "", stderr: err.message }));
|
|
29871
|
-
child.stdout.on("data", (d) => {
|
|
29872
|
-
stdout += String(d);
|
|
29873
|
-
});
|
|
29874
|
-
child.stderr.on("data", (d) => {
|
|
29875
|
-
stderr += String(d);
|
|
29876
|
-
});
|
|
29877
|
-
child.on("exit", (code) => settle({ exitCode: code ?? 1, stdout, stderr }));
|
|
29878
|
-
});
|
|
29879
|
-
}
|
|
29880
|
-
async function detectShellProfile() {
|
|
29881
|
-
const shell = process.env["SHELL"] ?? "";
|
|
29882
|
-
const home = homedir9();
|
|
29883
|
-
if (shell.includes("zsh")) return join26(home, ".zshrc");
|
|
29884
|
-
if (shell.includes("bash")) {
|
|
29885
|
-
const bashProfile = join26(home, ".bash_profile");
|
|
29886
|
-
return await pathExists5(bashProfile) ? bashProfile : join26(home, ".bashrc");
|
|
29887
|
-
}
|
|
29888
|
-
if (shell.includes("fish")) return join26(home, ".config", "fish", "config.fish");
|
|
29889
|
-
return join26(home, ".profile");
|
|
29890
|
-
}
|
|
29891
|
-
async function profileContains(profilePath, value) {
|
|
29892
|
-
try {
|
|
29893
|
-
const content = await readFile27(profilePath, "utf8");
|
|
29894
|
-
return content.includes(value);
|
|
29895
|
-
} catch {
|
|
29896
|
-
return false;
|
|
29897
|
-
}
|
|
29898
|
-
}
|
|
29899
|
-
async function appendToProfile(profilePath, lines) {
|
|
29900
|
-
await appendFile2(profilePath, `
|
|
29901
|
-
${lines}
|
|
29902
|
-
`, "utf8");
|
|
29903
|
-
}
|
|
29904
|
-
var execFileAsync2, REQUIRED_NODE_MAJOR;
|
|
29905
|
-
var init_shell = __esm({
|
|
29906
|
-
"packages/experience-design-system-cli/src/setup/lib/shell.ts"() {
|
|
29907
|
-
"use strict";
|
|
29908
|
-
execFileAsync2 = promisify2(execFile5);
|
|
29909
|
-
REQUIRED_NODE_MAJOR = 24;
|
|
29910
|
-
}
|
|
29911
|
-
});
|
|
29912
|
-
|
|
29913
|
-
// packages/experience-design-system-cli/src/setup/lib/checks.ts
|
|
29914
|
-
import { join as join27 } from "node:path";
|
|
29915
|
-
function checkNodeVersion(nodeVersion = process.versions.node) {
|
|
29916
|
-
const major = Number.parseInt(nodeVersion.split(".")[0], 10);
|
|
29917
|
-
return { passed: major >= REQUIRED_NODE_MAJOR, version: nodeVersion, major, required: REQUIRED_NODE_MAJOR };
|
|
29918
|
-
}
|
|
29919
|
-
async function detectNodeVersionManagers(homeDir, deps = { binaryExists, pathExists: pathExists5 }) {
|
|
29920
|
-
const nvmScript = join27(homeDir, ".nvm", "nvm.sh");
|
|
29921
|
-
return {
|
|
29922
|
-
nvm: await deps.binaryExists("nvm") || await deps.pathExists(nvmScript),
|
|
29923
|
-
fnm: await deps.binaryExists("fnm"),
|
|
29924
|
-
nvmScript
|
|
29925
|
-
};
|
|
29926
|
-
}
|
|
29927
|
-
async function detectPnpm(deps = { binaryExists, run: runSpawn }) {
|
|
29928
|
-
if (!await deps.binaryExists("pnpm")) return { status: "missing" };
|
|
29929
|
-
const version = await deps.run("pnpm", ["--version"]);
|
|
29930
|
-
if (version.exitCode !== 0) return { status: "broken" };
|
|
29931
|
-
return { status: "ok", version: version.stdout.trim() };
|
|
29932
|
-
}
|
|
29933
|
-
async function checkPnpm(pkgRoot, deps = { binaryExists, run: runSpawn }) {
|
|
29934
|
-
const detected = await detectPnpm(deps);
|
|
29935
|
-
if (detected.status !== "ok") return detected;
|
|
29936
|
-
const ping = await deps.run("pnpm", ["exec", "node", "--version"], { cwd: pkgRoot });
|
|
29937
|
-
if (ping.exitCode !== 0) return { status: "unusable-in-repo", version: detected.version };
|
|
29938
|
-
return detected;
|
|
29939
|
-
}
|
|
29940
|
-
async function installDependencies(pkgRoot, deps = { pathExists: pathExists5, run: runSpawn }) {
|
|
29941
|
-
const hadNodeModules = await deps.pathExists(join27(pkgRoot, "node_modules"));
|
|
29942
|
-
const repoRoot = join27(pkgRoot, "..", "..");
|
|
29943
|
-
const result = await deps.run("pnpm", ["install", "--frozen-lockfile"], { cwd: repoRoot });
|
|
29944
|
-
return { passed: result.exitCode === 0, hadNodeModules, result };
|
|
29945
|
-
}
|
|
29946
|
-
async function buildCli(repoRoot, deps = { run: runSpawn }) {
|
|
29947
|
-
const result = await deps.run("pnpm", ["--filter", "@contentful/experience-design-system-cli", "run", "build"], {
|
|
29948
|
-
cwd: repoRoot
|
|
29949
|
-
});
|
|
29950
|
-
return { passed: result.exitCode === 0, result };
|
|
29951
|
-
}
|
|
29952
|
-
var init_checks = __esm({
|
|
29953
|
-
"packages/experience-design-system-cli/src/setup/lib/checks.ts"() {
|
|
29954
|
-
"use strict";
|
|
29955
|
-
init_shell();
|
|
29956
|
-
}
|
|
29957
|
-
});
|
|
29958
|
-
|
|
29959
|
-
// packages/experience-design-system-cli/src/setup/lib/layout.ts
|
|
29960
|
-
function shouldUseWideStepper(columns) {
|
|
29961
|
-
return columns !== void 0 && columns >= WIDE_STEPPER_MIN_COLUMNS;
|
|
29962
|
-
}
|
|
29963
|
-
function setupStepperSeparator(columns) {
|
|
29964
|
-
return shouldUseWideStepper(columns) ? WIDE_STEPPER_SEPARATOR : COMPACT_STEPPER_SEPARATOR;
|
|
29965
|
-
}
|
|
29966
|
-
function setupStepperEntries(activeStep, columns) {
|
|
29967
|
-
const isWide = shouldUseWideStepper(columns);
|
|
29968
|
-
return SETUP_SCREENS.map((screen, index) => {
|
|
29969
|
-
const step = index + 1;
|
|
29970
|
-
const state = step < activeStep ? "complete" : step === activeStep ? "active" : "pending";
|
|
29971
|
-
const compactLabel = state === "complete" ? "\u2713" : state === "active" ? `[${step}]` : `${step}`;
|
|
29972
|
-
const wideLabel = state === "complete" ? `\u2713 ${screen.title}` : state === "active" ? `[${step} ${screen.title}]` : `${step} ${screen.title}`;
|
|
29973
|
-
return { step, title: screen.title, state, label: isWide ? wideLabel : compactLabel };
|
|
29974
|
-
});
|
|
29975
|
-
}
|
|
29976
|
-
function shouldAlignVersionRight(version, columns) {
|
|
29977
|
-
const contentWidth = SETUP_TITLE.length + HEADER_INLINE_GAP + `v${version}`.length;
|
|
29978
|
-
return columns !== void 0 && columns >= contentWidth;
|
|
29979
|
-
}
|
|
29980
|
-
function countRequiredFailures(results) {
|
|
29981
|
-
return results.filter((result) => result.required && result.status === "failed").length;
|
|
29982
|
-
}
|
|
29983
|
-
function formatSetupCompletionMessage(results) {
|
|
29984
|
-
const requiredFailed = countRequiredFailures(results);
|
|
29985
|
-
if (requiredFailed === 0) return "\u2713 Setup complete. You can now run: experiences import";
|
|
29986
|
-
return `\u26A0 ${requiredFailed} required step${requiredFailed === 1 ? "" : "s"} incomplete.`;
|
|
29987
|
-
}
|
|
29988
|
-
var SETUP_SCREENS, SETUP_TITLE, WIDE_STEPPER_SEPARATOR, COMPACT_STEPPER_SEPARATOR, HEADER_INLINE_GAP, WIDE_STEPPER_MIN_COLUMNS;
|
|
29989
|
-
var init_layout = __esm({
|
|
29990
|
-
"packages/experience-design-system-cli/src/setup/lib/layout.ts"() {
|
|
29991
|
-
"use strict";
|
|
29992
|
-
SETUP_SCREENS = [
|
|
29993
|
-
{ title: "Prerequisites", kind: "required" },
|
|
29994
|
-
{ title: "Coding agent", kind: "required" },
|
|
29995
|
-
{ title: "Contentful", kind: "optional" },
|
|
29996
|
-
{ title: "Preferences", kind: "optional" }
|
|
29997
|
-
];
|
|
29998
|
-
SETUP_TITLE = "experiences setup";
|
|
29999
|
-
WIDE_STEPPER_SEPARATOR = " \xB7 ";
|
|
30000
|
-
COMPACT_STEPPER_SEPARATOR = " ";
|
|
30001
|
-
HEADER_INLINE_GAP = 2;
|
|
30002
|
-
WIDE_STEPPER_MIN_COLUMNS = SETUP_SCREENS.map((screen, index) => {
|
|
30003
|
-
const label = `${index + 1} ${screen.title}`;
|
|
30004
|
-
return index === 0 ? `[${label}]` : label;
|
|
30005
|
-
}).join(WIDE_STEPPER_SEPARATOR).length;
|
|
30006
|
-
}
|
|
30007
|
-
});
|
|
30008
|
-
|
|
30009
|
-
// packages/experience-design-system-cli/src/setup/lib/prompt-input.ts
|
|
30010
|
-
function splitPromptInput(input) {
|
|
30011
|
-
const cleaned = stripBracketedPasteMarkers(input);
|
|
30012
|
-
const newlineIndex = cleaned.search(/[\r\n]/);
|
|
30013
|
-
if (newlineIndex === -1) return { text: stripControlCharacters(cleaned), submitted: false };
|
|
30014
|
-
return { text: stripControlCharacters(cleaned.slice(0, newlineIndex)), submitted: true };
|
|
30015
|
-
}
|
|
30016
|
-
function stripBracketedPasteMarkers(value) {
|
|
30017
|
-
return value.replace(/\x1b\[20[01]~/g, "");
|
|
30018
|
-
}
|
|
30019
|
-
function stripControlCharacters(value) {
|
|
30020
|
-
return value.replace(/[\x00-\x1f\x7f]/g, "");
|
|
30021
|
-
}
|
|
30022
|
-
var init_prompt_input = __esm({
|
|
30023
|
-
"packages/experience-design-system-cli/src/setup/lib/prompt-input.ts"() {
|
|
30024
|
-
"use strict";
|
|
30025
|
-
}
|
|
30026
|
-
});
|
|
30027
|
-
|
|
30028
|
-
// packages/experience-design-system-cli/src/setup/tui/usePromptInput.ts
|
|
30029
|
-
import { useLayoutEffect as useLayoutEffect2, useRef as useRef10 } from "react";
|
|
30030
|
-
import { useStdin as useStdin2 } from "ink";
|
|
30031
|
-
function parseKey(data) {
|
|
30032
|
-
const code = data.length === 1 ? data.charCodeAt(0) : -1;
|
|
30033
|
-
const isReturn = data === "\r" || data === "\n";
|
|
30034
|
-
const isTab = data === " " || data === "\x1B[Z";
|
|
30035
|
-
const isDelete = data === "\x1B[3~";
|
|
30036
|
-
const isPaste = data.startsWith(BRACKETED_PASTE_START);
|
|
30037
|
-
const upArrow = data === "\x1B[A";
|
|
30038
|
-
const downArrow = data === "\x1B[B";
|
|
30039
|
-
const isEscapeSequence = isPaste || isTab || isDelete || upArrow || downArrow;
|
|
30040
|
-
return {
|
|
30041
|
-
return: isReturn,
|
|
30042
|
-
escape: data === "\x1B",
|
|
30043
|
-
tab: isTab,
|
|
30044
|
-
backspace: data === "\x7F" || data === "\b",
|
|
30045
|
-
delete: isDelete,
|
|
30046
|
-
upArrow,
|
|
30047
|
-
downArrow,
|
|
30048
|
-
ctrl: !isReturn && !isTab && code >= 1 && code <= 26,
|
|
30049
|
-
meta: !isEscapeSequence && data.length > 1 && data.startsWith("\x1B")
|
|
30050
|
-
};
|
|
30051
|
-
}
|
|
30052
|
-
function usePromptInput(handler) {
|
|
30053
|
-
const { stdin, setRawMode } = useStdin2();
|
|
30054
|
-
const handlerRef = useRef10(handler);
|
|
30055
|
-
handlerRef.current = handler;
|
|
30056
|
-
useLayoutEffect2(() => {
|
|
30057
|
-
setRawMode(true);
|
|
30058
|
-
const handleData = (data) => {
|
|
30059
|
-
const chunk = Buffer.isBuffer(data) ? data.toString("utf8") : data;
|
|
30060
|
-
handlerRef.current(chunk, parseKey(chunk));
|
|
30061
|
-
};
|
|
30062
|
-
stdin.on("data", handleData);
|
|
30063
|
-
return () => {
|
|
30064
|
-
stdin.off("data", handleData);
|
|
30065
|
-
setRawMode(false);
|
|
30066
|
-
};
|
|
30067
|
-
}, [stdin, setRawMode]);
|
|
30068
|
-
}
|
|
30069
|
-
var BRACKETED_PASTE_START;
|
|
30070
|
-
var init_usePromptInput = __esm({
|
|
30071
|
-
"packages/experience-design-system-cli/src/setup/tui/usePromptInput.ts"() {
|
|
30072
|
-
"use strict";
|
|
30073
|
-
BRACKETED_PASTE_START = "\x1B[200~";
|
|
30074
|
-
}
|
|
30075
|
-
});
|
|
30076
|
-
|
|
30077
|
-
// packages/experience-design-system-cli/src/setup/tui/SetupStepper.tsx
|
|
30078
|
-
import React30 from "react";
|
|
30079
|
-
import { Box as Box50, Text as Text52 } from "ink";
|
|
30080
|
-
import { jsx as jsx53, jsxs as jsxs52 } from "react/jsx-runtime";
|
|
30081
|
-
function stepColor(state) {
|
|
30082
|
-
if (state === "complete") return PALETTE.success;
|
|
30083
|
-
if (state === "active") return PALETTE.info;
|
|
30084
|
-
return void 0;
|
|
30085
|
-
}
|
|
30086
|
-
function SetupStepper({ activeStep, columns }) {
|
|
30087
|
-
const entries = setupStepperEntries(activeStep, columns);
|
|
30088
|
-
const separator = setupStepperSeparator(columns);
|
|
30089
|
-
return /* @__PURE__ */ jsx53(Box50, { children: entries.map((entry, index) => /* @__PURE__ */ jsxs52(React30.Fragment, { children: [
|
|
30090
|
-
index > 0 && /* @__PURE__ */ jsx53(Text52, { dimColor: true, children: separator }),
|
|
30091
|
-
/* @__PURE__ */ jsx53(Text52, { bold: entry.state === "active", dimColor: entry.state === "pending", color: stepColor(entry.state), children: entry.label })
|
|
30092
|
-
] }, entry.step)) });
|
|
30093
|
-
}
|
|
30094
|
-
var init_SetupStepper = __esm({
|
|
30095
|
-
"packages/experience-design-system-cli/src/setup/tui/SetupStepper.tsx"() {
|
|
30096
|
-
"use strict";
|
|
30097
|
-
init_theme();
|
|
30098
|
-
init_layout();
|
|
30099
|
-
}
|
|
30100
|
-
});
|
|
30101
|
-
|
|
30102
|
-
// packages/experience-design-system-cli/src/setup/lib/types.ts
|
|
30103
|
-
function emit(dependencies, kind, message) {
|
|
30104
|
-
dependencies.write({ kind, message });
|
|
30105
|
-
}
|
|
30106
|
-
var init_types4 = __esm({
|
|
30107
|
-
"packages/experience-design-system-cli/src/setup/lib/types.ts"() {
|
|
30108
|
-
"use strict";
|
|
30109
|
-
}
|
|
30110
|
-
});
|
|
30111
|
-
|
|
30112
|
-
// packages/experience-design-system-cli/src/setup/steps/coding-agent.ts
|
|
30113
|
-
async function promptCodexModel(dependencies) {
|
|
30114
|
-
if (dependencies.env["OPENAI_API_KEY"]) return void 0;
|
|
30115
|
-
emit(dependencies, "warning", "No OPENAI_API_KEY \u2014 using ChatGPT account authentication.");
|
|
30116
|
-
emit(dependencies, "info", "Tip: run codex then type /model to browse all available models.");
|
|
30117
|
-
const model = (await dependencies.ask("Model name (optional - press Enter for Codex default): ")).trim();
|
|
30118
|
-
return model || void 0;
|
|
30119
|
-
}
|
|
30120
|
-
async function runAgentSetup(dependencies) {
|
|
30121
|
-
emit(dependencies, "info", "Experiences import uses a coding agent to generate component definitions.");
|
|
30122
|
-
const found = (await Promise.all(
|
|
30123
|
-
AGENT_DEFS.map(async (agent) => await dependencies.binaryExists(agent.binary) ? agent : void 0)
|
|
30124
|
-
)).filter((agent) => agent !== void 0);
|
|
30125
|
-
if (found.length === 1) {
|
|
30126
|
-
const selected2 = found[0];
|
|
30127
|
-
emit(dependencies, "success", `${selected2.name} (${selected2.binary}) found`);
|
|
30128
|
-
const agentModel2 = selected2.binary === "codex" ? await promptCodexModel(dependencies) : void 0;
|
|
30129
|
-
return { agent: selected2.binary, agentModel: agentModel2, passed: true };
|
|
30130
|
-
}
|
|
30131
|
-
if (found.length > 1) {
|
|
30132
|
-
const index2 = await dependencies.choose(
|
|
30133
|
-
"Multiple coding agents found. Choose one to use as the default:",
|
|
30134
|
-
found.map((agent) => ({ label: agent.name, description: agent.binary }))
|
|
30135
|
-
);
|
|
30136
|
-
if (index2 === void 0) return { agent: void 0, agentModel: void 0, passed: false };
|
|
30137
|
-
const selected2 = found[index2] ?? found[0];
|
|
30138
|
-
const agentModel2 = selected2.binary === "codex" ? await promptCodexModel(dependencies) : void 0;
|
|
30139
|
-
return { agent: selected2.binary, agentModel: agentModel2, passed: true };
|
|
30140
|
-
}
|
|
30141
|
-
emit(dependencies, "warning", "No coding agent found on PATH");
|
|
30142
|
-
const installable = AGENT_DEFS.slice(0, 3);
|
|
30143
|
-
const index = await dependencies.choose(
|
|
30144
|
-
"Choose one to install:",
|
|
30145
|
-
installable.map((agent) => ({ label: agent.name, description: agent.installHint }))
|
|
30146
|
-
);
|
|
30147
|
-
const selected = index === void 0 ? void 0 : installable[index];
|
|
30148
|
-
if (!selected) return { agent: void 0, agentModel: void 0, passed: false };
|
|
30149
|
-
const packageName = selected.binary === "claude" ? "@anthropic-ai/claude-code" : selected.binary === "codex" ? "@openai/codex" : "opencode-ai";
|
|
30150
|
-
const installed = await dependencies.run("npm", ["install", "-g", packageName]);
|
|
30151
|
-
if (installed.exitCode !== 0 || !await dependencies.binaryExists(selected.binary)) {
|
|
30152
|
-
emit(dependencies, "failure", "Install failed");
|
|
30153
|
-
return { agent: void 0, agentModel: void 0, passed: false };
|
|
30154
|
-
}
|
|
30155
|
-
emit(dependencies, "success", `${selected.name} installed`);
|
|
30156
|
-
const agentModel = selected.binary === "codex" ? await promptCodexModel(dependencies) : void 0;
|
|
30157
|
-
return { agent: selected.binary, agentModel, passed: true };
|
|
30158
|
-
}
|
|
30159
|
-
var init_coding_agent = __esm({
|
|
30160
|
-
"packages/experience-design-system-cli/src/setup/steps/coding-agent.ts"() {
|
|
30161
|
-
"use strict";
|
|
30162
|
-
init_agent_definitions();
|
|
30163
|
-
init_types4();
|
|
30164
|
-
}
|
|
30165
|
-
});
|
|
30166
|
-
|
|
30167
|
-
// packages/experience-design-system-cli/src/setup/steps/contentful.ts
|
|
30168
|
-
function emitCurrentValue(dependencies, label, value) {
|
|
30169
|
-
const paddedLabel = label.padEnd(CURRENT_VALUE_LABEL_WIDTH);
|
|
30170
|
-
if (value) emit(dependencies, "value", `${paddedLabel}${value}`);
|
|
30171
|
-
else emit(dependencies, "warning", `${paddedLabel}(not set)`);
|
|
30172
|
-
}
|
|
30173
|
-
async function runCredentialsSetup(dependencies) {
|
|
30174
|
-
emit(
|
|
30175
|
-
dependencies,
|
|
30176
|
-
"help",
|
|
30177
|
-
`Saved to ${dependencies.credentialsPath()} \u2014 loaded automatically by experiences import.`
|
|
30178
|
-
);
|
|
30179
|
-
emit(dependencies, "info", "");
|
|
30180
|
-
const envShadowing = [
|
|
30181
|
-
dependencies.env["CONTENTFUL_SPACE_ID"] ? "CONTENTFUL_SPACE_ID" : void 0,
|
|
30182
|
-
dependencies.env["CONTENTFUL_ENVIRONMENT_ID"] ? "CONTENTFUL_ENVIRONMENT_ID" : void 0,
|
|
30183
|
-
dependencies.env["CONTENTFUL_MANAGEMENT_TOKEN"] ? "CONTENTFUL_MANAGEMENT_TOKEN" : void 0,
|
|
30184
|
-
dependencies.env["EDS_HOST"] ? "EDS_HOST" : void 0
|
|
30185
|
-
].filter((value) => value !== void 0);
|
|
30186
|
-
if (envShadowing.length > 0) {
|
|
30187
|
-
emit(
|
|
30188
|
-
dependencies,
|
|
30189
|
-
"warning",
|
|
30190
|
-
`Env vars set: ${envShadowing.join(", ")}. Values saved here take precedence; env vars only apply where disk is empty.`
|
|
30191
|
-
);
|
|
30192
|
-
}
|
|
30193
|
-
const stored = await dependencies.readCredentials();
|
|
30194
|
-
const currentHost = stored.host ?? DEFAULT_CONFIGURED_HOST;
|
|
30195
|
-
const hasAny = Boolean(stored.spaceId || stored.environmentId || stored.cmaToken);
|
|
30196
|
-
const allSet = Boolean(stored.spaceId && stored.environmentId && stored.cmaToken);
|
|
30197
|
-
if (hasAny) {
|
|
30198
|
-
emit(dependencies, "info", "Current values:");
|
|
30199
|
-
emitCurrentValue(dependencies, "Space ID", stored.spaceId);
|
|
30200
|
-
emitCurrentValue(dependencies, "Environment ID", stored.environmentId);
|
|
30201
|
-
emitCurrentValue(
|
|
30202
|
-
dependencies,
|
|
30203
|
-
"CMA Token",
|
|
30204
|
-
stored.cmaToken && `${"\u2022".repeat(Math.min(stored.cmaToken.length, 8))}...`
|
|
30205
|
-
);
|
|
30206
|
-
emitCurrentValue(dependencies, "API Host", currentHost);
|
|
30207
|
-
}
|
|
30208
|
-
if (!await dependencies.confirm(hasAny ? "Update credentials?" : "Configure Contentful credentials?", !allSet)) {
|
|
30209
|
-
if (allSet) emit(dependencies, "success", "Credentials already configured \u2014 no changes made");
|
|
30210
|
-
else emit(dependencies, "warning", "Skipped. experiences import will prompt for credentials interactively.");
|
|
30211
|
-
return { passed: true };
|
|
30212
|
-
}
|
|
30213
|
-
const spaceId = await dependencies.ask(`Space ID${stored.spaceId ? ` [${stored.spaceId}]` : ""}: `) || stored.spaceId;
|
|
30214
|
-
const environmentId = await dependencies.ask(`Environment ID [${stored.environmentId || "master"}]: `) || stored.environmentId || "master";
|
|
30215
|
-
const cmaToken = await dependencies.askSecret(
|
|
30216
|
-
`CMA token${stored.cmaToken ? " [press Enter to keep existing]" : " (paste here)"}: `
|
|
30217
|
-
) || stored.cmaToken;
|
|
30218
|
-
if (!spaceId || !cmaToken) {
|
|
30219
|
-
emit(dependencies, "warning", "Space ID and CMA token are required. Skipped.");
|
|
30220
|
-
return { passed: false };
|
|
30221
|
-
}
|
|
30222
|
-
const hostInput = await dependencies.ask(`API host [${currentHost}]: `);
|
|
30223
|
-
const host = toConfiguredHost(hostInput) ?? stored.host;
|
|
30224
|
-
await dependencies.writeCredentials({ ...stored, spaceId, environmentId, cmaToken, ...host ? { host } : {} });
|
|
30225
|
-
emit(dependencies, "success", `Credentials saved to ${dependencies.credentialsPath()}`);
|
|
30226
|
-
emit(dependencies, "success", `API host set to ${host ?? DEFAULT_CONFIGURED_HOST}`);
|
|
30227
|
-
emit(dependencies, "info", "Run experiences import \u2014 credentials will be pre-filled automatically.");
|
|
30228
|
-
return { passed: true };
|
|
30229
|
-
}
|
|
30230
|
-
var CURRENT_VALUE_LABEL_WIDTH;
|
|
30231
|
-
var init_contentful = __esm({
|
|
30232
|
-
"packages/experience-design-system-cli/src/setup/steps/contentful.ts"() {
|
|
30233
|
-
"use strict";
|
|
30234
|
-
init_host_utils();
|
|
30235
|
-
init_types4();
|
|
30236
|
-
CURRENT_VALUE_LABEL_WIDTH = "Environment ID".length + 2;
|
|
30237
|
-
}
|
|
30238
|
-
});
|
|
30239
|
-
|
|
30240
|
-
// packages/experience-design-system-cli/src/setup/lib/yes-no-prompt.ts
|
|
30241
|
-
async function askYesNo(ask, question, defaultValue) {
|
|
30242
|
-
const hint = defaultValue ? "[Y/n]" : "[y/N]";
|
|
30243
|
-
const answer = (await ask(`${question} ${hint} `)).trim().toLowerCase();
|
|
30244
|
-
if (answer.startsWith("y")) return true;
|
|
30245
|
-
if (answer.startsWith("n")) return false;
|
|
30246
|
-
return defaultValue;
|
|
30247
|
-
}
|
|
30248
|
-
var init_yes_no_prompt = __esm({
|
|
30249
|
-
"packages/experience-design-system-cli/src/setup/lib/yes-no-prompt.ts"() {
|
|
30250
|
-
"use strict";
|
|
30251
|
-
}
|
|
30252
|
-
});
|
|
30253
|
-
|
|
30254
|
-
// packages/experience-design-system-cli/src/setup/steps/preferences/analytics.ts
|
|
30255
|
-
async function promptAnalyticsPreference(ask, current) {
|
|
30256
|
-
return askYesNo(ask, "Disable anonymous usage analytics?", current ?? false);
|
|
30257
|
-
}
|
|
30258
|
-
async function configureAnalytics(dependencies) {
|
|
30259
|
-
emit(dependencies, "page", ANALYTICS_HELP);
|
|
30260
|
-
const stored = await dependencies.readCredentials();
|
|
30261
|
-
const analyticsDisabled = await promptAnalyticsPreference(dependencies.ask, stored.analyticsDisabled);
|
|
30262
|
-
if (analyticsDisabled !== (stored.analyticsDisabled ?? false))
|
|
30263
|
-
await dependencies.writeCredentials({ ...stored, analyticsDisabled });
|
|
30264
|
-
}
|
|
30265
|
-
var ANALYTICS_HELP;
|
|
30266
|
-
var init_analytics2 = __esm({
|
|
30267
|
-
"packages/experience-design-system-cli/src/setup/steps/preferences/analytics.ts"() {
|
|
30268
|
-
"use strict";
|
|
30269
|
-
init_yes_no_prompt();
|
|
30270
|
-
init_types4();
|
|
30271
|
-
ANALYTICS_HELP = "Shares anonymous usage data about which CLI commands run.";
|
|
30272
|
-
}
|
|
30273
|
-
});
|
|
30274
|
-
|
|
30275
|
-
// packages/experience-design-system-cli/src/setup/steps/preferences/auto-filter.ts
|
|
30276
|
-
async function promptAutoFilterPreference(ask, current) {
|
|
30277
|
-
return askYesNo(ask, "Enable AI auto-filter by default?", current ?? true);
|
|
30278
|
-
}
|
|
30279
|
-
async function configureAutoFilter(dependencies) {
|
|
30280
|
-
emit(dependencies, "page", AUTO_FILTER_HELP);
|
|
30281
|
-
const stored = await dependencies.readCredentials();
|
|
30282
|
-
const autoFilter = await promptAutoFilterPreference(dependencies.ask, stored.autoFilter);
|
|
30283
|
-
if (autoFilter !== (stored.autoFilter ?? true)) await dependencies.writeCredentials({ ...stored, autoFilter });
|
|
30284
|
-
}
|
|
30285
|
-
var AUTO_FILTER_HELP;
|
|
30286
|
-
var init_auto_filter = __esm({
|
|
30287
|
-
"packages/experience-design-system-cli/src/setup/steps/preferences/auto-filter.ts"() {
|
|
30288
|
-
"use strict";
|
|
30289
|
-
init_yes_no_prompt();
|
|
30290
|
-
init_types4();
|
|
30291
|
-
AUTO_FILTER_HELP = "Filters out components irrelevant to experience orchestration during extraction.";
|
|
30292
|
-
}
|
|
30293
|
-
});
|
|
30294
|
-
|
|
30295
|
-
// packages/experience-design-system-cli/src/setup/steps/preferences/concurrency.ts
|
|
30296
|
-
async function configureConcurrency(dependencies, profilePath) {
|
|
30297
|
-
emit(dependencies, "page", CONCURRENCY_HELP);
|
|
30298
|
-
if (await dependencies.profileContains(profilePath, PROFILE_VARIABLE)) return;
|
|
30299
|
-
if (!await dependencies.confirm("Speed up component analysis on this machine?", false)) return;
|
|
30300
|
-
await dependencies.appendToProfile(profilePath, `# experiences performance
|
|
30301
|
-
export ${PROFILE_VARIABLE}=8`);
|
|
30302
|
-
}
|
|
30303
|
-
var CONCURRENCY_HELP, PROFILE_VARIABLE;
|
|
30304
|
-
var init_concurrency = __esm({
|
|
30305
|
-
"packages/experience-design-system-cli/src/setup/steps/preferences/concurrency.ts"() {
|
|
30306
|
-
"use strict";
|
|
30307
|
-
init_types4();
|
|
30308
|
-
CONCURRENCY_HELP = "Analyzes more components at once, which is faster on machines with spare cores.";
|
|
30309
|
-
PROFILE_VARIABLE = "EDS_EXTRACT_CONCURRENCY";
|
|
30310
|
-
}
|
|
30311
|
-
});
|
|
30312
|
-
|
|
30313
|
-
// packages/experience-design-system-cli/src/setup/steps/preferences/custom-prompts.ts
|
|
30314
|
-
async function promptCustomSkillPathAction(kind, current, ask) {
|
|
30315
|
-
const label = kind === "select" ? "select (analyze select-agent)" : "generate (generate components)";
|
|
30316
|
-
const answer = await ask(
|
|
30317
|
-
`Custom ${label} prompt path${current ? ` [${current}]` : " [none]"} (empty=keep, "-"=clear): `
|
|
30318
|
-
);
|
|
30319
|
-
const trimmed = answer.trim();
|
|
30320
|
-
return trimmed === "" ? void 0 : trimmed === "-" ? null : trimmed;
|
|
30321
|
-
}
|
|
30322
|
-
async function configureCustomPrompts(dependencies) {
|
|
30323
|
-
emit(dependencies, "page", CUSTOM_PROMPTS_HELP);
|
|
30324
|
-
if (!await dependencies.confirm("Use your own prompt files instead of the built-in ones?", false)) return;
|
|
30325
|
-
const stored = await dependencies.readCredentials();
|
|
30326
|
-
const selectPromptPath = await promptCustomSkillPathAction("select", stored.selectPromptPath, dependencies.ask);
|
|
30327
|
-
const generatePromptPath = await promptCustomSkillPathAction("generate", stored.generatePromptPath, dependencies.ask);
|
|
30328
|
-
const updated = { ...stored };
|
|
30329
|
-
if (selectPromptPath === null) delete updated.selectPromptPath;
|
|
30330
|
-
else if (selectPromptPath !== void 0) updated.selectPromptPath = selectPromptPath;
|
|
30331
|
-
if (generatePromptPath === null) delete updated.generatePromptPath;
|
|
30332
|
-
else if (generatePromptPath !== void 0) updated.generatePromptPath = generatePromptPath;
|
|
30333
|
-
await dependencies.writeCredentials(updated);
|
|
30334
|
-
}
|
|
30335
|
-
var CUSTOM_PROMPTS_HELP;
|
|
30336
|
-
var init_custom_prompts = __esm({
|
|
30337
|
-
"packages/experience-design-system-cli/src/setup/steps/preferences/custom-prompts.ts"() {
|
|
30338
|
-
"use strict";
|
|
30339
|
-
init_types4();
|
|
30340
|
-
CUSTOM_PROMPTS_HELP = "Replaces the built-in instructions the coding agent follows when it selects and generates components.";
|
|
30341
|
-
}
|
|
30342
|
-
});
|
|
30343
|
-
|
|
30344
|
-
// packages/experience-design-system-cli/src/setup/steps/preferences/debug.ts
|
|
30345
|
-
async function promptDebugModePreference(ask, current) {
|
|
30346
|
-
return askYesNo(ask, "Enable debug logging by default?", current ?? false);
|
|
30347
|
-
}
|
|
30348
|
-
async function configureDebug(dependencies) {
|
|
30349
|
-
emit(dependencies, "page", DEBUG_HELP);
|
|
30350
|
-
const stored = await dependencies.readCredentials();
|
|
30351
|
-
const debug = await promptDebugModePreference(dependencies.ask, stored.debug);
|
|
30352
|
-
if (debug !== (stored.debug ?? false)) await dependencies.writeCredentials({ ...stored, debug });
|
|
30353
|
-
}
|
|
30354
|
-
var DEBUG_HELP;
|
|
30355
|
-
var init_debug = __esm({
|
|
30356
|
-
"packages/experience-design-system-cli/src/setup/steps/preferences/debug.ts"() {
|
|
30357
|
-
"use strict";
|
|
30358
|
-
init_yes_no_prompt();
|
|
30359
|
-
init_types4();
|
|
30360
|
-
DEBUG_HELP = "Writes a verbose trace of every command decision, for troubleshooting.";
|
|
30361
|
-
}
|
|
30362
|
-
});
|
|
30363
|
-
|
|
30364
|
-
// packages/experience-design-system-cli/src/setup/steps/preferences/no-color.ts
|
|
30365
|
-
async function configureNoColor(dependencies, profilePath) {
|
|
30366
|
-
emit(dependencies, "page", NO_COLOR_HELP);
|
|
30367
|
-
if (!await dependencies.confirm("Turn off colored output?", false)) return;
|
|
30368
|
-
if (await dependencies.profileContains(profilePath, PROFILE_VARIABLE2)) return;
|
|
30369
|
-
await dependencies.appendToProfile(profilePath, `export ${PROFILE_VARIABLE2}=1`);
|
|
30370
|
-
}
|
|
30371
|
-
var NO_COLOR_HELP, PROFILE_VARIABLE2;
|
|
30372
|
-
var init_no_color = __esm({
|
|
30373
|
-
"packages/experience-design-system-cli/src/setup/steps/preferences/no-color.ts"() {
|
|
30374
|
-
"use strict";
|
|
30375
|
-
init_types4();
|
|
30376
|
-
NO_COLOR_HELP = "Prints plain text with no color, which suits CI logs and basic terminals.";
|
|
30377
|
-
PROFILE_VARIABLE2 = "NO_COLOR";
|
|
30378
|
-
}
|
|
30379
|
-
});
|
|
30380
|
-
|
|
30381
|
-
// packages/experience-design-system-cli/src/setup/steps/preferences/index.ts
|
|
30382
|
-
async function runPreferenceSetupAction(dependencies, profilePath) {
|
|
30383
|
-
for (const option of PREFERENCE_OPTIONS) {
|
|
30384
|
-
await option.configure(dependencies, profilePath);
|
|
30385
|
-
}
|
|
30386
|
-
return { selected: PREFERENCE_OPTIONS.map((option) => option.key) };
|
|
30387
|
-
}
|
|
30388
|
-
var PREFERENCE_OPTIONS;
|
|
30389
|
-
var init_preferences = __esm({
|
|
30390
|
-
"packages/experience-design-system-cli/src/setup/steps/preferences/index.ts"() {
|
|
30391
|
-
"use strict";
|
|
30392
|
-
init_analytics2();
|
|
30393
|
-
init_auto_filter();
|
|
30394
|
-
init_concurrency();
|
|
30395
|
-
init_custom_prompts();
|
|
30396
|
-
init_debug();
|
|
30397
|
-
init_no_color();
|
|
30398
|
-
PREFERENCE_OPTIONS = [
|
|
30399
|
-
{ key: "autoFilter", label: "AI auto-filter", configure: configureAutoFilter },
|
|
30400
|
-
{ key: "concurrency", label: "Performance concurrency", configure: configureConcurrency },
|
|
30401
|
-
{ key: "customPrompts", label: "Custom prompts", configure: configureCustomPrompts },
|
|
30402
|
-
{ key: "debug", label: "Debug logging", configure: configureDebug },
|
|
30403
|
-
{ key: "analytics", label: "Usage analytics", configure: configureAnalytics },
|
|
30404
|
-
{ key: "noColor", label: "Disable terminal colors", configure: configureNoColor }
|
|
30405
|
-
];
|
|
30406
|
-
}
|
|
30407
|
-
});
|
|
30408
|
-
|
|
30409
|
-
// packages/experience-design-system-cli/src/setup/steps/prerequisites/build.ts
|
|
30410
|
-
async function runBuildSetup(dependencies, repoRoot) {
|
|
30411
|
-
emit(dependencies, "info", "Running pnpm install...");
|
|
30412
|
-
const install = await dependencies.run("pnpm", ["install", "--frozen-lockfile"], { cwd: repoRoot });
|
|
30413
|
-
if (install.exitCode !== 0) {
|
|
30414
|
-
emit(dependencies, "failure", "pnpm install failed");
|
|
30415
|
-
return { passed: false };
|
|
30416
|
-
}
|
|
30417
|
-
emit(dependencies, "success", "Dependencies installed");
|
|
30418
|
-
emit(dependencies, "info", "Building CLI...");
|
|
30419
|
-
const build = await dependencies.run(
|
|
30420
|
-
"pnpm",
|
|
30421
|
-
["--filter", "@contentful/experience-design-system-cli", "run", "build"],
|
|
30422
|
-
{ cwd: repoRoot }
|
|
30423
|
-
);
|
|
30424
|
-
if (build.exitCode !== 0) {
|
|
30425
|
-
emit(dependencies, "failure", "Build failed");
|
|
30426
|
-
return { passed: false };
|
|
30427
|
-
}
|
|
30428
|
-
emit(dependencies, "success", "CLI built successfully");
|
|
30429
|
-
return { passed: true };
|
|
30430
|
-
}
|
|
30431
|
-
var init_build = __esm({
|
|
30432
|
-
"packages/experience-design-system-cli/src/setup/steps/prerequisites/build.ts"() {
|
|
30433
|
-
"use strict";
|
|
30434
|
-
init_types4();
|
|
30435
|
-
}
|
|
30436
|
-
});
|
|
30437
|
-
|
|
30438
|
-
// packages/experience-design-system-cli/src/setup/steps/prerequisites/node.ts
|
|
30439
|
-
async function runNodeSetup(dependencies) {
|
|
30440
|
-
const check = checkNodeVersion(dependencies.nodeVersion);
|
|
30441
|
-
if (check.passed) {
|
|
30442
|
-
emit(dependencies, "success", `Node.js v${check.version} \u2014 already good`);
|
|
30443
|
-
return { passed: true };
|
|
30444
|
-
}
|
|
30445
|
-
emit(dependencies, "failure", `Node.js v${check.version} \u2014 need v${check.required}+`);
|
|
30446
|
-
const { nvm: hasNvm, fnm: hasFnm, nvmScript } = await detectNodeVersionManagers(dependencies.homeDir, dependencies);
|
|
30447
|
-
if (hasNvm) {
|
|
30448
|
-
emit(
|
|
30449
|
-
dependencies,
|
|
30450
|
-
"info",
|
|
30451
|
-
`nvm detected. Will run: nvm install ${REQUIRED_NODE_MAJOR} && nvm use ${REQUIRED_NODE_MAJOR}`
|
|
30452
|
-
);
|
|
30453
|
-
if (!await dependencies.confirm(`Install and switch to Node ${REQUIRED_NODE_MAJOR} via nvm?`)) {
|
|
30454
|
-
emit(
|
|
30455
|
-
dependencies,
|
|
30456
|
-
"warning",
|
|
30457
|
-
`Skipped. Re-run experiences setup after switching to Node ${REQUIRED_NODE_MAJOR}.`
|
|
30458
|
-
);
|
|
30459
|
-
return { passed: false };
|
|
30460
|
-
}
|
|
30461
|
-
const result2 = await dependencies.run("bash", [
|
|
30462
|
-
"-c",
|
|
30463
|
-
`source "${nvmScript}" && nvm install ${REQUIRED_NODE_MAJOR} && nvm alias default ${REQUIRED_NODE_MAJOR}`
|
|
30464
|
-
]);
|
|
30465
|
-
if (result2.exitCode !== 0) {
|
|
30466
|
-
emit(dependencies, "failure", "nvm install failed");
|
|
30467
|
-
emit(dependencies, "info", `Run manually: nvm install ${REQUIRED_NODE_MAJOR} && nvm use ${REQUIRED_NODE_MAJOR}`);
|
|
30468
|
-
return { passed: false };
|
|
30469
|
-
}
|
|
30470
|
-
emit(
|
|
30471
|
-
dependencies,
|
|
30472
|
-
"success",
|
|
30473
|
-
`Node ${REQUIRED_NODE_MAJOR} installed via nvm. Re-run experiences setup in a fresh shell to pick it up.`
|
|
30474
|
-
);
|
|
30475
|
-
return { passed: false, restartRequired: true };
|
|
30476
|
-
}
|
|
30477
|
-
if (hasFnm) {
|
|
30478
|
-
emit(
|
|
30479
|
-
dependencies,
|
|
30480
|
-
"info",
|
|
30481
|
-
`fnm detected. Will run: fnm install ${REQUIRED_NODE_MAJOR} && fnm use ${REQUIRED_NODE_MAJOR}`
|
|
30482
|
-
);
|
|
30483
|
-
if (!await dependencies.confirm(`Install and switch to Node ${REQUIRED_NODE_MAJOR} via fnm?`)) {
|
|
30484
|
-
emit(
|
|
30485
|
-
dependencies,
|
|
30486
|
-
"warning",
|
|
30487
|
-
`Skipped. Re-run experiences setup after switching to Node ${REQUIRED_NODE_MAJOR}.`
|
|
30488
|
-
);
|
|
30489
|
-
return { passed: false };
|
|
30490
|
-
}
|
|
30491
|
-
const install = await dependencies.run("fnm", ["install", String(REQUIRED_NODE_MAJOR)]);
|
|
30492
|
-
if (install.exitCode !== 0) {
|
|
30493
|
-
emit(dependencies, "failure", "fnm install failed");
|
|
30494
|
-
return { passed: false };
|
|
30495
|
-
}
|
|
30496
|
-
const useResult = await dependencies.run("fnm", ["use", String(REQUIRED_NODE_MAJOR)]);
|
|
30497
|
-
if (useResult.exitCode !== 0) {
|
|
30498
|
-
emit(dependencies, "warning", `fnm use ${REQUIRED_NODE_MAJOR} failed \u2014 node installed but not activated`);
|
|
30499
|
-
emit(dependencies, "info", `Run manually: fnm use ${REQUIRED_NODE_MAJOR} && fnm default ${REQUIRED_NODE_MAJOR}`);
|
|
30500
|
-
} else {
|
|
30501
|
-
const defaultResult = await dependencies.run("fnm", ["default", String(REQUIRED_NODE_MAJOR)]);
|
|
30502
|
-
if (defaultResult.exitCode !== 0) {
|
|
30503
|
-
emit(
|
|
30504
|
-
dependencies,
|
|
30505
|
-
"warning",
|
|
30506
|
-
`fnm default ${REQUIRED_NODE_MAJOR} failed \u2014 version won't persist across new shells`
|
|
30507
|
-
);
|
|
30508
|
-
emit(dependencies, "info", `Run manually: fnm default ${REQUIRED_NODE_MAJOR}`);
|
|
30509
|
-
}
|
|
30510
|
-
}
|
|
30511
|
-
emit(
|
|
30512
|
-
dependencies,
|
|
30513
|
-
"success",
|
|
30514
|
-
`Node ${REQUIRED_NODE_MAJOR} installed via fnm. Re-run experiences setup in a fresh shell.`
|
|
30515
|
-
);
|
|
30516
|
-
return { passed: false, restartRequired: true };
|
|
30517
|
-
}
|
|
30518
|
-
emit(dependencies, "info", "No Node version manager detected (nvm or fnm).");
|
|
30519
|
-
if (!await dependencies.confirm("Install nvm now? (recommended)")) {
|
|
30520
|
-
emit(dependencies, "info", `Install Node ${REQUIRED_NODE_MAJOR} manually from https://nodejs.org`);
|
|
30521
|
-
return { passed: false };
|
|
30522
|
-
}
|
|
30523
|
-
const result = await dependencies.run("bash", [
|
|
30524
|
-
"-c",
|
|
30525
|
-
"curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash"
|
|
30526
|
-
]);
|
|
30527
|
-
if (result.exitCode !== 0) {
|
|
30528
|
-
emit(dependencies, "failure", "nvm install failed");
|
|
30529
|
-
return { passed: false };
|
|
30530
|
-
}
|
|
30531
|
-
emit(dependencies, "success", "nvm installed. Open a new shell, then re-run experiences setup.");
|
|
30532
|
-
return { passed: false, restartRequired: true };
|
|
30533
|
-
}
|
|
30534
|
-
var init_node = __esm({
|
|
30535
|
-
"packages/experience-design-system-cli/src/setup/steps/prerequisites/node.ts"() {
|
|
30536
|
-
"use strict";
|
|
30537
|
-
init_checks();
|
|
30538
|
-
init_shell();
|
|
30539
|
-
init_types4();
|
|
30540
|
-
}
|
|
30541
|
-
});
|
|
30542
|
-
|
|
30543
|
-
// packages/experience-design-system-cli/src/setup/steps/prerequisites/pnpm.ts
|
|
30544
|
-
async function runPnpmSetup(dependencies) {
|
|
30545
|
-
const detected = await detectPnpm(dependencies);
|
|
30546
|
-
if (detected.status === "ok") {
|
|
30547
|
-
emit(dependencies, "success", `pnpm v${detected.version} \u2014 already installed`);
|
|
30548
|
-
return { passed: true };
|
|
30549
|
-
}
|
|
30550
|
-
emit(dependencies, "failure", "pnpm not found");
|
|
30551
|
-
if (await dependencies.binaryExists("corepack")) {
|
|
30552
|
-
emit(dependencies, "info", "Will run: corepack enable && corepack prepare pnpm@latest --activate");
|
|
30553
|
-
if (await dependencies.confirm("Install pnpm via corepack?")) {
|
|
30554
|
-
const enabled = await dependencies.run("corepack", ["enable"]);
|
|
30555
|
-
const installed = enabled.exitCode === 0 ? await dependencies.run("corepack", ["prepare", "pnpm@latest", "--activate"]) : enabled;
|
|
30556
|
-
if (installed.exitCode === 0) {
|
|
30557
|
-
emit(dependencies, "success", "pnpm installed via corepack");
|
|
30558
|
-
return { passed: true };
|
|
30559
|
-
}
|
|
30560
|
-
emit(dependencies, "failure", "corepack install failed");
|
|
30561
|
-
return { passed: false };
|
|
30562
|
-
}
|
|
30563
|
-
}
|
|
30564
|
-
emit(dependencies, "info", "Will run: npm install -g pnpm");
|
|
30565
|
-
if (!await dependencies.confirm("Install pnpm via npm?")) {
|
|
30566
|
-
emit(dependencies, "warning", "Skipped. Install pnpm manually: npm install -g pnpm");
|
|
30567
|
-
return { passed: false };
|
|
30568
|
-
}
|
|
30569
|
-
const result = await dependencies.run("npm", ["install", "-g", "pnpm"]);
|
|
30570
|
-
if (result.exitCode !== 0) {
|
|
30571
|
-
emit(dependencies, "failure", "npm install -g pnpm failed");
|
|
30572
|
-
return { passed: false };
|
|
30573
|
-
}
|
|
30574
|
-
emit(dependencies, "success", "pnpm installed");
|
|
30575
|
-
return { passed: true };
|
|
30576
|
-
}
|
|
30577
|
-
var init_pnpm = __esm({
|
|
30578
|
-
"packages/experience-design-system-cli/src/setup/steps/prerequisites/pnpm.ts"() {
|
|
30579
|
-
"use strict";
|
|
30580
|
-
init_checks();
|
|
30581
|
-
init_types4();
|
|
30582
|
-
}
|
|
30583
|
-
});
|
|
30584
|
-
|
|
30585
|
-
// packages/experience-design-system-cli/src/setup/steps/prerequisites/index.ts
|
|
30586
|
-
async function runPrerequisitesSetup(dependencies, repoRoot, options = {}) {
|
|
30587
|
-
const node = await runNodeSetup(dependencies);
|
|
30588
|
-
if (!node.passed) return { node };
|
|
30589
|
-
const pnpm = await runPnpmSetup(dependencies);
|
|
30590
|
-
if (!pnpm.passed || options.skipBuild) return { node, pnpm };
|
|
30591
|
-
const build = await runBuildSetup(dependencies, repoRoot);
|
|
30592
|
-
return { node, pnpm, build };
|
|
30593
|
-
}
|
|
30594
|
-
var init_prerequisites = __esm({
|
|
30595
|
-
"packages/experience-design-system-cli/src/setup/steps/prerequisites/index.ts"() {
|
|
30596
|
-
"use strict";
|
|
30597
|
-
init_build();
|
|
30598
|
-
init_node();
|
|
30599
|
-
init_pnpm();
|
|
30600
|
-
}
|
|
30601
|
-
});
|
|
30602
|
-
|
|
30603
|
-
// packages/experience-design-system-cli/src/setup/tui/SetupScreen.tsx
|
|
30604
|
-
var SetupScreen_exports = {};
|
|
30605
|
-
__export(SetupScreen_exports, {
|
|
30606
|
-
SetupScreen: () => SetupScreen
|
|
30607
|
-
});
|
|
30608
|
-
import { useEffect as useEffect16, useRef as useRef11, useState as useState29 } from "react";
|
|
30609
|
-
import { Box as Box51, Text as Text53, useStdout as useStdout9 } from "ink";
|
|
30610
|
-
import { Select } from "@inkjs/ui";
|
|
30611
|
-
import { Fragment as Fragment16, jsx as jsx54, jsxs as jsxs53 } from "react/jsx-runtime";
|
|
30612
|
-
function SetupScreen({
|
|
30613
|
-
version,
|
|
30614
|
-
repoRoot,
|
|
30615
|
-
profilePath,
|
|
30616
|
-
dependencies,
|
|
30617
|
-
skip = {},
|
|
30618
|
-
columns: columnsOverride,
|
|
30619
|
-
offerDoctor = false,
|
|
30620
|
-
onComplete
|
|
30621
|
-
}) {
|
|
30622
|
-
const { stdout } = useStdout9();
|
|
30623
|
-
const columns = columnsOverride ?? stdout?.columns;
|
|
30624
|
-
const [activeStep, setActiveStep] = useState29(1);
|
|
30625
|
-
const [events, setEvents] = useState29([]);
|
|
30626
|
-
const [prompt, setPrompt] = useState29(null);
|
|
30627
|
-
const [pageHelp, setPageHelp] = useState29(null);
|
|
30628
|
-
const [inputValue, setInputValue] = useState29("");
|
|
30629
|
-
const inputValueRef = useRef11("");
|
|
30630
|
-
const updateInput = (next) => {
|
|
30631
|
-
inputValueRef.current = next;
|
|
30632
|
-
setInputValue(next);
|
|
30633
|
-
};
|
|
30634
|
-
const [outcome, setOutcome] = useState29(null);
|
|
30635
|
-
const [notice, setNotice] = useState29(null);
|
|
30636
|
-
const startedRef = useRef11(false);
|
|
30637
|
-
useEffect16(() => {
|
|
30638
|
-
if (startedRef.current) return;
|
|
30639
|
-
startedRef.current = true;
|
|
30640
|
-
const request2 = (build) => new Promise((resolve27) => {
|
|
30641
|
-
updateInput("");
|
|
30642
|
-
setPrompt(build(resolve27));
|
|
30643
|
-
});
|
|
30644
|
-
const uiDependencies = {
|
|
30645
|
-
...dependencies,
|
|
30646
|
-
ask: (question) => request2((resolve27) => ({ kind: "text", question, resolve: resolve27 })),
|
|
30647
|
-
askSecret: (question) => request2((resolve27) => ({ kind: "secret", question, resolve: resolve27 })),
|
|
30648
|
-
confirm: (question, defaultYes = true) => request2((resolve27) => ({ kind: "confirm", question, defaultYes, resolve: resolve27 })),
|
|
30649
|
-
choose: (question, options) => request2((resolve27) => ({ kind: "select", question, options, resolve: resolve27 })),
|
|
30650
|
-
write: (event) => {
|
|
30651
|
-
if (event.kind === "page") {
|
|
30652
|
-
setEvents([]);
|
|
30653
|
-
setPageHelp(event.message);
|
|
30654
|
-
return;
|
|
30655
|
-
}
|
|
30656
|
-
setEvents((current) => [...current, event]);
|
|
30657
|
-
}
|
|
30658
|
-
};
|
|
30659
|
-
const enterStep = (step) => {
|
|
30660
|
-
setActiveStep(step);
|
|
30661
|
-
setEvents([]);
|
|
30662
|
-
setPageHelp(null);
|
|
30663
|
-
};
|
|
30664
|
-
void (async () => {
|
|
30665
|
-
const results = [];
|
|
30666
|
-
const prerequisites = await runPrerequisitesSetup(uiDependencies, repoRoot, {
|
|
30667
|
-
...skip.skipBuild !== void 0 ? { skipBuild: skip.skipBuild } : {}
|
|
30668
|
-
});
|
|
30669
|
-
results.push({
|
|
30670
|
-
name: "Node.js 24+",
|
|
30671
|
-
status: prerequisites.node.passed ? "completed" : "failed",
|
|
30672
|
-
required: true
|
|
30673
|
-
});
|
|
30674
|
-
if (!prerequisites.node.passed) {
|
|
30675
|
-
setNotice("Node.js setup requires a shell restart. Re-run experiences setup afterwards.");
|
|
30676
|
-
const restartOutcome = {
|
|
30677
|
-
results,
|
|
30678
|
-
exitCode: 0,
|
|
30679
|
-
restartRequired: prerequisites.node.restartRequired ?? false,
|
|
30680
|
-
runDoctor: false
|
|
30681
|
-
};
|
|
30682
|
-
setOutcome(restartOutcome);
|
|
30683
|
-
onComplete(restartOutcome);
|
|
30684
|
-
return;
|
|
30685
|
-
}
|
|
30686
|
-
results.push({ name: "pnpm", status: prerequisites.pnpm?.passed ? "completed" : "failed", required: true });
|
|
30687
|
-
if (prerequisites.build) {
|
|
30688
|
-
results.push({
|
|
30689
|
-
name: "Install & build",
|
|
30690
|
-
status: prerequisites.build.passed ? "completed" : "failed",
|
|
30691
|
-
required: true
|
|
30692
|
-
});
|
|
30693
|
-
} else if (skip.skipBuild) {
|
|
30694
|
-
results.push({ name: "Install & build", status: "skipped", required: false });
|
|
30695
|
-
}
|
|
30696
|
-
enterStep(2);
|
|
30697
|
-
if (skip.skipAgent) {
|
|
30698
|
-
results.push({ name: "Coding agent", status: "skipped", required: false });
|
|
30699
|
-
} else {
|
|
30700
|
-
const { agent, agentModel, passed } = await runAgentSetup(uiDependencies);
|
|
30701
|
-
if (agent) {
|
|
30702
|
-
const stored = await dependencies.readCredentials();
|
|
30703
|
-
const { agentModel: _staleModel, ...storedWithoutModel } = stored;
|
|
30704
|
-
await dependencies.writeCredentials({
|
|
30705
|
-
...storedWithoutModel,
|
|
30706
|
-
agent,
|
|
30707
|
-
...agentModel ? { agentModel } : {}
|
|
30708
|
-
});
|
|
30709
|
-
}
|
|
30710
|
-
results.push({ name: "Coding agent", status: passed ? "completed" : "failed", required: true });
|
|
30711
|
-
}
|
|
30712
|
-
enterStep(3);
|
|
30713
|
-
if (skip.skipCredentials) {
|
|
30714
|
-
results.push({ name: "Contentful credentials", status: "skipped", required: false });
|
|
30715
|
-
} else {
|
|
30716
|
-
const credentials = await runCredentialsSetup(uiDependencies);
|
|
30717
|
-
results.push({
|
|
30718
|
-
name: "Contentful credentials",
|
|
30719
|
-
status: credentials.passed ? "completed" : "failed",
|
|
30720
|
-
required: false
|
|
30721
|
-
});
|
|
30722
|
-
}
|
|
30723
|
-
enterStep(4);
|
|
30724
|
-
if (skip.skipOptional) {
|
|
30725
|
-
results.push({ name: "Preferences", status: "skipped", required: false });
|
|
30726
|
-
} else {
|
|
30727
|
-
const { selected } = await runPreferenceSetupAction(uiDependencies, profilePath);
|
|
30728
|
-
results.push({
|
|
30729
|
-
name: "Preferences",
|
|
30730
|
-
status: selected.length > 0 ? "completed" : "skipped",
|
|
30731
|
-
required: false
|
|
30732
|
-
});
|
|
30733
|
-
}
|
|
30734
|
-
const exitCode = countRequiredFailures(results) === 0 ? 0 : 1;
|
|
30735
|
-
setPrompt(null);
|
|
30736
|
-
setEvents([]);
|
|
30737
|
-
setOutcome({ results, exitCode, restartRequired: false, runDoctor: false });
|
|
30738
|
-
const runDoctor2 = offerDoctor ? await request2((resolve27) => ({
|
|
30739
|
-
kind: "confirm",
|
|
30740
|
-
question: "Run experiences doctor now to verify your environment?",
|
|
30741
|
-
defaultYes: exitCode === 0,
|
|
30742
|
-
resolve: resolve27
|
|
30743
|
-
})) : false;
|
|
30744
|
-
setPrompt(null);
|
|
30745
|
-
const finalOutcome = { results, exitCode, restartRequired: false, runDoctor: runDoctor2 };
|
|
30746
|
-
setOutcome(finalOutcome);
|
|
30747
|
-
onComplete(finalOutcome);
|
|
30748
|
-
})();
|
|
30749
|
-
}, []);
|
|
30750
|
-
usePromptInput((chunk, key) => {
|
|
30751
|
-
const active = prompt;
|
|
30752
|
-
if (!active) return;
|
|
30753
|
-
if (active.kind === "select") return;
|
|
30754
|
-
const submit = (value) => {
|
|
30755
|
-
setPrompt(null);
|
|
30756
|
-
updateInput("");
|
|
30757
|
-
if (active.kind === "confirm") {
|
|
30758
|
-
const answer = value.trim().toLowerCase();
|
|
30759
|
-
active.resolve(answer === "" ? active.defaultYes : answer.startsWith("y"));
|
|
30760
|
-
} else {
|
|
30761
|
-
active.resolve(value.trim());
|
|
30762
|
-
}
|
|
30763
|
-
};
|
|
30764
|
-
if (key.return) {
|
|
30765
|
-
submit(inputValueRef.current);
|
|
30766
|
-
return;
|
|
30767
|
-
}
|
|
30768
|
-
if (key.backspace || key.delete) {
|
|
30769
|
-
updateInput(inputValueRef.current.slice(0, -1));
|
|
30770
|
-
return;
|
|
30771
|
-
}
|
|
30772
|
-
if (key.ctrl || key.meta || key.escape || key.tab) return;
|
|
30773
|
-
const { text, submitted } = splitPromptInput(chunk);
|
|
30774
|
-
if (!text && !submitted) return;
|
|
30775
|
-
const next = inputValueRef.current + text;
|
|
30776
|
-
if (submitted) submit(next);
|
|
30777
|
-
else updateInput(next);
|
|
30778
|
-
});
|
|
30779
|
-
const versionLabel = `v${version}`;
|
|
30780
|
-
const alignRight = shouldAlignVersionRight(version, columns);
|
|
30781
|
-
return /* @__PURE__ */ jsxs53(Box51, { flexDirection: "column", paddingX: 1, children: [
|
|
30782
|
-
/* @__PURE__ */ jsxs53(Box51, { children: [
|
|
30783
|
-
/* @__PURE__ */ jsx54(Text53, { bold: true, children: SETUP_TITLE }),
|
|
30784
|
-
alignRight ? /* @__PURE__ */ jsx54(Box51, { flexGrow: 1 }) : /* @__PURE__ */ jsx54(Text53, { children: " " }),
|
|
30785
|
-
/* @__PURE__ */ jsx54(Text53, { dimColor: true, children: versionLabel })
|
|
30786
|
-
] }),
|
|
30787
|
-
/* @__PURE__ */ jsx54(Box51, { marginTop: 1, children: /* @__PURE__ */ jsx54(SetupStepper, { activeStep, columns }) }),
|
|
30788
|
-
outcome ? /* @__PURE__ */ jsx54(SetupSummary, { outcome, notice }) : /* @__PURE__ */ jsxs53(Fragment16, { children: [
|
|
30789
|
-
/* @__PURE__ */ jsx54(SetupEventLog, { events }),
|
|
30790
|
-
!prompt && /* @__PURE__ */ jsx54(Box51, { marginTop: 1, children: /* @__PURE__ */ jsxs53(Text53, { color: PALETTE.info, children: [
|
|
30791
|
-
"\u27F3 ",
|
|
30792
|
-
STEP_ACTIVITY[activeStep - 1],
|
|
30793
|
-
"\u2026"
|
|
30794
|
-
] }) })
|
|
30795
|
-
] }),
|
|
30796
|
-
prompt && (prompt.kind === "select" ? /* @__PURE__ */ jsx54(
|
|
30797
|
-
SetupChoiceList,
|
|
30798
|
-
{
|
|
30799
|
-
prompt,
|
|
30800
|
-
onResolve: (index) => {
|
|
30801
|
-
setPrompt(null);
|
|
30802
|
-
prompt.resolve(index);
|
|
30803
|
-
}
|
|
30804
|
-
}
|
|
30805
|
-
) : /* @__PURE__ */ jsx54(SetupPrompt, { prompt, value: inputValue })),
|
|
30806
|
-
pageHelp && !outcome && /* @__PURE__ */ jsx54(Box51, { marginTop: 1, children: /* @__PURE__ */ jsx54(Text53, { dimColor: true, children: pageHelp }) })
|
|
30807
|
-
] });
|
|
30808
|
-
}
|
|
30809
|
-
function SetupEventLog({ events }) {
|
|
30810
|
-
if (events.length === 0) return null;
|
|
30811
|
-
return /* @__PURE__ */ jsx54(Box51, { flexDirection: "column", marginTop: 1, children: events.map((event, index) => /* @__PURE__ */ jsx54(SetupEventLine, { event }, `${index}-${event.message}`)) });
|
|
30812
|
-
}
|
|
30813
|
-
function SetupEventLine({ event }) {
|
|
30814
|
-
if (event.message === "") return /* @__PURE__ */ jsx54(Text53, { children: " " });
|
|
30815
|
-
if (event.kind === "success") return /* @__PURE__ */ jsxs53(Text53, { color: PALETTE.success, children: [
|
|
30816
|
-
"\u2713 ",
|
|
30817
|
-
event.message
|
|
30818
|
-
] });
|
|
30819
|
-
if (event.kind === "failure") return /* @__PURE__ */ jsxs53(Text53, { color: PALETTE.error, children: [
|
|
30820
|
-
"\u2717 ",
|
|
30821
|
-
event.message
|
|
30822
|
-
] });
|
|
30823
|
-
if (event.kind === "warning") return /* @__PURE__ */ jsxs53(Text53, { color: PALETTE.warning, children: [
|
|
30824
|
-
"\u26A0 ",
|
|
30825
|
-
event.message
|
|
30826
|
-
] });
|
|
30827
|
-
if (event.kind === "help") return /* @__PURE__ */ jsx54(Text53, { dimColor: true, children: event.message });
|
|
30828
|
-
if (event.kind === "value") return /* @__PURE__ */ jsxs53(Text53, { children: [
|
|
30829
|
-
" ",
|
|
30830
|
-
event.message
|
|
30831
|
-
] });
|
|
30832
|
-
return /* @__PURE__ */ jsx54(Text53, { children: event.message });
|
|
30833
|
-
}
|
|
30834
|
-
function SetupChoiceList({
|
|
30835
|
-
prompt,
|
|
30836
|
-
onResolve
|
|
30837
|
-
}) {
|
|
30838
|
-
const options = [
|
|
30839
|
-
...prompt.options.map((option, index) => ({
|
|
30840
|
-
label: option.description ? `${option.label} ${option.description}` : option.label,
|
|
30841
|
-
value: String(index)
|
|
30842
|
-
})),
|
|
30843
|
-
{ label: "Skip", value: SKIP_VALUE }
|
|
30844
|
-
];
|
|
30845
|
-
return /* @__PURE__ */ jsxs53(Box51, { flexDirection: "column", marginTop: 1, children: [
|
|
30846
|
-
/* @__PURE__ */ jsx54(Text53, { children: prompt.question }),
|
|
30847
|
-
/* @__PURE__ */ jsx54(Box51, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsx54(
|
|
30848
|
-
Select,
|
|
30849
|
-
{
|
|
30850
|
-
options,
|
|
30851
|
-
visibleOptionCount: options.length,
|
|
30852
|
-
onChange: (value) => onResolve(value === SKIP_VALUE ? void 0 : Number(value))
|
|
30853
|
-
}
|
|
30854
|
-
) }),
|
|
30855
|
-
/* @__PURE__ */ jsx54(Box51, { marginTop: 1, children: /* @__PURE__ */ jsx54(Text53, { dimColor: true, children: "\u2191\u2193 to move \xB7 Enter to select" }) })
|
|
30856
|
-
] });
|
|
30857
|
-
}
|
|
30858
|
-
function SetupPrompt({ prompt, value }) {
|
|
30859
|
-
if (prompt.kind === "select") return /* @__PURE__ */ jsx54(Text53, { children: prompt.question });
|
|
30860
|
-
const display = prompt.kind === "secret" ? "\u2022".repeat(value.length) : value;
|
|
30861
|
-
const hint = prompt.kind === "confirm" ? prompt.defaultYes ? " [Y/n]" : " [y/N]" : "";
|
|
30862
|
-
return /* @__PURE__ */ jsxs53(Box51, { marginTop: 1, children: [
|
|
30863
|
-
/* @__PURE__ */ jsx54(Text53, { color: PALETTE.info, children: "\u203A " }),
|
|
30864
|
-
/* @__PURE__ */ jsxs53(Text53, { children: [
|
|
30865
|
-
prompt.question,
|
|
30866
|
-
hint
|
|
30867
|
-
] }),
|
|
30868
|
-
/* @__PURE__ */ jsxs53(Text53, { children: [
|
|
30869
|
-
" ",
|
|
30870
|
-
display
|
|
30871
|
-
] }),
|
|
30872
|
-
/* @__PURE__ */ jsx54(Text53, { color: PALETTE.info, children: "\u2588" })
|
|
30873
|
-
] });
|
|
30874
|
-
}
|
|
30875
|
-
function SetupSummary({ outcome, notice }) {
|
|
30876
|
-
const requiredFailed = countRequiredFailures(outcome.results);
|
|
30877
|
-
return /* @__PURE__ */ jsxs53(Box51, { flexDirection: "column", marginTop: 1, children: [
|
|
30878
|
-
/* @__PURE__ */ jsx54(Text53, { bold: true, children: "Summary" }),
|
|
30879
|
-
outcome.results.map((result) => {
|
|
30880
|
-
if (result.status === "completed") {
|
|
30881
|
-
return /* @__PURE__ */ jsxs53(Text53, { color: PALETTE.success, children: [
|
|
30882
|
-
"\u2713 ",
|
|
30883
|
-
result.name
|
|
30884
|
-
] }, result.name);
|
|
30885
|
-
}
|
|
30886
|
-
if (result.status === "skipped") {
|
|
30887
|
-
return /* @__PURE__ */ jsxs53(Text53, { dimColor: true, children: [
|
|
30888
|
-
"\u2013 ",
|
|
30889
|
-
result.name,
|
|
30890
|
-
" \u2014 skipped"
|
|
30891
|
-
] }, result.name);
|
|
30892
|
-
}
|
|
30893
|
-
return /* @__PURE__ */ jsxs53(Text53, { color: result.required ? PALETTE.error : PALETTE.warning, children: [
|
|
30894
|
-
result.required ? "\u2717" : "\u26A0",
|
|
30895
|
-
" ",
|
|
30896
|
-
result.name,
|
|
30897
|
-
" \u2014 ",
|
|
30898
|
-
result.required ? "required" : "optional"
|
|
30899
|
-
] }, result.name);
|
|
30900
|
-
}),
|
|
30901
|
-
notice && /* @__PURE__ */ jsx54(Box51, { marginTop: 1, children: /* @__PURE__ */ jsx54(Text53, { color: PALETTE.warning, children: notice }) }),
|
|
30902
|
-
/* @__PURE__ */ jsx54(Box51, { marginTop: 1, children: /* @__PURE__ */ jsx54(Text53, { bold: true, color: requiredFailed === 0 ? PALETTE.success : PALETTE.warning, children: formatSetupCompletionMessage(outcome.results) }) }),
|
|
30903
|
-
requiredFailed > 0 && /* @__PURE__ */ jsx54(Text53, { dimColor: true, children: "Complete the steps above, then re-run experiences setup." })
|
|
30904
|
-
] });
|
|
30905
|
-
}
|
|
30906
|
-
var STEP_ACTIVITY, SKIP_VALUE;
|
|
30907
|
-
var init_SetupScreen = __esm({
|
|
30908
|
-
"packages/experience-design-system-cli/src/setup/tui/SetupScreen.tsx"() {
|
|
30909
|
-
"use strict";
|
|
30910
|
-
init_theme();
|
|
30911
|
-
init_layout();
|
|
30912
|
-
init_prompt_input();
|
|
30913
|
-
init_usePromptInput();
|
|
30914
|
-
init_SetupStepper();
|
|
30915
|
-
init_coding_agent();
|
|
30916
|
-
init_contentful();
|
|
30917
|
-
init_preferences();
|
|
30918
|
-
init_prerequisites();
|
|
30919
|
-
STEP_ACTIVITY = [
|
|
30920
|
-
"Checking prerequisites",
|
|
30921
|
-
"Configuring your coding agent",
|
|
30922
|
-
"Configuring Contentful credentials",
|
|
30923
|
-
"Configuring preferences"
|
|
30924
|
-
];
|
|
30925
|
-
SKIP_VALUE = "\0skip";
|
|
30926
|
-
}
|
|
30927
|
-
});
|
|
30928
|
-
|
|
30929
29824
|
// packages/experience-design-system-cli/src/program.ts
|
|
30930
29825
|
import { spawn as spawn6 } from "node:child_process";
|
|
30931
29826
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
30932
|
-
import { dirname as dirname14, join as
|
|
30933
|
-
import { readFileSync as
|
|
29827
|
+
import { dirname as dirname14, join as join27, resolve as resolve26 } from "node:path";
|
|
29828
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
30934
29829
|
import { Command } from "commander";
|
|
30935
29830
|
|
|
30936
29831
|
// packages/experience-design-system-cli/src/analyze/command.ts
|
|
@@ -31507,7 +30402,7 @@ function resolveProjectRoot(sessionId2, projectRootFlag) {
|
|
|
31507
30402
|
}
|
|
31508
30403
|
}
|
|
31509
30404
|
async function selectBatch(agent, model, batch, total, verbose, skillPathOverride) {
|
|
31510
|
-
const
|
|
30405
|
+
const prompt2 = await buildPrompt({
|
|
31511
30406
|
skill: "select",
|
|
31512
30407
|
mode: "autonomous",
|
|
31513
30408
|
rawComponentsInline: JSON.stringify(
|
|
@@ -31525,7 +30420,7 @@ async function selectBatch(agent, model, batch, total, verbose, skillPathOverrid
|
|
|
31525
30420
|
const result = await invoker.invoke({
|
|
31526
30421
|
agent,
|
|
31527
30422
|
model,
|
|
31528
|
-
prompt,
|
|
30423
|
+
prompt: prompt2,
|
|
31529
30424
|
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
31530
30425
|
onOutput: (chunk) => formatter.push(chunk)
|
|
31531
30426
|
});
|
|
@@ -31829,14 +30724,14 @@ function registerAnalyzeSelectAgentCommand(program) {
|
|
|
31829
30724
|
return;
|
|
31830
30725
|
}
|
|
31831
30726
|
const first = selectionCandidates[0];
|
|
31832
|
-
const
|
|
30727
|
+
const prompt2 = await buildPrompt({
|
|
31833
30728
|
skill: "select",
|
|
31834
30729
|
mode: "autonomous",
|
|
31835
30730
|
rawComponentsInline: JSON.stringify([buildComponentData(first)], null, 2),
|
|
31836
30731
|
outDir: process.cwd(),
|
|
31837
30732
|
skillPathOverride: selectPromptPath ? resolve12(selectPromptPath) : void 0
|
|
31838
30733
|
});
|
|
31839
|
-
process.stdout.write(
|
|
30734
|
+
process.stdout.write(prompt2 + "\n");
|
|
31840
30735
|
await exitWithAnalytics(0);
|
|
31841
30736
|
return;
|
|
31842
30737
|
}
|
|
@@ -32195,8 +31090,8 @@ async function resolveMapping(input) {
|
|
|
32195
31090
|
const residueParents = input.components.map((c2) => c2.name).filter((n) => !coveredParents.has(n));
|
|
32196
31091
|
const shouldRunAgent = (input.useAgent || input.forceAgent) && (input.forceAgent || residueParents.length > 0);
|
|
32197
31092
|
if (shouldRunAgent) {
|
|
32198
|
-
const
|
|
32199
|
-
const raw = await input.runAgentFn({ prompt, files: input.files });
|
|
31093
|
+
const prompt2 = input.buildPrompt ? input.buildPrompt(input.files, [...componentNames]) : defaultPrompt(input.files, [...componentNames], input.promptOverride);
|
|
31094
|
+
const raw = await input.runAgentFn({ prompt: prompt2, files: input.files });
|
|
32200
31095
|
const parsed = parseMapEdges(raw, { componentNames });
|
|
32201
31096
|
collected.push(...parsed.edges);
|
|
32202
31097
|
agentWarnings.push(...parsed.warnings);
|
|
@@ -32676,9 +31571,9 @@ async function resolveViaAgentParser(input) {
|
|
|
32676
31571
|
}
|
|
32677
31572
|
return out;
|
|
32678
31573
|
};
|
|
32679
|
-
const attempt = async (
|
|
31574
|
+
const attempt = async (prompt2) => {
|
|
32680
31575
|
input.onPhase?.("authoring");
|
|
32681
|
-
const raw = await input.runAgentFn({ prompt });
|
|
31576
|
+
const raw = await input.runAgentFn({ prompt: prompt2 });
|
|
32682
31577
|
const source = extractParserSource(raw);
|
|
32683
31578
|
if (source === null)
|
|
32684
31579
|
return { error: "agent output had no parser-shaped code block (expected `export default function (ctx) {\u2026}`)" };
|
|
@@ -33137,10 +32032,10 @@ function registerAnalyzeCommand(program) {
|
|
|
33137
32032
|
const componentNameSet = new Set(validatedComponents.map((c2) => c2.name));
|
|
33138
32033
|
const cacheVersion = await getCliCacheVersion();
|
|
33139
32034
|
let lastAgentExitCode = 0;
|
|
33140
|
-
const spawnAgent = async (
|
|
32035
|
+
const spawnAgent = async (prompt2) => {
|
|
33141
32036
|
const res = await runAgent({
|
|
33142
32037
|
agent: resolverAgent,
|
|
33143
|
-
prompt,
|
|
32038
|
+
prompt: prompt2,
|
|
33144
32039
|
timeoutMs: 12e4,
|
|
33145
32040
|
promptViaStdin: true,
|
|
33146
32041
|
onDebugEvent: (name, payload) => getDebugLogger().event("agent", name, payload)
|
|
@@ -33192,7 +32087,7 @@ function registerAnalyzeCommand(program) {
|
|
|
33192
32087
|
files: promptFiles,
|
|
33193
32088
|
runtimeFiles,
|
|
33194
32089
|
componentNames: componentNameSet,
|
|
33195
|
-
runAgentFn: ({ prompt }) => spawnAgent(
|
|
32090
|
+
runAgentFn: ({ prompt: prompt2 }) => spawnAgent(prompt2),
|
|
33196
32091
|
...compositionPrompt ? { instructionOverride: compositionPrompt } : {},
|
|
33197
32092
|
onPhase: (phase) => emitCompositionProgress(phase),
|
|
33198
32093
|
// The candidate filter selected these files because they carry
|
|
@@ -33236,7 +32131,7 @@ function registerAnalyzeCommand(program) {
|
|
|
33236
32131
|
forceAgent: sources.forceAgent && useEdgeEmission,
|
|
33237
32132
|
files: promptFiles,
|
|
33238
32133
|
...compositionPrompt ? { promptOverride: compositionPrompt } : {},
|
|
33239
|
-
runAgentFn: async ({ prompt }) => {
|
|
32134
|
+
runAgentFn: async ({ prompt: prompt2 }) => {
|
|
33240
32135
|
if (!opts.compositionRefresh) {
|
|
33241
32136
|
const cached = lookupCompositionCache(db, agentCacheKey, cacheVersion);
|
|
33242
32137
|
if (cached !== null) {
|
|
@@ -33245,7 +32140,7 @@ function registerAnalyzeCommand(program) {
|
|
|
33245
32140
|
}
|
|
33246
32141
|
}
|
|
33247
32142
|
emitCompositionProgress(`agent:${resolverAgent}`);
|
|
33248
|
-
const stdout = await spawnAgent(
|
|
32143
|
+
const stdout = await spawnAgent(prompt2);
|
|
33249
32144
|
if (lastAgentExitCode === 0) {
|
|
33250
32145
|
storeCompositionCache(db, agentCacheKey, cacheVersion, stdout);
|
|
33251
32146
|
}
|
|
@@ -33686,7 +32581,7 @@ async function runOneComponent(agent, model, db, sessionId2, component, tokensIn
|
|
|
33686
32581
|
component.props.map((p) => p.name),
|
|
33687
32582
|
component.props.map((p) => p.type)
|
|
33688
32583
|
);
|
|
33689
|
-
const
|
|
32584
|
+
const prompt2 = await buildPrompt({
|
|
33690
32585
|
skill: "components",
|
|
33691
32586
|
mode: "autonomous",
|
|
33692
32587
|
rawComponentsInline,
|
|
@@ -33708,7 +32603,7 @@ async function runOneComponent(agent, model, db, sessionId2, component, tokensIn
|
|
|
33708
32603
|
const result = await invoker2.invoke({
|
|
33709
32604
|
agent,
|
|
33710
32605
|
model,
|
|
33711
|
-
prompt,
|
|
32606
|
+
prompt: prompt2,
|
|
33712
32607
|
timeoutMs: DEFAULT_TIMEOUT_MS3,
|
|
33713
32608
|
onOutput: (chunk) => formatter.push(chunk)
|
|
33714
32609
|
});
|
|
@@ -33931,7 +32826,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
33931
32826
|
sampleComponent.props.map((p) => p.name),
|
|
33932
32827
|
sampleComponent.props.map((p) => p.type)
|
|
33933
32828
|
) : void 0;
|
|
33934
|
-
const
|
|
32829
|
+
const prompt2 = await buildPrompt({
|
|
33935
32830
|
skill,
|
|
33936
32831
|
mode: "autonomous",
|
|
33937
32832
|
rawComponentsInline: sampleInline ?? rawTokensInline,
|
|
@@ -33943,7 +32838,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
33943
32838
|
componentSourceRefs: sampleSourceRef ? [sampleSourceRef] : void 0,
|
|
33944
32839
|
skillPathOverride: generatePromptPath
|
|
33945
32840
|
});
|
|
33946
|
-
process.stdout.write(
|
|
32841
|
+
process.stdout.write(prompt2 + "\n");
|
|
33947
32842
|
await exitWithAnalytics(0);
|
|
33948
32843
|
}
|
|
33949
32844
|
const binary = resolveBinary(agent);
|
|
@@ -34063,7 +32958,7 @@ session=${sessionId2 ?? ""}
|
|
|
34063
32958
|
return;
|
|
34064
32959
|
}
|
|
34065
32960
|
}
|
|
34066
|
-
const
|
|
32961
|
+
const prompt2 = await buildPrompt({
|
|
34067
32962
|
skill,
|
|
34068
32963
|
mode: "autonomous",
|
|
34069
32964
|
rawTokensInline,
|
|
@@ -34075,7 +32970,7 @@ session=${sessionId2 ?? ""}
|
|
|
34075
32970
|
const result = await invoker2.invoke({
|
|
34076
32971
|
agent,
|
|
34077
32972
|
model,
|
|
34078
|
-
prompt,
|
|
32973
|
+
prompt: prompt2,
|
|
34079
32974
|
timeoutMs: DEFAULT_TIMEOUT_MS3 * 5
|
|
34080
32975
|
});
|
|
34081
32976
|
if (result.timedOut) {
|
|
@@ -35427,7 +34322,7 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
|
|
|
35427
34322
|
const tokenTree = rebuildDTCGTree(groups, tokens);
|
|
35428
34323
|
const componentSourceRefs = await loadComponentSourceRefs(db, sessionId2);
|
|
35429
34324
|
if (opts.printPrompt) {
|
|
35430
|
-
const
|
|
34325
|
+
const prompt3 = await buildPrompt({
|
|
35431
34326
|
skill: "map-tokens",
|
|
35432
34327
|
mode: "autonomous",
|
|
35433
34328
|
generatedCdf,
|
|
@@ -35435,7 +34330,7 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
|
|
|
35435
34330
|
componentSourceRefs,
|
|
35436
34331
|
outDir: process.cwd()
|
|
35437
34332
|
});
|
|
35438
|
-
process.stdout.write(
|
|
34333
|
+
process.stdout.write(prompt3 + "\n");
|
|
35439
34334
|
await exitWithAnalytics(0);
|
|
35440
34335
|
return;
|
|
35441
34336
|
}
|
|
@@ -35472,7 +34367,7 @@ Install it, choose another agent with --agent, or use --print-prompt to run the
|
|
|
35472
34367
|
);
|
|
35473
34368
|
}
|
|
35474
34369
|
const stepId = createStep(db, sessionId2, "map tokens", { agent, model: model ?? "" });
|
|
35475
|
-
const
|
|
34370
|
+
const prompt2 = await buildPrompt({
|
|
35476
34371
|
skill: "map-tokens",
|
|
35477
34372
|
mode: "autonomous",
|
|
35478
34373
|
generatedCdf,
|
|
@@ -35481,7 +34376,7 @@ Install it, choose another agent with --agent, or use --print-prompt to run the
|
|
|
35481
34376
|
outDir: process.cwd()
|
|
35482
34377
|
});
|
|
35483
34378
|
const invoker3 = createLocalCliAgentInvoker();
|
|
35484
|
-
const result = await invoker3.invoke({ agent, model, prompt, timeoutMs: DEFAULT_TIMEOUT_MS4 });
|
|
34379
|
+
const result = await invoker3.invoke({ agent, model, prompt: prompt2, timeoutMs: DEFAULT_TIMEOUT_MS4 });
|
|
35485
34380
|
if (result.timedOut || result.exitCode !== 0) {
|
|
35486
34381
|
const error = result.timedOut ? `timed out after ${DEFAULT_TIMEOUT_MS4 / 6e4} minutes` : describeAgentFailure(result);
|
|
35487
34382
|
updateStep(db, stepId, "failed", {}, error);
|
|
@@ -36390,7 +35285,7 @@ async function replayRun(opts) {
|
|
|
36390
35285
|
if (!opts.interactive) {
|
|
36391
35286
|
throw new Error(MISSING_CREDS_ERROR);
|
|
36392
35287
|
}
|
|
36393
|
-
const
|
|
35288
|
+
const prompt2 = opts.promptForCredentials ?? (async (need) => {
|
|
36394
35289
|
const { promptForPushCredentials: promptForPushCredentials2 } = await Promise.resolve().then(() => (init_push_creds_prompt(), push_creds_prompt_exports));
|
|
36395
35290
|
return promptForPushCredentials2({
|
|
36396
35291
|
...need.spaceId ? { initialSpaceId: need.spaceId } : {},
|
|
@@ -36400,7 +35295,7 @@ async function replayRun(opts) {
|
|
|
36400
35295
|
summary: `Push run ${run.id} \u2192 enter credentials. Defaults reflect the run record and your saved setup.`
|
|
36401
35296
|
});
|
|
36402
35297
|
});
|
|
36403
|
-
const collected = await
|
|
35298
|
+
const collected = await prompt2({
|
|
36404
35299
|
spaceId,
|
|
36405
35300
|
environmentId,
|
|
36406
35301
|
cmaToken,
|
|
@@ -37050,18 +35945,54 @@ function registerImportCommand(program) {
|
|
|
37050
35945
|
);
|
|
37051
35946
|
}
|
|
37052
35947
|
|
|
37053
|
-
// packages/experience-design-system-cli/src/
|
|
37054
|
-
init_cli_path();
|
|
37055
|
-
|
|
37056
|
-
// packages/experience-design-system-cli/src/doctor/checks.ts
|
|
35948
|
+
// packages/experience-design-system-cli/src/setup/command.ts
|
|
37057
35949
|
init_credentials_store();
|
|
37058
|
-
|
|
37059
|
-
|
|
37060
|
-
|
|
37061
|
-
import { homedir as
|
|
37062
|
-
import {
|
|
35950
|
+
import { execFile as execFile5, spawn as spawn5 } from "node:child_process";
|
|
35951
|
+
import { appendFile as appendFile2, readFile as readFile27, access as access10 } from "node:fs/promises";
|
|
35952
|
+
import { join as join26 } from "node:path";
|
|
35953
|
+
import { homedir as homedir9 } from "node:os";
|
|
35954
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
35955
|
+
import { createInterface } from "node:readline";
|
|
35956
|
+
import { promisify as promisify2 } from "node:util";
|
|
35957
|
+
|
|
35958
|
+
// packages/experience-design-system-cli/src/setup/auto-filter-prompt.ts
|
|
35959
|
+
async function promptAutoFilterPreference(ask, current) {
|
|
35960
|
+
const defaultValue = current ?? true;
|
|
35961
|
+
const hint = defaultValue ? "[Y/n]" : "[y/N]";
|
|
35962
|
+
const answer = (await ask(` Enable AI auto-filter by default? ${hint} `)).trim().toLowerCase();
|
|
35963
|
+
if (answer === "") return defaultValue;
|
|
35964
|
+
if (answer.startsWith("y")) return true;
|
|
35965
|
+
if (answer.startsWith("n")) return false;
|
|
35966
|
+
return defaultValue;
|
|
35967
|
+
}
|
|
35968
|
+
|
|
35969
|
+
// packages/experience-design-system-cli/src/setup/debug-mode-prompt.ts
|
|
35970
|
+
async function promptDebugModePreference(ask, current) {
|
|
35971
|
+
const defaultValue = current ?? false;
|
|
35972
|
+
const hint = defaultValue ? "[Y/n]" : "[y/N]";
|
|
35973
|
+
const answer = (await ask(` Enable debug logging by default? ${hint} `)).trim().toLowerCase();
|
|
35974
|
+
if (answer === "") return defaultValue;
|
|
35975
|
+
if (answer.startsWith("y")) return true;
|
|
35976
|
+
if (answer.startsWith("n")) return false;
|
|
35977
|
+
return defaultValue;
|
|
35978
|
+
}
|
|
37063
35979
|
|
|
37064
|
-
// packages/experience-design-system-cli/src/
|
|
35980
|
+
// packages/experience-design-system-cli/src/setup/analytics-prompt.ts
|
|
35981
|
+
async function promptAnalyticsPreference(ask, current) {
|
|
35982
|
+
const defaultValue = current ?? false;
|
|
35983
|
+
const hint = defaultValue ? "[Y/n]" : "[y/N]";
|
|
35984
|
+
const answer = (await ask(` Disable anonymous usage analytics? ${hint} `)).trim().toLowerCase();
|
|
35985
|
+
if (answer === "") return defaultValue;
|
|
35986
|
+
if (answer.startsWith("y")) return true;
|
|
35987
|
+
if (answer.startsWith("n")) return false;
|
|
35988
|
+
return defaultValue;
|
|
35989
|
+
}
|
|
35990
|
+
|
|
35991
|
+
// packages/experience-design-system-cli/src/setup/command.ts
|
|
35992
|
+
init_host_utils();
|
|
35993
|
+
init_cli_path();
|
|
35994
|
+
var execFileAsync2 = promisify2(execFile5);
|
|
35995
|
+
var REQUIRED_NODE_MAJOR = 24;
|
|
37065
35996
|
function ok(msg) {
|
|
37066
35997
|
process.stdout.write(` \x1B[32m\u2713\x1B[0m ${msg}
|
|
37067
35998
|
`);
|
|
@@ -37078,56 +36009,618 @@ function info(msg) {
|
|
|
37078
36009
|
process.stdout.write(` ${msg}
|
|
37079
36010
|
`);
|
|
37080
36011
|
}
|
|
37081
|
-
function section(title) {
|
|
36012
|
+
function section(title, tag) {
|
|
36013
|
+
const tagStr = tag ? tag === "[required]" ? ` \x1B[31m[required]\x1B[0m` : ` \x1B[2m[optional]\x1B[0m` : "";
|
|
37082
36014
|
process.stdout.write(`
|
|
37083
|
-
\x1B[1m${title}\x1B[0m
|
|
36015
|
+
\x1B[1m${title}\x1B[0m${tagStr}
|
|
36016
|
+
`);
|
|
36017
|
+
}
|
|
36018
|
+
function dim(msg) {
|
|
36019
|
+
process.stdout.write(`\x1B[2m${msg}\x1B[0m
|
|
37084
36020
|
`);
|
|
37085
36021
|
}
|
|
37086
|
-
function
|
|
37087
|
-
|
|
36022
|
+
function isInteractivePromptSession() {
|
|
36023
|
+
return !!(process.stdin.isTTY && process.stdout.isTTY);
|
|
37088
36024
|
}
|
|
37089
|
-
|
|
37090
|
-
|
|
37091
|
-
|
|
37092
|
-
|
|
37093
|
-
const
|
|
37094
|
-
|
|
37095
|
-
|
|
36025
|
+
function prompt(question) {
|
|
36026
|
+
if (!isInteractivePromptSession()) {
|
|
36027
|
+
return Promise.resolve("");
|
|
36028
|
+
}
|
|
36029
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
36030
|
+
return new Promise((resolve27) => {
|
|
36031
|
+
rl.question(question, (answer) => {
|
|
36032
|
+
rl.close();
|
|
36033
|
+
resolve27(answer.trim());
|
|
36034
|
+
});
|
|
36035
|
+
});
|
|
36036
|
+
}
|
|
36037
|
+
function promptSecret(question) {
|
|
36038
|
+
if (!isInteractivePromptSession()) {
|
|
36039
|
+
return Promise.resolve("");
|
|
36040
|
+
}
|
|
36041
|
+
return new Promise((resolve27) => {
|
|
36042
|
+
const rl = createInterface({
|
|
36043
|
+
input: process.stdin,
|
|
36044
|
+
output: process.stdout,
|
|
36045
|
+
terminal: process.stdin.isTTY
|
|
36046
|
+
});
|
|
36047
|
+
let value = "";
|
|
36048
|
+
process.stdout.write(question);
|
|
36049
|
+
let origWrite = null;
|
|
36050
|
+
if (process.stdin.isTTY) {
|
|
36051
|
+
origWrite = rl.output.write.bind(
|
|
36052
|
+
rl.output
|
|
36053
|
+
);
|
|
36054
|
+
rl.output.write = (s) => {
|
|
36055
|
+
if (s === "\r\n" || s === "\n" || s === "\r") origWrite(s);
|
|
36056
|
+
};
|
|
36057
|
+
}
|
|
36058
|
+
rl.on("line", (line) => {
|
|
36059
|
+
value = line;
|
|
36060
|
+
rl.close();
|
|
36061
|
+
});
|
|
36062
|
+
rl.once("close", () => {
|
|
36063
|
+
if (origWrite) {
|
|
36064
|
+
rl.output.write = origWrite;
|
|
36065
|
+
}
|
|
36066
|
+
if (!process.stdin.isTTY) process.stdout.write("\n");
|
|
36067
|
+
process.stdin.resume();
|
|
36068
|
+
resolve27(value);
|
|
36069
|
+
});
|
|
36070
|
+
});
|
|
36071
|
+
}
|
|
36072
|
+
async function confirm(question, defaultYes = true) {
|
|
36073
|
+
if (!isInteractivePromptSession()) {
|
|
36074
|
+
return false;
|
|
36075
|
+
}
|
|
36076
|
+
const hint = defaultYes ? "[Y/n]" : "[y/N]";
|
|
36077
|
+
const answer = await prompt(` ${question} ${hint} `);
|
|
36078
|
+
if (!answer) return defaultYes;
|
|
36079
|
+
return answer.toLowerCase().startsWith("y");
|
|
36080
|
+
}
|
|
36081
|
+
async function binaryExists(name) {
|
|
36082
|
+
try {
|
|
36083
|
+
await execFileAsync2("which", [name]);
|
|
36084
|
+
return true;
|
|
36085
|
+
} catch {
|
|
36086
|
+
return false;
|
|
36087
|
+
}
|
|
36088
|
+
}
|
|
36089
|
+
function runSpawn(cmd, args, opts = {}) {
|
|
36090
|
+
return new Promise((resolve27) => {
|
|
36091
|
+
const child = spawn5(cmd, args, {
|
|
36092
|
+
cwd: opts.cwd,
|
|
36093
|
+
env: opts.env ?? process.env,
|
|
36094
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
36095
|
+
});
|
|
36096
|
+
let settled = false;
|
|
36097
|
+
let stdout = "";
|
|
36098
|
+
let stderr = "";
|
|
36099
|
+
child.on("error", (err) => {
|
|
36100
|
+
if (!settled) {
|
|
36101
|
+
settled = true;
|
|
36102
|
+
resolve27({ exitCode: 1, stdout: "", stderr: err.message });
|
|
36103
|
+
}
|
|
36104
|
+
});
|
|
36105
|
+
child.stdout.on("data", (d) => {
|
|
36106
|
+
stdout += String(d);
|
|
36107
|
+
});
|
|
36108
|
+
child.stderr.on("data", (d) => {
|
|
36109
|
+
stderr += String(d);
|
|
36110
|
+
});
|
|
36111
|
+
child.on("exit", (code) => {
|
|
36112
|
+
if (!settled) {
|
|
36113
|
+
settled = true;
|
|
36114
|
+
resolve27({ exitCode: code ?? 1, stdout, stderr });
|
|
36115
|
+
}
|
|
36116
|
+
});
|
|
36117
|
+
});
|
|
36118
|
+
}
|
|
36119
|
+
async function detectShellProfile() {
|
|
36120
|
+
const shell = process.env["SHELL"] ?? "";
|
|
36121
|
+
const home = homedir9();
|
|
36122
|
+
if (shell.includes("zsh")) {
|
|
36123
|
+
return join26(home, ".zshrc");
|
|
36124
|
+
}
|
|
36125
|
+
if (shell.includes("bash")) {
|
|
36126
|
+
const bashProfile = join26(home, ".bash_profile");
|
|
36127
|
+
const exists = await access10(bashProfile).then(() => true).catch(() => false);
|
|
36128
|
+
return exists ? bashProfile : join26(home, ".bashrc");
|
|
36129
|
+
}
|
|
36130
|
+
if (shell.includes("fish")) {
|
|
36131
|
+
return join26(home, ".config", "fish", "config.fish");
|
|
36132
|
+
}
|
|
36133
|
+
return join26(home, ".profile");
|
|
36134
|
+
}
|
|
36135
|
+
async function profileContains(profilePath, str) {
|
|
36136
|
+
try {
|
|
36137
|
+
const content = await readFile27(profilePath, "utf8");
|
|
36138
|
+
return content.includes(str);
|
|
36139
|
+
} catch {
|
|
36140
|
+
return false;
|
|
36141
|
+
}
|
|
36142
|
+
}
|
|
36143
|
+
async function appendToProfile(profilePath, lines) {
|
|
36144
|
+
await appendFile2(profilePath, `
|
|
36145
|
+
${lines}
|
|
36146
|
+
`, "utf8");
|
|
36147
|
+
}
|
|
36148
|
+
async function setupNode() {
|
|
36149
|
+
section("Step 1: Node.js", "[required]");
|
|
36150
|
+
const current = process.versions.node;
|
|
36151
|
+
const major = parseInt(current.split(".")[0], 10);
|
|
36152
|
+
if (major >= REQUIRED_NODE_MAJOR) {
|
|
36153
|
+
ok(`Node.js v${current} \u2014 already good`);
|
|
37096
36154
|
return true;
|
|
37097
36155
|
}
|
|
37098
|
-
fail(`Node.js v${
|
|
36156
|
+
fail(`Node.js v${current} \u2014 need v${REQUIRED_NODE_MAJOR}+`);
|
|
37099
36157
|
info("");
|
|
37100
|
-
|
|
37101
|
-
const
|
|
37102
|
-
if (
|
|
37103
|
-
info(`
|
|
37104
|
-
|
|
37105
|
-
|
|
37106
|
-
|
|
37107
|
-
|
|
37108
|
-
|
|
37109
|
-
|
|
37110
|
-
|
|
36158
|
+
const hasNvm = await binaryExists("nvm") || await access10(join26(homedir9(), ".nvm", "nvm.sh")).then(() => true).catch(() => false);
|
|
36159
|
+
const hasFnm = await binaryExists("fnm");
|
|
36160
|
+
if (hasNvm) {
|
|
36161
|
+
info(`nvm detected. Will run: nvm install ${REQUIRED_NODE_MAJOR} && nvm use ${REQUIRED_NODE_MAJOR}`);
|
|
36162
|
+
const go = await confirm(`Install and switch to Node ${REQUIRED_NODE_MAJOR} via nvm?`);
|
|
36163
|
+
if (!go) {
|
|
36164
|
+
warn(`Skipped. Re-run experiences setup after switching to Node ${REQUIRED_NODE_MAJOR}.`);
|
|
36165
|
+
return false;
|
|
36166
|
+
}
|
|
36167
|
+
const nvmScript = join26(homedir9(), ".nvm", "nvm.sh");
|
|
36168
|
+
const result = await runSpawn("bash", [
|
|
36169
|
+
"-c",
|
|
36170
|
+
`source "${nvmScript}" && nvm install ${REQUIRED_NODE_MAJOR} && nvm alias default ${REQUIRED_NODE_MAJOR}`
|
|
36171
|
+
]);
|
|
36172
|
+
if (result.exitCode !== 0) {
|
|
36173
|
+
fail("nvm install failed");
|
|
36174
|
+
info(result.stderr.trim().split("\n").slice(0, 5).join("\n"));
|
|
36175
|
+
info(`Run manually: nvm install ${REQUIRED_NODE_MAJOR} && nvm use ${REQUIRED_NODE_MAJOR}`);
|
|
36176
|
+
return false;
|
|
36177
|
+
}
|
|
36178
|
+
ok(`Node ${REQUIRED_NODE_MAJOR} installed via nvm. Re-run experiences setup in a fresh shell to pick it up.`);
|
|
36179
|
+
return false;
|
|
36180
|
+
}
|
|
36181
|
+
if (hasFnm) {
|
|
36182
|
+
info(`fnm detected. Will run: fnm install ${REQUIRED_NODE_MAJOR} && fnm use ${REQUIRED_NODE_MAJOR}`);
|
|
36183
|
+
const go = await confirm(`Install and switch to Node ${REQUIRED_NODE_MAJOR} via fnm?`);
|
|
36184
|
+
if (!go) {
|
|
36185
|
+
warn(`Skipped. Re-run experiences setup after switching to Node ${REQUIRED_NODE_MAJOR}.`);
|
|
36186
|
+
return false;
|
|
36187
|
+
}
|
|
36188
|
+
const result = await runSpawn("fnm", ["install", String(REQUIRED_NODE_MAJOR)]);
|
|
36189
|
+
if (result.exitCode !== 0) {
|
|
36190
|
+
fail("fnm install failed");
|
|
36191
|
+
info(`Run manually: fnm install ${REQUIRED_NODE_MAJOR} && fnm use ${REQUIRED_NODE_MAJOR}`);
|
|
36192
|
+
return false;
|
|
36193
|
+
}
|
|
36194
|
+
const useResult = await runSpawn("fnm", ["use", String(REQUIRED_NODE_MAJOR)]);
|
|
36195
|
+
if (useResult.exitCode !== 0) {
|
|
36196
|
+
warn(`fnm use ${REQUIRED_NODE_MAJOR} failed \u2014 node installed but not activated`);
|
|
36197
|
+
info(`Run manually: fnm use ${REQUIRED_NODE_MAJOR} && fnm default ${REQUIRED_NODE_MAJOR}`);
|
|
36198
|
+
} else {
|
|
36199
|
+
const defaultResult = await runSpawn("fnm", ["default", String(REQUIRED_NODE_MAJOR)]);
|
|
36200
|
+
if (defaultResult.exitCode !== 0) {
|
|
36201
|
+
warn(`fnm default ${REQUIRED_NODE_MAJOR} failed \u2014 version won't persist across new shells`);
|
|
36202
|
+
info(`Run manually: fnm default ${REQUIRED_NODE_MAJOR}`);
|
|
36203
|
+
}
|
|
36204
|
+
}
|
|
36205
|
+
ok(`Node ${REQUIRED_NODE_MAJOR} installed via fnm. Re-run experiences setup in a fresh shell.`);
|
|
36206
|
+
return false;
|
|
37111
36207
|
}
|
|
36208
|
+
info("No Node version manager detected (nvm or fnm).");
|
|
36209
|
+
const installNvm = await confirm("Install nvm now? (recommended)");
|
|
36210
|
+
if (installNvm) {
|
|
36211
|
+
info("Running nvm install script...");
|
|
36212
|
+
const result = await runSpawn("bash", [
|
|
36213
|
+
"-c",
|
|
36214
|
+
"curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash"
|
|
36215
|
+
]);
|
|
36216
|
+
if (result.exitCode !== 0) {
|
|
36217
|
+
fail("nvm install failed");
|
|
36218
|
+
info("Install manually: https://github.com/nvm-sh/nvm#installing-and-updating");
|
|
36219
|
+
return false;
|
|
36220
|
+
}
|
|
36221
|
+
ok("nvm installed. Open a new shell, then re-run experiences setup.");
|
|
36222
|
+
return false;
|
|
36223
|
+
}
|
|
36224
|
+
info(`Install Node ${REQUIRED_NODE_MAJOR} manually from https://nodejs.org`);
|
|
37112
36225
|
return false;
|
|
37113
36226
|
}
|
|
37114
|
-
async function
|
|
36227
|
+
async function setupPnpm() {
|
|
36228
|
+
section("Step 2: pnpm", "[required]");
|
|
36229
|
+
if (await binaryExists("pnpm")) {
|
|
36230
|
+
const v = await runSpawn("pnpm", ["--version"]);
|
|
36231
|
+
ok(`pnpm v${v.stdout.trim()} \u2014 already installed`);
|
|
36232
|
+
return true;
|
|
36233
|
+
}
|
|
36234
|
+
fail("pnpm not found");
|
|
36235
|
+
info("");
|
|
36236
|
+
const hasCorecpack = await binaryExists("corepack");
|
|
36237
|
+
if (hasCorecpack) {
|
|
36238
|
+
info("Will run: corepack enable && corepack prepare pnpm@latest --activate");
|
|
36239
|
+
const go2 = await confirm("Install pnpm via corepack?");
|
|
36240
|
+
if (go2) {
|
|
36241
|
+
const r1 = await runSpawn("corepack", ["enable"]);
|
|
36242
|
+
const r2 = r1.exitCode === 0 ? await runSpawn("corepack", ["prepare", "pnpm@latest", "--activate"]) : r1;
|
|
36243
|
+
if (r2.exitCode !== 0) {
|
|
36244
|
+
fail("corepack install failed");
|
|
36245
|
+
info("Try: npm install -g pnpm");
|
|
36246
|
+
return false;
|
|
36247
|
+
}
|
|
36248
|
+
ok("pnpm installed via corepack");
|
|
36249
|
+
return true;
|
|
36250
|
+
}
|
|
36251
|
+
}
|
|
36252
|
+
info("Will run: npm install -g pnpm");
|
|
36253
|
+
const go = await confirm("Install pnpm via npm?");
|
|
36254
|
+
if (!go) {
|
|
36255
|
+
warn("Skipped. Install pnpm manually: npm install -g pnpm");
|
|
36256
|
+
return false;
|
|
36257
|
+
}
|
|
36258
|
+
const result = await runSpawn("npm", ["install", "-g", "pnpm"]);
|
|
36259
|
+
if (result.exitCode !== 0) {
|
|
36260
|
+
fail("npm install -g pnpm failed");
|
|
36261
|
+
info(result.stderr.trim().split("\n").slice(0, 5).join("\n"));
|
|
36262
|
+
return false;
|
|
36263
|
+
}
|
|
36264
|
+
ok("pnpm installed");
|
|
36265
|
+
return true;
|
|
36266
|
+
}
|
|
36267
|
+
async function setupBuild(repoRoot) {
|
|
36268
|
+
section("Step 3: Install dependencies & build", "[required]");
|
|
36269
|
+
info("Running pnpm install...");
|
|
36270
|
+
const installResult = await runSpawn("pnpm", ["install", "--frozen-lockfile"], { cwd: repoRoot });
|
|
36271
|
+
if (installResult.exitCode !== 0) {
|
|
36272
|
+
fail("pnpm install failed");
|
|
36273
|
+
const errLines = installResult.stderr.trim().split("\n").slice(0, 8);
|
|
36274
|
+
for (const line of errLines) info(line);
|
|
36275
|
+
info("");
|
|
36276
|
+
info("Try: pnpm install (without --frozen-lockfile) to update the lockfile");
|
|
36277
|
+
return false;
|
|
36278
|
+
}
|
|
36279
|
+
ok("Dependencies installed");
|
|
36280
|
+
info("Building CLI...");
|
|
36281
|
+
const buildResult = await runSpawn("pnpm", ["--filter", "@contentful/experience-design-system-cli", "run", "build"], {
|
|
36282
|
+
cwd: repoRoot
|
|
36283
|
+
});
|
|
36284
|
+
if (buildResult.exitCode !== 0) {
|
|
36285
|
+
fail("Build failed");
|
|
36286
|
+
const errLines = buildResult.stderr.trim().split("\n").slice(0, 10);
|
|
36287
|
+
for (const line of errLines) info(line);
|
|
36288
|
+
return false;
|
|
36289
|
+
}
|
|
36290
|
+
ok("CLI built successfully");
|
|
36291
|
+
return true;
|
|
36292
|
+
}
|
|
36293
|
+
var AGENT_DEFS = [
|
|
36294
|
+
{ name: "Claude Code", binary: "claude", installHint: "npm install -g @anthropic-ai/claude-code && claude login" },
|
|
36295
|
+
{ name: "OpenAI Codex", binary: "codex", installHint: "npm install -g @openai/codex (requires OPENAI_API_KEY)" },
|
|
36296
|
+
{ name: "OpenCode", binary: "opencode", installHint: "npm install -g opencode-ai && opencode auth" },
|
|
36297
|
+
{ name: "GitHub Copilot", binary: "copilot", installHint: "npm install -g @github/copilot && copilot" }
|
|
36298
|
+
];
|
|
36299
|
+
function pick(items, defaultIdx = 0) {
|
|
36300
|
+
items.forEach((item, i) => {
|
|
36301
|
+
const num = `\x1B[1m[${i + 1}]\x1B[0m`;
|
|
36302
|
+
const desc = item.description ? ` \x1B[2m${item.description}\x1B[0m` : "";
|
|
36303
|
+
const def = i === defaultIdx ? ` \x1B[2m(default)\x1B[0m` : "";
|
|
36304
|
+
process.stdout.write(` ${num} ${item.label}${desc}${def}
|
|
36305
|
+
`);
|
|
36306
|
+
});
|
|
36307
|
+
process.stdout.write(` \x1B[2m[s] Skip\x1B[0m
|
|
36308
|
+
`);
|
|
36309
|
+
}
|
|
36310
|
+
async function promptCodexModel(ask = prompt) {
|
|
36311
|
+
if (process.env["OPENAI_API_KEY"]) return void 0;
|
|
36312
|
+
info("");
|
|
36313
|
+
process.stdout.write(` \x1B[33m\u26A0\x1B[0m No OPENAI_API_KEY \u2014 using ChatGPT account authentication.
|
|
36314
|
+
`);
|
|
36315
|
+
info(" Tip: run \x1B[1mcodex\x1B[0m then type \x1B[1m/model\x1B[0m to browse the models available to your account.");
|
|
36316
|
+
const model = await ask(" Model name (optional - press Enter for Codex default): ");
|
|
36317
|
+
const trimmed = model.trim();
|
|
36318
|
+
return trimmed || void 0;
|
|
36319
|
+
}
|
|
36320
|
+
async function setupAgent() {
|
|
36321
|
+
section("Step 4: Coding agent (claude, codex, opencode, or copilot)", "[required]");
|
|
36322
|
+
info("experiences import uses a coding agent to generate component definitions.");
|
|
36323
|
+
info("");
|
|
36324
|
+
const found = (await Promise.all(AGENT_DEFS.map(async (a) => await binaryExists(a.binary) ? a : null))).filter(
|
|
36325
|
+
(a) => a !== null
|
|
36326
|
+
);
|
|
36327
|
+
if (found.length === 1) {
|
|
36328
|
+
ok(`${found[0].name} (${found[0].binary}) found`);
|
|
36329
|
+
const agentModel = found[0].binary === "codex" ? await promptCodexModel() : void 0;
|
|
36330
|
+
return { agent: found[0].binary, agentModel };
|
|
36331
|
+
}
|
|
36332
|
+
if (found.length > 1) {
|
|
36333
|
+
info("Multiple coding agents found. Choose one to use as the default:");
|
|
36334
|
+
info("");
|
|
36335
|
+
pick(found.map((a) => ({ label: `${a.name}`, description: a.binary })));
|
|
36336
|
+
info("");
|
|
36337
|
+
const choice2 = await prompt(" \x1B[2m\u203A\x1B[0m Your choice [1]: ");
|
|
36338
|
+
if (choice2.toLowerCase() === "s") {
|
|
36339
|
+
warn("Skipped. Install a coding agent before running experiences import.");
|
|
36340
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36341
|
+
}
|
|
36342
|
+
const parsed = choice2 === "" ? 1 : parseInt(choice2, 10);
|
|
36343
|
+
const idx = Number.isNaN(parsed) || parsed < 1 || parsed > found.length ? 0 : parsed - 1;
|
|
36344
|
+
const selected = found[idx];
|
|
36345
|
+
const agentModel = selected.binary === "codex" ? await promptCodexModel() : void 0;
|
|
36346
|
+
return { agent: selected.binary, agentModel };
|
|
36347
|
+
}
|
|
36348
|
+
warn("No coding agent found on PATH");
|
|
36349
|
+
info("");
|
|
36350
|
+
info("Choose one to install:");
|
|
36351
|
+
info("");
|
|
36352
|
+
pick([
|
|
36353
|
+
{ label: "Claude Code", description: "npm install -g @anthropic-ai/claude-code" },
|
|
36354
|
+
{ label: "OpenAI Codex", description: "npm install -g @openai/codex" },
|
|
36355
|
+
{ label: "OpenCode", description: "npm install -g opencode-ai" }
|
|
36356
|
+
]);
|
|
36357
|
+
info("");
|
|
36358
|
+
const choice = await prompt(" Your choice: ");
|
|
36359
|
+
if (choice === "1" || choice === "") {
|
|
36360
|
+
const r = await runSpawn("npm", ["install", "-g", "@anthropic-ai/claude-code"]);
|
|
36361
|
+
if (r.exitCode !== 0) {
|
|
36362
|
+
fail("Install failed");
|
|
36363
|
+
info(r.stderr.trim().split("\n").slice(0, 5).join("\n"));
|
|
36364
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36365
|
+
}
|
|
36366
|
+
if (!await binaryExists("claude")) {
|
|
36367
|
+
fail("claude binary not found on PATH after install \u2014 check your npm global bin directory");
|
|
36368
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36369
|
+
}
|
|
36370
|
+
ok("Claude Code installed");
|
|
36371
|
+
info("");
|
|
36372
|
+
info("Next: run `claude login` to authenticate (browser OAuth).");
|
|
36373
|
+
info("Or set ANTHROPIC_API_KEY in your shell profile.");
|
|
36374
|
+
return { agent: "claude", agentModel: void 0 };
|
|
36375
|
+
}
|
|
36376
|
+
if (choice === "2") {
|
|
36377
|
+
const r = await runSpawn("npm", ["install", "-g", "@openai/codex"]);
|
|
36378
|
+
if (r.exitCode !== 0) {
|
|
36379
|
+
fail("Install failed");
|
|
36380
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36381
|
+
}
|
|
36382
|
+
if (!await binaryExists("codex")) {
|
|
36383
|
+
fail("codex binary not found on PATH after install \u2014 check your npm global bin directory");
|
|
36384
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36385
|
+
}
|
|
36386
|
+
ok("OpenAI Codex installed");
|
|
36387
|
+
const agentModel = await promptCodexModel();
|
|
36388
|
+
return { agent: "codex", agentModel };
|
|
36389
|
+
}
|
|
36390
|
+
if (choice === "3") {
|
|
36391
|
+
const r = await runSpawn("npm", ["install", "-g", "opencode-ai"]);
|
|
36392
|
+
if (r.exitCode !== 0) {
|
|
36393
|
+
fail("Install failed");
|
|
36394
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36395
|
+
}
|
|
36396
|
+
if (!await binaryExists("opencode")) {
|
|
36397
|
+
fail("opencode binary not found on PATH after install \u2014 check your npm global bin directory");
|
|
36398
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36399
|
+
}
|
|
36400
|
+
ok("OpenCode installed");
|
|
36401
|
+
info("Run `opencode auth` to configure your provider.");
|
|
36402
|
+
return { agent: "opencode", agentModel: void 0 };
|
|
36403
|
+
}
|
|
36404
|
+
warn("Skipped. Install a coding agent before running experiences import.");
|
|
36405
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36406
|
+
}
|
|
36407
|
+
async function setupContentfulCredentials() {
|
|
36408
|
+
section("Step 5: Contentful credentials", "[optional]");
|
|
36409
|
+
info(`Saved to ${experiencesCredentialsPath()} \u2014 loaded automatically by experiences import.`);
|
|
36410
|
+
info("");
|
|
36411
|
+
const envShadowing = [
|
|
36412
|
+
process.env["CONTENTFUL_SPACE_ID"] ? "CONTENTFUL_SPACE_ID" : null,
|
|
36413
|
+
process.env["CONTENTFUL_ENVIRONMENT_ID"] ? "CONTENTFUL_ENVIRONMENT_ID" : null,
|
|
36414
|
+
process.env["CONTENTFUL_MANAGEMENT_TOKEN"] ? "CONTENTFUL_MANAGEMENT_TOKEN" : null,
|
|
36415
|
+
process.env["EDS_HOST"] ? "EDS_HOST" : null
|
|
36416
|
+
].filter((v) => !!v);
|
|
36417
|
+
if (envShadowing.length > 0) {
|
|
36418
|
+
warn(
|
|
36419
|
+
`Env vars set: ${envShadowing.join(", ")}. Values saved here take precedence; env vars only apply where disk is empty.`
|
|
36420
|
+
);
|
|
36421
|
+
info("");
|
|
36422
|
+
}
|
|
36423
|
+
const stored = await readExperiencesCredentials();
|
|
36424
|
+
const currentSpace = stored.spaceId;
|
|
36425
|
+
const currentEnv = stored.environmentId;
|
|
36426
|
+
const currentToken = stored.cmaToken;
|
|
36427
|
+
const storedHost = stored.host;
|
|
36428
|
+
const currentHost = storedHost ?? DEFAULT_CONFIGURED_HOST;
|
|
36429
|
+
const hasAny = !!(currentSpace || currentEnv || currentToken);
|
|
36430
|
+
if (hasAny) {
|
|
36431
|
+
info("Current values:");
|
|
36432
|
+
if (currentSpace) {
|
|
36433
|
+
ok(`Space ID ${currentSpace}`);
|
|
36434
|
+
} else {
|
|
36435
|
+
warn("Space ID (not set)");
|
|
36436
|
+
}
|
|
36437
|
+
if (currentEnv) {
|
|
36438
|
+
ok(`Environment ID ${currentEnv}`);
|
|
36439
|
+
} else {
|
|
36440
|
+
warn("Environment ID (not set)");
|
|
36441
|
+
}
|
|
36442
|
+
if (currentToken) {
|
|
36443
|
+
ok(`CMA Token ${"\u2022".repeat(Math.min(currentToken.length, 8))}...`);
|
|
36444
|
+
} else {
|
|
36445
|
+
warn("CMA Token (not set)");
|
|
36446
|
+
}
|
|
36447
|
+
ok(`API Host ${currentHost}`);
|
|
36448
|
+
info("");
|
|
36449
|
+
}
|
|
36450
|
+
const allSet = !!(currentSpace && currentEnv && currentToken);
|
|
36451
|
+
const doUpdate = await confirm(hasAny ? "Update credentials?" : "Configure Contentful credentials?", !allSet);
|
|
36452
|
+
if (!doUpdate) {
|
|
36453
|
+
if (allSet) {
|
|
36454
|
+
ok("Credentials already configured \u2014 no changes made");
|
|
36455
|
+
} else {
|
|
36456
|
+
warn("Skipped. experiences import will prompt for credentials interactively.");
|
|
36457
|
+
}
|
|
36458
|
+
return true;
|
|
36459
|
+
}
|
|
36460
|
+
info("");
|
|
36461
|
+
info("Get your CMA token: Contentful web app \u2192 Settings \u2192 API keys \u2192 Content management tokens");
|
|
36462
|
+
info("");
|
|
36463
|
+
const spaceIdInput = await prompt(` Space ID${currentSpace ? ` [${currentSpace}]` : ""}: `);
|
|
36464
|
+
const spaceId = spaceIdInput || currentSpace;
|
|
36465
|
+
const envIdInput = await prompt(` Environment ID [${currentEnv || "master"}]: `);
|
|
36466
|
+
const environmentId = envIdInput || currentEnv || "master";
|
|
36467
|
+
const tokenInput = await promptSecret(
|
|
36468
|
+
` CMA token${currentToken ? " [press Enter to keep existing]" : " (paste here)"}: `
|
|
36469
|
+
);
|
|
36470
|
+
const cmaToken = tokenInput || currentToken;
|
|
36471
|
+
if (!cmaToken || !spaceId) {
|
|
36472
|
+
warn("Space ID and CMA token are required. Skipped.");
|
|
36473
|
+
return false;
|
|
36474
|
+
}
|
|
36475
|
+
const hostInput = await prompt(` API host [${currentHost}]: `);
|
|
36476
|
+
const host = toConfiguredHost(hostInput) ?? storedHost;
|
|
36477
|
+
const existing = await readExperiencesCredentials();
|
|
36478
|
+
await writeExperiencesCredentials({ ...existing, spaceId, environmentId, cmaToken, ...host ? { host } : {} });
|
|
36479
|
+
ok(`Credentials saved to ${experiencesCredentialsPath()}`);
|
|
36480
|
+
ok(`API host set to ${host ?? DEFAULT_CONFIGURED_HOST}`);
|
|
36481
|
+
info("Run experiences import \u2014 credentials will be pre-filled automatically.");
|
|
36482
|
+
return true;
|
|
36483
|
+
}
|
|
36484
|
+
async function promptCustomSkillPath(kind, current, ask = prompt) {
|
|
36485
|
+
const flagName = kind === "select" ? "--select-prompt-path" : "--generate-prompt-path";
|
|
36486
|
+
void flagName;
|
|
36487
|
+
const label = kind === "select" ? "select (analyze select-agent)" : "generate (generate components)";
|
|
36488
|
+
const currentLabel = current ? ` [${current}]` : " [none]";
|
|
36489
|
+
const answer = await ask(` Custom ${label} prompt path${currentLabel} (empty=keep, "-"=clear): `);
|
|
36490
|
+
const trimmed = answer.trim();
|
|
36491
|
+
if (trimmed === "") return void 0;
|
|
36492
|
+
if (trimmed === "-") return null;
|
|
36493
|
+
return trimmed;
|
|
36494
|
+
}
|
|
36495
|
+
async function setupQoL(profilePath) {
|
|
36496
|
+
section("Step 6: Optional extras", "[optional]");
|
|
36497
|
+
info("These are not required for experiences import but improve the experience.");
|
|
36498
|
+
info("");
|
|
36499
|
+
const existingCreds = await readExperiencesCredentials();
|
|
36500
|
+
info("AI auto-filter \u2014 runs an agent pass before the manual scope-gate to prefilter components.");
|
|
36501
|
+
info("Operators who prefer to review every component can default this OFF and override per run with --auto-filter.");
|
|
36502
|
+
const autoFilter = await promptAutoFilterPreference((q) => prompt(q), existingCreds.autoFilter);
|
|
36503
|
+
if (autoFilter !== (existingCreds.autoFilter ?? true)) {
|
|
36504
|
+
await writeExperiencesCredentials({ ...existingCreds, autoFilter });
|
|
36505
|
+
ok(`AI auto-filter default set to ${autoFilter ? "ON" : "OFF"}`);
|
|
36506
|
+
} else {
|
|
36507
|
+
dim(" unchanged");
|
|
36508
|
+
}
|
|
36509
|
+
info("");
|
|
36510
|
+
const hasConcurrency = await profileContains(profilePath, "EDS_EXTRACT_CONCURRENCY");
|
|
36511
|
+
if (!hasConcurrency) {
|
|
36512
|
+
info("EDS_EXTRACT_CONCURRENCY \u2014 controls how many components are analyzed in parallel.");
|
|
36513
|
+
info("Default is 4. Set higher (e.g. 8) on fast machines to speed up large codebases.");
|
|
36514
|
+
const setConcurrency = await confirm("Add EDS_EXTRACT_CONCURRENCY=8 to your profile?", false);
|
|
36515
|
+
if (setConcurrency) {
|
|
36516
|
+
await appendToProfile(profilePath, "# experiences performance\nexport EDS_EXTRACT_CONCURRENCY=8");
|
|
36517
|
+
ok(`EDS_EXTRACT_CONCURRENCY=8 written to ${profilePath}`);
|
|
36518
|
+
} else {
|
|
36519
|
+
dim(" skipped");
|
|
36520
|
+
}
|
|
36521
|
+
} else {
|
|
36522
|
+
ok("EDS_EXTRACT_CONCURRENCY \u2014 already set");
|
|
36523
|
+
}
|
|
36524
|
+
info("");
|
|
36525
|
+
info("Custom skill prompt paths \u2014 point select-agent and/or generate components at your own .md prompts.");
|
|
36526
|
+
info("When set, the bundled invariants (utility-wrapper rejection, description rules) do NOT apply.");
|
|
36527
|
+
const offerCustomPrompts = await confirm("Configure custom skill prompt paths?", false);
|
|
36528
|
+
if (offerCustomPrompts) {
|
|
36529
|
+
const stored = await readExperiencesCredentials();
|
|
36530
|
+
const selectAnswer = await promptCustomSkillPath("select", stored.selectPromptPath);
|
|
36531
|
+
const generateAnswer = await promptCustomSkillPath("generate", stored.generatePromptPath);
|
|
36532
|
+
const updated = { ...stored };
|
|
36533
|
+
if (selectAnswer === null) delete updated.selectPromptPath;
|
|
36534
|
+
else if (selectAnswer !== void 0) updated.selectPromptPath = selectAnswer;
|
|
36535
|
+
if (generateAnswer === null) delete updated.generatePromptPath;
|
|
36536
|
+
else if (generateAnswer !== void 0) updated.generatePromptPath = generateAnswer;
|
|
36537
|
+
await writeExperiencesCredentials(updated);
|
|
36538
|
+
ok(`Custom prompt paths saved to ${experiencesCredentialsPath()}`);
|
|
36539
|
+
} else {
|
|
36540
|
+
dim(" skipped");
|
|
36541
|
+
}
|
|
36542
|
+
info("");
|
|
36543
|
+
info("Debug logging \u2014 writes a JSONL trace of every command decision (agent calls, tool calls,");
|
|
36544
|
+
info("apply actions, filter decisions, etc.) to ~/.contentful/experience-design-system-cli/debug/.");
|
|
36545
|
+
info("Useful for developers debugging the CLI; OFF by default because traces are verbose.");
|
|
36546
|
+
const debugCreds = await readExperiencesCredentials();
|
|
36547
|
+
const debugChoice = await promptDebugModePreference((q) => prompt(q), debugCreds.debug);
|
|
36548
|
+
if (debugChoice !== (debugCreds.debug ?? false)) {
|
|
36549
|
+
await writeExperiencesCredentials({ ...debugCreds, debug: debugChoice });
|
|
36550
|
+
ok(`Debug logging default set to ${debugChoice ? "ON" : "OFF"}`);
|
|
36551
|
+
} else {
|
|
36552
|
+
dim(" unchanged");
|
|
36553
|
+
}
|
|
36554
|
+
info("");
|
|
36555
|
+
info("");
|
|
36556
|
+
info("Anonymous usage analytics \u2014 helps us see which commands are used and where imports");
|
|
36557
|
+
info("succeed or fail. Never includes source code, file paths, credentials, or authored content.");
|
|
36558
|
+
info("Disabling here persists the opt-out; it will not silently re-enable later. See README > Usage data.");
|
|
36559
|
+
const analyticsCreds = await readExperiencesCredentials();
|
|
36560
|
+
const analyticsDisabled = await promptAnalyticsPreference((q) => prompt(q), analyticsCreds.analyticsDisabled);
|
|
36561
|
+
if (analyticsDisabled !== (analyticsCreds.analyticsDisabled ?? false)) {
|
|
36562
|
+
await writeExperiencesCredentials({ ...analyticsCreds, analyticsDisabled });
|
|
36563
|
+
ok(`Analytics ${analyticsDisabled ? "disabled" : "enabled"}`);
|
|
36564
|
+
} else {
|
|
36565
|
+
dim(" unchanged");
|
|
36566
|
+
}
|
|
36567
|
+
info("");
|
|
36568
|
+
info("");
|
|
36569
|
+
info("NO_COLOR \u2014 set to 1 to disable ANSI color output (useful in CI or plain terminals).");
|
|
36570
|
+
const setNoColor = await confirm("Add NO_COLOR=1 (disable colors) to your profile?", false);
|
|
36571
|
+
if (setNoColor) {
|
|
36572
|
+
const hasNoColor = await profileContains(profilePath, "NO_COLOR");
|
|
36573
|
+
if (!hasNoColor) {
|
|
36574
|
+
await appendToProfile(profilePath, "export NO_COLOR=1");
|
|
36575
|
+
ok(`NO_COLOR=1 written to ${profilePath}`);
|
|
36576
|
+
} else {
|
|
36577
|
+
warn("NO_COLOR already present in profile \u2014 skipping");
|
|
36578
|
+
}
|
|
36579
|
+
} else {
|
|
36580
|
+
dim(" skipped");
|
|
36581
|
+
}
|
|
36582
|
+
}
|
|
36583
|
+
async function checkNode() {
|
|
36584
|
+
section("Checking Node.js version");
|
|
36585
|
+
const current = process.versions.node;
|
|
36586
|
+
const major = parseInt(current.split(".")[0], 10);
|
|
36587
|
+
if (major < REQUIRED_NODE_MAJOR) {
|
|
36588
|
+
fail(`Node.js v${current} \u2014 need v${REQUIRED_NODE_MAJOR}+`);
|
|
36589
|
+
info("");
|
|
36590
|
+
info("How to fix:");
|
|
36591
|
+
if (await binaryExists("nvm")) {
|
|
36592
|
+
info(` nvm install ${REQUIRED_NODE_MAJOR}`);
|
|
36593
|
+
info(` nvm use ${REQUIRED_NODE_MAJOR}`);
|
|
36594
|
+
info(` nvm alias default ${REQUIRED_NODE_MAJOR} # make it permanent`);
|
|
36595
|
+
} else if (await binaryExists("fnm")) {
|
|
36596
|
+
info(` fnm install ${REQUIRED_NODE_MAJOR}`);
|
|
36597
|
+
info(` fnm use ${REQUIRED_NODE_MAJOR}`);
|
|
36598
|
+
} else {
|
|
36599
|
+
info(` Download Node v${REQUIRED_NODE_MAJOR} from https://nodejs.org`);
|
|
36600
|
+
}
|
|
36601
|
+
return false;
|
|
36602
|
+
}
|
|
36603
|
+
ok(`Node.js v${current}`);
|
|
36604
|
+
return true;
|
|
36605
|
+
}
|
|
36606
|
+
async function checkPnpm(pkgRoot) {
|
|
37115
36607
|
section("Checking pnpm");
|
|
37116
|
-
|
|
37117
|
-
if (check.status === "missing") {
|
|
36608
|
+
if (!await binaryExists("pnpm")) {
|
|
37118
36609
|
fail("pnpm not found");
|
|
37119
36610
|
info("How to fix:");
|
|
37120
36611
|
info(" npm install -g pnpm");
|
|
37121
36612
|
info(" # or: corepack enable pnpm");
|
|
37122
36613
|
return false;
|
|
37123
36614
|
}
|
|
37124
|
-
|
|
36615
|
+
const versionResult = await runSpawn("pnpm", ["--version"]);
|
|
36616
|
+
if (versionResult.exitCode !== 0) {
|
|
37125
36617
|
fail("pnpm found but not working");
|
|
37126
36618
|
info("Try reinstalling: npm install -g pnpm --force");
|
|
37127
36619
|
return false;
|
|
37128
36620
|
}
|
|
37129
|
-
ok(`pnpm v${
|
|
37130
|
-
|
|
36621
|
+
ok(`pnpm v${versionResult.stdout.trim()}`);
|
|
36622
|
+
const pingResult = await runSpawn("pnpm", ["exec", "node", "--version"], { cwd: pkgRoot });
|
|
36623
|
+
if (pingResult.exitCode !== 0) {
|
|
37131
36624
|
fail("pnpm cannot execute in repo root");
|
|
37132
36625
|
info("The pnpm global store may be mismatched with your current Node version.");
|
|
37133
36626
|
info("How to fix:");
|
|
@@ -37136,18 +36629,21 @@ async function reportPnpm(pkgRoot) {
|
|
|
37136
36629
|
}
|
|
37137
36630
|
return true;
|
|
37138
36631
|
}
|
|
37139
|
-
async function
|
|
36632
|
+
async function checkDependencies(pkgRoot) {
|
|
37140
36633
|
section("Checking dependencies (pnpm install)");
|
|
37141
|
-
|
|
36634
|
+
const nodeModulesExists = await access10(join26(pkgRoot, "node_modules")).then(() => true).catch(() => false);
|
|
36635
|
+
if (!nodeModulesExists) {
|
|
37142
36636
|
info("node_modules not found \u2014 running pnpm install...");
|
|
37143
36637
|
} else {
|
|
37144
36638
|
info("Running pnpm install to ensure dependencies are up to date...");
|
|
37145
36639
|
}
|
|
37146
|
-
const
|
|
37147
|
-
|
|
36640
|
+
const repoRoot = join26(pkgRoot, "..", "..");
|
|
36641
|
+
const result = await runSpawn("pnpm", ["install", "--frozen-lockfile"], { cwd: repoRoot });
|
|
36642
|
+
if (result.exitCode !== 0) {
|
|
37148
36643
|
fail("pnpm install failed");
|
|
37149
36644
|
info("");
|
|
37150
|
-
|
|
36645
|
+
const errLines = result.stderr.trim().split("\n").slice(0, 10);
|
|
36646
|
+
for (const line of errLines) info(line);
|
|
37151
36647
|
info("");
|
|
37152
36648
|
info("How to fix:");
|
|
37153
36649
|
info(" \u2022 Try: pnpm install (without --frozen-lockfile) to update the lockfile");
|
|
@@ -37157,14 +36653,18 @@ async function reportDependencies(pkgRoot) {
|
|
|
37157
36653
|
ok("Dependencies installed");
|
|
37158
36654
|
return true;
|
|
37159
36655
|
}
|
|
37160
|
-
async function
|
|
36656
|
+
async function checkBuild(pkgRoot) {
|
|
37161
36657
|
section("Building CLI");
|
|
37162
36658
|
info("Running pnpm build...");
|
|
37163
|
-
const
|
|
37164
|
-
|
|
36659
|
+
const repoRoot = join26(pkgRoot, "..", "..");
|
|
36660
|
+
const result = await runSpawn("pnpm", ["--filter", "@contentful/experience-design-system-cli", "run", "build"], {
|
|
36661
|
+
cwd: repoRoot
|
|
36662
|
+
});
|
|
36663
|
+
if (result.exitCode !== 0) {
|
|
37165
36664
|
fail("Build failed");
|
|
37166
36665
|
info("");
|
|
37167
|
-
|
|
36666
|
+
const errLines = result.stderr.trim().split("\n").slice(0, 15);
|
|
36667
|
+
for (const line of errLines) info(line);
|
|
37168
36668
|
info("");
|
|
37169
36669
|
info("How to fix:");
|
|
37170
36670
|
info(" \u2022 Check for TypeScript errors: pnpm typecheck");
|
|
@@ -37174,22 +36674,25 @@ async function reportBuild(pkgRoot) {
|
|
|
37174
36674
|
ok("Build succeeded");
|
|
37175
36675
|
return true;
|
|
37176
36676
|
}
|
|
37177
|
-
async function
|
|
36677
|
+
async function checkAgent() {
|
|
37178
36678
|
section("Checking coding agent");
|
|
36679
|
+
const agents = AGENT_DEFS;
|
|
37179
36680
|
const creds = await readExperiencesCredentials();
|
|
37180
36681
|
const savedAgent = creds.agent;
|
|
37181
36682
|
const savedModel = creds.agentModel;
|
|
37182
36683
|
if (savedAgent) {
|
|
37183
|
-
|
|
36684
|
+
const found = await binaryExists(savedAgent);
|
|
36685
|
+
if (found) {
|
|
37184
36686
|
const modelStr = savedModel ? ` \u2014 model: ${savedModel}` : "";
|
|
37185
36687
|
ok(`${savedAgent}${modelStr} (saved preference)`);
|
|
37186
36688
|
return true;
|
|
36689
|
+
} else {
|
|
36690
|
+
warn(`Saved agent '${savedAgent}' not found on PATH`);
|
|
36691
|
+
info(`Re-run experiences setup to reconfigure.`);
|
|
36692
|
+
return false;
|
|
37187
36693
|
}
|
|
37188
|
-
warn(`Saved agent '${savedAgent}' not found on PATH`);
|
|
37189
|
-
info(`Re-run experiences setup to reconfigure.`);
|
|
37190
|
-
return false;
|
|
37191
36694
|
}
|
|
37192
|
-
for (const agent of
|
|
36695
|
+
for (const agent of agents) {
|
|
37193
36696
|
if (await binaryExists(agent.binary)) {
|
|
37194
36697
|
ok(`${agent.name} (${agent.binary}) found`);
|
|
37195
36698
|
info("Tip: run experiences setup to save a default agent and model.");
|
|
@@ -37204,147 +36707,152 @@ async function reportAgent() {
|
|
|
37204
36707
|
info(" \u2022 OpenCode: npm install -g opencode-ai");
|
|
37205
36708
|
return false;
|
|
37206
36709
|
}
|
|
37207
|
-
|
|
37208
|
-
|
|
37209
|
-
|
|
37210
|
-
|
|
37211
|
-
|
|
37212
|
-
|
|
37213
|
-
|
|
37214
|
-
|
|
37215
|
-
|
|
37216
|
-
|
|
37217
|
-
|
|
37218
|
-
|
|
37219
|
-
|
|
37220
|
-
|
|
37221
|
-
|
|
37222
|
-
|
|
37223
|
-
|
|
37224
|
-
|
|
36710
|
+
function registerSetupCommand(program) {
|
|
36711
|
+
program.command("doctor").description("Check prerequisites so experiences import runs without errors").option("--skip-build", "Skip the pnpm install + build step (useful if already built)").option("--skip-agent", "Skip the coding agent check").action(async (opts) => {
|
|
36712
|
+
process.stderr.write("\x1B[1mexperiences doctor\x1B[0m \u2014 checking your environment\n");
|
|
36713
|
+
const pkgRoot = findPkgRoot();
|
|
36714
|
+
const results = [];
|
|
36715
|
+
const nodeOk = await checkNode();
|
|
36716
|
+
results.push({ name: "Node.js version", ok: nodeOk, required: true });
|
|
36717
|
+
if (nodeOk) {
|
|
36718
|
+
const pnpmOk = await checkPnpm(pkgRoot);
|
|
36719
|
+
results.push({ name: "pnpm", ok: pnpmOk, required: true });
|
|
36720
|
+
if (!opts.skipBuild) {
|
|
36721
|
+
if (pnpmOk) {
|
|
36722
|
+
const depsOk = await checkDependencies(pkgRoot);
|
|
36723
|
+
results.push({ name: "dependencies", ok: depsOk, required: true });
|
|
36724
|
+
if (depsOk) {
|
|
36725
|
+
const buildOk = await checkBuild(pkgRoot);
|
|
36726
|
+
results.push({ name: "build", ok: buildOk, required: true });
|
|
36727
|
+
}
|
|
37225
36728
|
}
|
|
36729
|
+
} else {
|
|
36730
|
+
info("\nSkipping install + build (--skip-build)");
|
|
37226
36731
|
}
|
|
36732
|
+
}
|
|
36733
|
+
if (!opts.skipAgent) {
|
|
36734
|
+
const agentOk = await checkAgent();
|
|
36735
|
+
results.push({ name: "coding agent", ok: agentOk, required: false });
|
|
36736
|
+
}
|
|
36737
|
+
section("Summary");
|
|
36738
|
+
const failed = results.filter((r) => !r.ok);
|
|
36739
|
+
const requiredFailed = failed.filter((r) => r.required);
|
|
36740
|
+
for (const r of results) {
|
|
36741
|
+
if (r.ok) {
|
|
36742
|
+
ok(r.name);
|
|
36743
|
+
} else if (r.required) {
|
|
36744
|
+
fail(`${r.name} \u2014 required`);
|
|
36745
|
+
} else {
|
|
36746
|
+
warn(`${r.name} \u2014 optional`);
|
|
36747
|
+
}
|
|
36748
|
+
}
|
|
36749
|
+
if (requiredFailed.length === 0 && failed.length === 0) {
|
|
36750
|
+
process.stderr.write(
|
|
36751
|
+
"\n\x1B[32m\x1B[1m\u2713 All checks passed. You are ready to run: experiences import\x1B[0m\n\n"
|
|
36752
|
+
);
|
|
36753
|
+
process.exit(0);
|
|
36754
|
+
} else if (requiredFailed.length === 0) {
|
|
36755
|
+
process.stderr.write("\n\x1B[33m\x1B[1m\u26A0 Required checks passed, but optional checks failed.\x1B[0m\n");
|
|
36756
|
+
process.stderr.write(
|
|
36757
|
+
" You can run \x1B[1mexperiences import\x1B[0m but the generate steps may fail without a coding agent.\n\n"
|
|
36758
|
+
);
|
|
36759
|
+
process.exit(0);
|
|
37227
36760
|
} else {
|
|
37228
|
-
|
|
37229
|
-
|
|
37230
|
-
}
|
|
37231
|
-
if (!opts.skipAgent) {
|
|
37232
|
-
const agentOk = await reportAgent();
|
|
37233
|
-
results.push({ name: "coding agent", ok: agentOk, required: false });
|
|
37234
|
-
}
|
|
37235
|
-
section("Summary");
|
|
37236
|
-
const failed = results.filter((r) => !r.ok);
|
|
37237
|
-
const requiredFailed = failed.filter((r) => r.required);
|
|
37238
|
-
for (const r of results) {
|
|
37239
|
-
if (r.ok) ok(r.name);
|
|
37240
|
-
else if (r.required) fail(`${r.name} \u2014 required`);
|
|
37241
|
-
else warn(`${r.name} \u2014 optional`);
|
|
37242
|
-
}
|
|
37243
|
-
if (requiredFailed.length === 0 && failed.length === 0) {
|
|
37244
|
-
process.stderr.write("\n\x1B[32m\x1B[1m\u2713 All checks passed. You are ready to run: experiences import\x1B[0m\n\n");
|
|
37245
|
-
process.exit(0);
|
|
37246
|
-
} else if (requiredFailed.length === 0) {
|
|
37247
|
-
process.stderr.write("\n\x1B[33m\x1B[1m\u26A0 Required checks passed, but optional checks failed.\x1B[0m\n");
|
|
37248
|
-
process.stderr.write(
|
|
37249
|
-
" You can run \x1B[1mexperiences import\x1B[0m but the generate steps may fail without a coding agent.\n\n"
|
|
37250
|
-
);
|
|
37251
|
-
process.exit(0);
|
|
37252
|
-
} else {
|
|
37253
|
-
process.stderr.write(
|
|
37254
|
-
`
|
|
36761
|
+
process.stderr.write(
|
|
36762
|
+
`
|
|
37255
36763
|
\x1B[31m\x1B[1m\u2717 ${requiredFailed.length} required check${requiredFailed.length === 1 ? "" : "s"} failed.\x1B[0m
|
|
37256
36764
|
`
|
|
37257
|
-
|
|
37258
|
-
|
|
37259
|
-
|
|
37260
|
-
|
|
37261
|
-
}
|
|
37262
|
-
|
|
37263
|
-
|
|
37264
|
-
|
|
37265
|
-
|
|
37266
|
-
|
|
37267
|
-
|
|
37268
|
-
|
|
37269
|
-
|
|
37270
|
-
|
|
37271
|
-
|
|
37272
|
-
|
|
37273
|
-
|
|
37274
|
-
|
|
37275
|
-
|
|
37276
|
-
|
|
37277
|
-
|
|
37278
|
-
|
|
37279
|
-
}
|
|
37280
|
-
|
|
37281
|
-
|
|
37282
|
-
|
|
37283
|
-
|
|
37284
|
-
|
|
37285
|
-
|
|
37286
|
-
|
|
37287
|
-
|
|
37288
|
-
|
|
37289
|
-
|
|
37290
|
-
|
|
37291
|
-
|
|
37292
|
-
|
|
37293
|
-
|
|
37294
|
-
}
|
|
37295
|
-
|
|
37296
|
-
|
|
37297
|
-
process.stderr.write(`${SETUP_REQUIRES_TTY_MESSAGE}
|
|
37298
|
-
`);
|
|
37299
|
-
process.exit(1);
|
|
37300
|
-
return;
|
|
37301
|
-
}
|
|
37302
|
-
const { render: render7 } = await import("ink");
|
|
37303
|
-
const { createElement: createElement7 } = await import("react");
|
|
37304
|
-
const { SetupScreen: SetupScreen2 } = await Promise.resolve().then(() => (init_SetupScreen(), SetupScreen_exports));
|
|
37305
|
-
const repoRoot = join29(findPkgRoot(), "..", "..");
|
|
37306
|
-
const profilePath = await detectShellProfile();
|
|
37307
|
-
const completion = { outcome: null };
|
|
37308
|
-
let unmountInk = null;
|
|
37309
|
-
const { waitUntilExit, unmount } = render7(
|
|
37310
|
-
createElement7(SetupScreen2, {
|
|
37311
|
-
version: getCliVersion(),
|
|
37312
|
-
repoRoot,
|
|
37313
|
-
profilePath,
|
|
37314
|
-
dependencies: createSetupScreenDependencies(),
|
|
37315
|
-
skip: {
|
|
37316
|
-
...opts.skipBuild !== void 0 ? { skipBuild: opts.skipBuild } : {},
|
|
37317
|
-
...opts.skipAgent !== void 0 ? { skipAgent: opts.skipAgent } : {},
|
|
37318
|
-
...opts.skipCredentials !== void 0 ? { skipCredentials: opts.skipCredentials } : {},
|
|
37319
|
-
...opts.skipOptional !== void 0 ? { skipOptional: opts.skipOptional } : {}
|
|
37320
|
-
},
|
|
37321
|
-
offerDoctor: true,
|
|
37322
|
-
onComplete: (result) => {
|
|
37323
|
-
completion.outcome = result;
|
|
37324
|
-
unmountInk?.();
|
|
36765
|
+
);
|
|
36766
|
+
process.stderr.write(" Fix the issues above, then re-run \x1B[1mexperiences doctor\x1B[0m.\n\n");
|
|
36767
|
+
process.exit(1);
|
|
36768
|
+
}
|
|
36769
|
+
});
|
|
36770
|
+
program.command("setup").description("Interactive setup wizard: installs prerequisites and configures credentials for experiences import").option("--skip-build", "Skip the pnpm install + build step").option("--skip-agent", "Skip the coding agent check").option("--skip-credentials", "Skip the Contentful credentials step").option("--skip-optional", "Skip optional quality-of-life extras").action(
|
|
36771
|
+
async (opts) => {
|
|
36772
|
+
process.stdout.write("\n\x1B[1mexperiences setup\x1B[0m \u2014 interactive setup wizard\n");
|
|
36773
|
+
process.stdout.write("Sets up everything you need to run \x1B[1mexperiences import\x1B[0m.\n");
|
|
36774
|
+
const pkgRoot = findPkgRoot();
|
|
36775
|
+
const repoRoot = join26(pkgRoot, "..", "..");
|
|
36776
|
+
const profilePath = await detectShellProfile();
|
|
36777
|
+
const results = [];
|
|
36778
|
+
const nodeOk = await setupNode();
|
|
36779
|
+
results.push({ name: "Node.js 24+", passed: nodeOk, required: true });
|
|
36780
|
+
if (!nodeOk) {
|
|
36781
|
+
process.stdout.write(
|
|
36782
|
+
"\n\x1B[33mNode.js setup requires a shell restart. Re-run experiences setup afterwards.\x1B[0m\n\n"
|
|
36783
|
+
);
|
|
36784
|
+
process.exit(0);
|
|
36785
|
+
}
|
|
36786
|
+
const pnpmOk = await setupPnpm();
|
|
36787
|
+
results.push({ name: "pnpm", passed: pnpmOk, required: true });
|
|
36788
|
+
if (!opts.skipBuild && pnpmOk) {
|
|
36789
|
+
const buildOk = await setupBuild(repoRoot);
|
|
36790
|
+
results.push({ name: "install & build", passed: buildOk, required: true });
|
|
36791
|
+
} else if (opts.skipBuild) {
|
|
36792
|
+
info("\nSkipping install + build (--skip-build)");
|
|
36793
|
+
}
|
|
36794
|
+
if (!opts.skipAgent) {
|
|
36795
|
+
const { agent, agentModel } = await setupAgent();
|
|
36796
|
+
if (agent) {
|
|
36797
|
+
const stored = await readExperiencesCredentials();
|
|
36798
|
+
const { agentModel: _staleModel, ...storedWithoutModel } = stored;
|
|
36799
|
+
await writeExperiencesCredentials({ ...storedWithoutModel, agent, ...agentModel ? { agentModel } : {} });
|
|
36800
|
+
}
|
|
36801
|
+
results.push({ name: "coding agent", passed: !!agent, required: true });
|
|
36802
|
+
} else {
|
|
36803
|
+
info("\nSkipping agent check (--skip-agent)");
|
|
36804
|
+
results.push({ name: "coding agent", passed: true, required: false });
|
|
37325
36805
|
}
|
|
37326
|
-
|
|
36806
|
+
if (!opts.skipCredentials) {
|
|
36807
|
+
const credsOk = await setupContentfulCredentials();
|
|
36808
|
+
results.push({ name: "Contentful credentials", passed: credsOk, required: false });
|
|
36809
|
+
} else {
|
|
36810
|
+
info("\nSkipping credentials (--skip-credentials)");
|
|
36811
|
+
}
|
|
36812
|
+
if (!opts.skipOptional) {
|
|
36813
|
+
await setupQoL(profilePath);
|
|
36814
|
+
}
|
|
36815
|
+
section("Summary");
|
|
36816
|
+
const requiredFailed = results.filter((r) => r.required && !r.passed);
|
|
36817
|
+
const optionalFailed = results.filter((r) => !r.required && !r.passed);
|
|
36818
|
+
for (const r of results) {
|
|
36819
|
+
if (r.passed) {
|
|
36820
|
+
ok(`${r.name}`);
|
|
36821
|
+
} else if (r.required) {
|
|
36822
|
+
fail(`${r.name} \u2014 required`);
|
|
36823
|
+
} else {
|
|
36824
|
+
warn(`${r.name} \u2014 optional`);
|
|
36825
|
+
}
|
|
36826
|
+
}
|
|
36827
|
+
process.stdout.write("\n");
|
|
36828
|
+
if (requiredFailed.length === 0) {
|
|
36829
|
+
process.stdout.write("\x1B[32m\x1B[1m\u2713 Setup complete. You can now run: experiences import\x1B[0m\n");
|
|
36830
|
+
if (optionalFailed.length > 0) {
|
|
36831
|
+
process.stdout.write(" (Some optional steps were skipped \u2014 that's fine.)\n");
|
|
36832
|
+
}
|
|
36833
|
+
} else {
|
|
36834
|
+
process.stdout.write(
|
|
36835
|
+
`\x1B[33m\x1B[1m\u26A0 ${requiredFailed.length} required step${requiredFailed.length === 1 ? "" : "s"} incomplete.\x1B[0m
|
|
36836
|
+
`
|
|
36837
|
+
);
|
|
36838
|
+
process.stdout.write(" Complete the steps above, then re-run \x1B[1mexperiences setup\x1B[0m.\n");
|
|
36839
|
+
}
|
|
36840
|
+
process.stdout.write("\n");
|
|
36841
|
+
const runDoctor = process.stdout.isTTY && await confirm("Run experiences doctor now to verify your environment?", requiredFailed.length === 0);
|
|
36842
|
+
if (runDoctor) {
|
|
36843
|
+
process.stdout.write("\n");
|
|
36844
|
+
const cliBin = process.argv[1] ?? fileURLToPath4(import.meta.url);
|
|
36845
|
+
const doctorResult = await runSpawn(process.execPath, [cliBin, "doctor"], {
|
|
36846
|
+
env: process.env
|
|
36847
|
+
});
|
|
36848
|
+
process.stdout.write(doctorResult.stdout);
|
|
36849
|
+
process.stderr.write(doctorResult.stderr);
|
|
36850
|
+
process.exit(doctorResult.exitCode);
|
|
36851
|
+
}
|
|
36852
|
+
process.stdout.write("\nRun \x1B[1mexperiences doctor\x1B[0m at any time to re-check your environment.\n\n");
|
|
36853
|
+
process.exit(requiredFailed.length === 0 ? 0 : 1);
|
|
36854
|
+
}
|
|
37327
36855
|
);
|
|
37328
|
-
unmountInk = unmount;
|
|
37329
|
-
await waitUntilExit();
|
|
37330
|
-
const finished = completion.outcome;
|
|
37331
|
-
if (!finished) {
|
|
37332
|
-
process.exit(1);
|
|
37333
|
-
return;
|
|
37334
|
-
}
|
|
37335
|
-
if (finished.runDoctor) {
|
|
37336
|
-
const cliBin = process.argv[1] ?? fileURLToPath4(import.meta.url);
|
|
37337
|
-
const doctorResult = await runSpawn(process.execPath, [cliBin, "doctor"], { env: process.env });
|
|
37338
|
-
process.stdout.write(doctorResult.stdout);
|
|
37339
|
-
process.stderr.write(doctorResult.stderr);
|
|
37340
|
-
process.exit(doctorResult.exitCode);
|
|
37341
|
-
return;
|
|
37342
|
-
}
|
|
37343
|
-
process.stdout.write("\nRun \x1B[1mexperiences doctor\x1B[0m at any time to re-check your environment.\n\n");
|
|
37344
|
-
process.exit(finished.exitCode);
|
|
37345
|
-
}
|
|
37346
|
-
function registerSetupCommand(program) {
|
|
37347
|
-
program.command("setup").description("Interactive setup wizard: installs prerequisites and configures credentials for experiences import").option("--skip-build", "Skip the pnpm install + build step").option("--skip-agent", "Skip the coding agent check").option("--skip-credentials", "Skip the Contentful credentials step").option("--skip-optional", "Skip optional quality-of-life extras").action((opts) => runSetup(opts));
|
|
37348
36856
|
}
|
|
37349
36857
|
|
|
37350
36858
|
// packages/experience-design-system-cli/src/runs/ls-command.ts
|
|
@@ -37504,7 +37012,7 @@ async function beginCommand(command, opts) {
|
|
|
37504
37012
|
init_analytics();
|
|
37505
37013
|
init_credentials_store();
|
|
37506
37014
|
init_cli_path();
|
|
37507
|
-
var pkg3 = JSON.parse(
|
|
37015
|
+
var pkg3 = JSON.parse(readFileSync10(join27(findPkgRoot(), "package.json"), "utf8"));
|
|
37508
37016
|
async function runBuild(opts) {
|
|
37509
37017
|
return new Promise((resolvePromise) => {
|
|
37510
37018
|
const child = opts.spawnFn();
|
|
@@ -37560,7 +37068,6 @@ function createProgram() {
|
|
|
37560
37068
|
registerSessionCommand(program);
|
|
37561
37069
|
registerImportCommand(program);
|
|
37562
37070
|
registerImportV2Command(program);
|
|
37563
|
-
registerDoctorCommand(program);
|
|
37564
37071
|
registerSetupCommand(program);
|
|
37565
37072
|
registerRunsCommand(program);
|
|
37566
37073
|
registerBuildCommand(program);
|