@contentful/experience-design-system-cli 2.32.1-dev-build-6b922ec.0 → 2.32.1-dev-build-b7d2d34.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/helpers/build-contentful-management-client.d.ts +7 -0
- package/dist/src/helpers/fetch-and-persist-existing-contentful-entities.d.ts +29 -0
- package/dist/src/helpers/fetch-existing-contentful-entities.d.ts +11 -0
- package/dist/src/helpers/find-nearly-matching-component.d.ts +7 -0
- package/dist/src/helpers/read-existing-contentful-entities-from-session.d.ts +7 -0
- package/dist/src/helpers/summarize-existing-contentful-entities.d.ts +50 -0
- package/dist/src/import/orchestrator.d.ts +0 -1
- package/dist/src/import/tui/WizardApp.d.ts +3 -0
- package/dist/src/index.js +1304 -1537
- package/dist/src/session/cache-keys.d.ts +1 -1
- 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/skills/generate-components.md +27 -0
- package/skills/map-tokens.md +12 -0
- package/skills/select-components.md +11 -0
- 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/helpers/cma-client.d.ts +0 -17
- package/dist/src/helpers/fetch-existing-entities.d.ts +0 -16
- 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,19 +332,19 @@ 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
|
-
return new Promise((
|
|
338
|
+
return new Promise((resolve28) => {
|
|
339
339
|
const bedrockEnv = bedrock ? BEDROCK_ENV_BY_AGENT[agent] : void 0;
|
|
340
340
|
const child = spawn(binary, args, {
|
|
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 {
|
|
@@ -384,25 +384,25 @@ async function runAgent(options) {
|
|
|
384
384
|
stderrLen: stderr.length,
|
|
385
385
|
stderrTail: stderr.slice(-1e3)
|
|
386
386
|
});
|
|
387
|
-
|
|
387
|
+
resolve28(result);
|
|
388
388
|
});
|
|
389
389
|
});
|
|
390
390
|
}
|
|
391
391
|
async function checkAgentAuth(agent) {
|
|
392
392
|
const binary = resolveBinary(agent);
|
|
393
|
-
const binaryExists2 = await new Promise((
|
|
393
|
+
const binaryExists2 = await new Promise((resolve28) => {
|
|
394
394
|
if (binary.startsWith("/")) {
|
|
395
|
-
import("node:fs/promises").then((fs2) => fs2.access(binary).then(() =>
|
|
395
|
+
import("node:fs/promises").then((fs2) => fs2.access(binary).then(() => resolve28(true), () => resolve28(false)));
|
|
396
396
|
return;
|
|
397
397
|
}
|
|
398
398
|
const child = spawn("which", [binary], { stdio: "ignore" });
|
|
399
|
-
child.on("close", (code) =>
|
|
399
|
+
child.on("close", (code) => resolve28(code === 0));
|
|
400
400
|
});
|
|
401
401
|
if (!binaryExists2)
|
|
402
402
|
return "not-found";
|
|
403
403
|
if (agent !== "claude")
|
|
404
404
|
return "ok";
|
|
405
|
-
return new Promise((
|
|
405
|
+
return new Promise((resolve28) => {
|
|
406
406
|
const child = spawn(binary, ["auth", "status", "--json"], {
|
|
407
407
|
stdio: ["ignore", "pipe", "pipe"]
|
|
408
408
|
});
|
|
@@ -412,7 +412,7 @@ async function checkAgentAuth(agent) {
|
|
|
412
412
|
if (!done) {
|
|
413
413
|
done = true;
|
|
414
414
|
child.kill("SIGTERM");
|
|
415
|
-
|
|
415
|
+
resolve28("unauthenticated");
|
|
416
416
|
}
|
|
417
417
|
}, 5e3);
|
|
418
418
|
child.stdout?.on("data", (chunk) => {
|
|
@@ -424,14 +424,14 @@ async function checkAgentAuth(agent) {
|
|
|
424
424
|
done = true;
|
|
425
425
|
clearTimeout(timer);
|
|
426
426
|
if (code !== 0) {
|
|
427
|
-
|
|
427
|
+
resolve28("unauthenticated");
|
|
428
428
|
return;
|
|
429
429
|
}
|
|
430
430
|
try {
|
|
431
431
|
const status = JSON.parse(stdout);
|
|
432
|
-
|
|
432
|
+
resolve28(status.loggedIn ? "ok" : "unauthenticated");
|
|
433
433
|
} catch {
|
|
434
|
-
|
|
434
|
+
resolve28("unauthenticated");
|
|
435
435
|
}
|
|
436
436
|
});
|
|
437
437
|
});
|
|
@@ -624,8 +624,20 @@ function renderTokenCandidateSection(kind, entries) {
|
|
|
624
624
|
${formatTokenCandidateLines(entries)}`;
|
|
625
625
|
}
|
|
626
626
|
function buildPreamble(options) {
|
|
627
|
-
const { skill, rawComponentsInline, rawTokensInline, rawTokensFilename, tokensInline, tokenMapInline, generatedCdf, tokenTree, componentSourceRefs } = options;
|
|
627
|
+
const { skill, rawComponentsInline, rawTokensInline, rawTokensFilename, tokensInline, tokenMapInline, generatedCdf, tokenTree, componentSourceRefs, existingComponentsInline, existingTokensInline } = options;
|
|
628
628
|
const sections = [];
|
|
629
|
+
if (existingComponentsInline) {
|
|
630
|
+
sections.push(`Existing components in the target Contentful space (JSON) \u2014 use for alignment, not as a hard filter:
|
|
631
|
+
\`\`\`json
|
|
632
|
+
${existingComponentsInline}
|
|
633
|
+
\`\`\``);
|
|
634
|
+
}
|
|
635
|
+
if (existingTokensInline) {
|
|
636
|
+
sections.push(`Existing design tokens in the target Contentful space (JSON) \u2014 prefer binding to these paths over inventing new ones:
|
|
637
|
+
\`\`\`json
|
|
638
|
+
${existingTokensInline}
|
|
639
|
+
\`\`\``);
|
|
640
|
+
}
|
|
629
641
|
if (rawComponentsInline) {
|
|
630
642
|
sections.push(`Raw component data (JSON):
|
|
631
643
|
\`\`\`json
|
|
@@ -8775,9 +8787,10 @@ async function hashFile(filePath) {
|
|
|
8775
8787
|
const content = await readFile6(filePath, "utf8");
|
|
8776
8788
|
return hashContent(content);
|
|
8777
8789
|
}
|
|
8778
|
-
async function hashPromptForSkill(skill, agent, model, skillPathOverride) {
|
|
8790
|
+
async function hashPromptForSkill(skill, agent, model, skillPathOverride, extraInputs = []) {
|
|
8779
8791
|
const promptHash = skillPathOverride ? await hashFile(resolve6(skillPathOverride)) : await hashFile(resolveSkillPath(skill));
|
|
8780
|
-
|
|
8792
|
+
const extraSegment = extraInputs.length > 0 ? `|${extraInputs.join("|")}` : "";
|
|
8793
|
+
return hashContent(`${promptHash}|${agent}|${model ?? ""}${extraSegment}`);
|
|
8781
8794
|
}
|
|
8782
8795
|
var init_cache_keys = __esm({
|
|
8783
8796
|
"packages/experience-design-system-cli/src/session/cache-keys.ts"() {
|
|
@@ -12885,7 +12898,7 @@ var init_user_agent = __esm({
|
|
|
12885
12898
|
|
|
12886
12899
|
// packages/experience-design-system-cli/src/apply/api-client.ts
|
|
12887
12900
|
function defaultSleep(delayMs) {
|
|
12888
|
-
return new Promise((
|
|
12901
|
+
return new Promise((resolve28) => setTimeout(resolve28, delayMs));
|
|
12889
12902
|
}
|
|
12890
12903
|
function isTransientStatus(status) {
|
|
12891
12904
|
return status >= 500 && status <= 599;
|
|
@@ -13273,7 +13286,7 @@ ${trimmed}`;
|
|
|
13273
13286
|
const progress = maxAttempts > 1 ? attempt / (maxAttempts - 1) : 0;
|
|
13274
13287
|
const baseDelay = intervalMs + (maxIntervalMs - intervalMs) * progress;
|
|
13275
13288
|
const jitter = Math.random() * baseDelay * 0.15;
|
|
13276
|
-
await new Promise((
|
|
13289
|
+
await new Promise((resolve28) => setTimeout(resolve28, baseDelay + jitter));
|
|
13277
13290
|
}
|
|
13278
13291
|
}
|
|
13279
13292
|
throw new Error(`Operation ${operationId} timed out after ${maxAttempts} attempts`);
|
|
@@ -13370,10 +13383,10 @@ function parseJsonBody(body) {
|
|
|
13370
13383
|
const p = asRecord(parsed);
|
|
13371
13384
|
if (!p) return null;
|
|
13372
13385
|
const details = asRecord(p.details) ?? {};
|
|
13373
|
-
const
|
|
13374
|
-
const codeRaw =
|
|
13375
|
-
const messageRaw =
|
|
13376
|
-
const cycleRaw =
|
|
13386
|
+
const pick2 = (k) => p[k] !== void 0 ? p[k] : details[k];
|
|
13387
|
+
const codeRaw = pick2("code") ?? asRecord(p.sys)?.id;
|
|
13388
|
+
const messageRaw = pick2("message");
|
|
13389
|
+
const cycleRaw = pick2("cycle");
|
|
13377
13390
|
const out = {};
|
|
13378
13391
|
if (typeof codeRaw === "string") out.code = codeRaw;
|
|
13379
13392
|
if (typeof messageRaw === "string") out.message = messageRaw;
|
|
@@ -16565,7 +16578,7 @@ var init_command2 = __esm({
|
|
|
16565
16578
|
});
|
|
16566
16579
|
|
|
16567
16580
|
// packages/experience-design-system-cli/src/import/path-utils.ts
|
|
16568
|
-
import { resolve as
|
|
16581
|
+
import { resolve as resolve21 } from "node:path";
|
|
16569
16582
|
import { homedir as homedir6 } from "node:os";
|
|
16570
16583
|
function expandTilde(input) {
|
|
16571
16584
|
if (input === "~" || input.startsWith("~/") || input.startsWith("~\\")) {
|
|
@@ -16579,7 +16592,7 @@ function normalizePath(input) {
|
|
|
16579
16592
|
p = p.slice(1, -1);
|
|
16580
16593
|
}
|
|
16581
16594
|
p = expandTilde(p);
|
|
16582
|
-
return
|
|
16595
|
+
return resolve21(p);
|
|
16583
16596
|
}
|
|
16584
16597
|
var init_path_utils = __esm({
|
|
16585
16598
|
"packages/experience-design-system-cli/src/import/path-utils.ts"() {
|
|
@@ -16587,9 +16600,74 @@ var init_path_utils = __esm({
|
|
|
16587
16600
|
}
|
|
16588
16601
|
});
|
|
16589
16602
|
|
|
16603
|
+
// packages/experience-design-system-cli/src/helpers/build-contentful-management-client.ts
|
|
16604
|
+
import { createClient as createClient2 } from "contentful-management";
|
|
16605
|
+
function buildContentfulManagementClient(opts) {
|
|
16606
|
+
return createClient2(
|
|
16607
|
+
{
|
|
16608
|
+
accessToken: opts.cmaToken,
|
|
16609
|
+
...opts.host ? { host: toConfiguredHost(opts.host) } : {}
|
|
16610
|
+
},
|
|
16611
|
+
{ type: "plain" }
|
|
16612
|
+
);
|
|
16613
|
+
}
|
|
16614
|
+
var init_build_contentful_management_client = __esm({
|
|
16615
|
+
"packages/experience-design-system-cli/src/helpers/build-contentful-management-client.ts"() {
|
|
16616
|
+
"use strict";
|
|
16617
|
+
init_host_utils();
|
|
16618
|
+
}
|
|
16619
|
+
});
|
|
16620
|
+
|
|
16621
|
+
// packages/experience-design-system-cli/src/helpers/fetch-existing-contentful-entities.ts
|
|
16622
|
+
import { fetchAll } from "contentful-management";
|
|
16623
|
+
async function fetchExistingContentfulEntitiesFromContentful(client2, params) {
|
|
16624
|
+
const scope = { spaceId: params.spaceId, environmentId: params.environmentId, query: {} };
|
|
16625
|
+
const components = await fetchAll(client2.component.getMany, scope);
|
|
16626
|
+
const tokens = await fetchAll(client2.designToken.getMany, scope);
|
|
16627
|
+
return { components, tokens };
|
|
16628
|
+
}
|
|
16629
|
+
var init_fetch_existing_contentful_entities = __esm({
|
|
16630
|
+
"packages/experience-design-system-cli/src/helpers/fetch-existing-contentful-entities.ts"() {
|
|
16631
|
+
"use strict";
|
|
16632
|
+
}
|
|
16633
|
+
});
|
|
16634
|
+
|
|
16635
|
+
// packages/experience-design-system-cli/src/helpers/fetch-and-persist-existing-contentful-entities.ts
|
|
16636
|
+
import { writeFile as writeFile5 } from "node:fs/promises";
|
|
16637
|
+
import { join as join18 } from "node:path";
|
|
16638
|
+
async function fetchAndPersistExistingContentfulEntities(params) {
|
|
16639
|
+
const t0 = Date.now();
|
|
16640
|
+
try {
|
|
16641
|
+
const client2 = buildContentfulManagementClient({
|
|
16642
|
+
cmaToken: params.cmaToken,
|
|
16643
|
+
...params.host ? { host: params.host } : {}
|
|
16644
|
+
});
|
|
16645
|
+
const entities = await fetchExistingContentfulEntitiesFromContentful(client2, {
|
|
16646
|
+
spaceId: params.spaceId,
|
|
16647
|
+
environmentId: params.environmentId
|
|
16648
|
+
});
|
|
16649
|
+
const path = join18(params.outDir, ".existing-entities.json");
|
|
16650
|
+
await writeFile5(path, JSON.stringify(entities, null, 2), "utf8");
|
|
16651
|
+
return { ok: true, path, durationMs: Date.now() - t0, entities };
|
|
16652
|
+
} catch (error) {
|
|
16653
|
+
return {
|
|
16654
|
+
ok: false,
|
|
16655
|
+
durationMs: Date.now() - t0,
|
|
16656
|
+
error: error instanceof Error ? error.message : String(error)
|
|
16657
|
+
};
|
|
16658
|
+
}
|
|
16659
|
+
}
|
|
16660
|
+
var init_fetch_and_persist_existing_contentful_entities = __esm({
|
|
16661
|
+
"packages/experience-design-system-cli/src/helpers/fetch-and-persist-existing-contentful-entities.ts"() {
|
|
16662
|
+
"use strict";
|
|
16663
|
+
init_build_contentful_management_client();
|
|
16664
|
+
init_fetch_existing_contentful_entities();
|
|
16665
|
+
}
|
|
16666
|
+
});
|
|
16667
|
+
|
|
16590
16668
|
// packages/experience-design-system-cli/src/runs/save-path-resolver.ts
|
|
16591
16669
|
import { access as access8 } from "node:fs/promises";
|
|
16592
|
-
import { join as
|
|
16670
|
+
import { join as join20 } from "node:path";
|
|
16593
16671
|
function isConflictMode(value) {
|
|
16594
16672
|
return CONFLICT_MODES.includes(value);
|
|
16595
16673
|
}
|
|
@@ -16597,7 +16675,7 @@ async function listConflictingFiles(path) {
|
|
|
16597
16675
|
const conflicts = [];
|
|
16598
16676
|
for (const name of SAVE_FILES) {
|
|
16599
16677
|
try {
|
|
16600
|
-
await access8(
|
|
16678
|
+
await access8(join20(path, name));
|
|
16601
16679
|
conflicts.push(name);
|
|
16602
16680
|
} catch {
|
|
16603
16681
|
}
|
|
@@ -16617,7 +16695,7 @@ function buildTimestampedSubdir(base, now = /* @__PURE__ */ new Date()) {
|
|
|
16617
16695
|
const hh = pad2(now.getHours());
|
|
16618
16696
|
const mm = pad2(now.getMinutes());
|
|
16619
16697
|
const ss = pad2(now.getSeconds());
|
|
16620
|
-
return
|
|
16698
|
+
return join20(base, `dsi-${y}${m}${d}-${hh}${mm}${ss}`);
|
|
16621
16699
|
}
|
|
16622
16700
|
async function resolveSavePath(path, options = {}) {
|
|
16623
16701
|
const conflicts = await listConflictingFiles(path);
|
|
@@ -16647,8 +16725,8 @@ var init_save_path_resolver = __esm({
|
|
|
16647
16725
|
});
|
|
16648
16726
|
|
|
16649
16727
|
// packages/experience-design-system-cli/src/runs/store.ts
|
|
16650
|
-
import { readFile as
|
|
16651
|
-
import { join as
|
|
16728
|
+
import { readFile as readFile23, writeFile as writeFile6, mkdir as mkdir6, rename } from "node:fs/promises";
|
|
16729
|
+
import { join as join21 } from "node:path";
|
|
16652
16730
|
import { homedir as homedir7 } from "node:os";
|
|
16653
16731
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
16654
16732
|
function runsFilePath() {
|
|
@@ -16691,7 +16769,7 @@ function migrateRecord(rec) {
|
|
|
16691
16769
|
}
|
|
16692
16770
|
async function readFileMaybe() {
|
|
16693
16771
|
try {
|
|
16694
|
-
const raw = await
|
|
16772
|
+
const raw = await readFile23(RUNS_PATH, "utf8");
|
|
16695
16773
|
const parsed = JSON.parse(raw);
|
|
16696
16774
|
if (!READABLE_VERSIONS.has(parsed.version)) {
|
|
16697
16775
|
throw new Error(
|
|
@@ -16769,8 +16847,8 @@ var init_store = __esm({
|
|
|
16769
16847
|
RUNS_FILE_VERSION = 3;
|
|
16770
16848
|
RUNS_FILE_CAP = 200;
|
|
16771
16849
|
READABLE_VERSIONS = /* @__PURE__ */ new Set([1, 2, 3]);
|
|
16772
|
-
RUNS_DIR =
|
|
16773
|
-
RUNS_PATH =
|
|
16850
|
+
RUNS_DIR = join21(homedir7(), ".config", "experiences");
|
|
16851
|
+
RUNS_PATH = join21(RUNS_DIR, "runs.json");
|
|
16774
16852
|
CROCKFORD = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
16775
16853
|
}
|
|
16776
16854
|
});
|
|
@@ -16834,7 +16912,7 @@ var init_run_teaser = __esm({
|
|
|
16834
16912
|
import { useState as useState9, useEffect as useEffect3 } from "react";
|
|
16835
16913
|
import { Box as Box20, Text as Text20 } from "ink";
|
|
16836
16914
|
import { readdirSync as readdirSync3 } from "node:fs";
|
|
16837
|
-
import { dirname as dirname13, basename as basename6, join as
|
|
16915
|
+
import { dirname as dirname13, basename as basename6, join as join22 } from "node:path";
|
|
16838
16916
|
import { jsx as jsx20, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
16839
16917
|
function autocomplete(partial) {
|
|
16840
16918
|
if (!partial) return null;
|
|
@@ -16849,13 +16927,13 @@ function autocomplete(partial) {
|
|
|
16849
16927
|
}
|
|
16850
16928
|
const matches = entries.filter((e) => e.startsWith(base));
|
|
16851
16929
|
if (matches.length === 0) return null;
|
|
16852
|
-
if (matches.length === 1) return
|
|
16930
|
+
if (matches.length === 1) return join22(dir, matches[0]);
|
|
16853
16931
|
let prefix = matches[0];
|
|
16854
16932
|
for (const m of matches) {
|
|
16855
16933
|
while (!m.startsWith(prefix)) prefix = prefix.slice(0, -1);
|
|
16856
16934
|
if (!prefix) break;
|
|
16857
16935
|
}
|
|
16858
|
-
return prefix.length > base.length ?
|
|
16936
|
+
return prefix.length > base.length ? join22(dir, prefix) : null;
|
|
16859
16937
|
}
|
|
16860
16938
|
function PathPrompt({
|
|
16861
16939
|
defaultPath,
|
|
@@ -17287,8 +17365,8 @@ var init_save_conflict = __esm({
|
|
|
17287
17365
|
|
|
17288
17366
|
// packages/experience-design-system-cli/src/runs/fingerprint.ts
|
|
17289
17367
|
import { createHash as createHash4 } from "node:crypto";
|
|
17290
|
-
import { readFile as
|
|
17291
|
-
import { resolve as
|
|
17368
|
+
import { readFile as readFile24, stat as stat5 } from "node:fs/promises";
|
|
17369
|
+
import { resolve as resolve23 } from "node:path";
|
|
17292
17370
|
function rowField(row, key) {
|
|
17293
17371
|
const v = row[key];
|
|
17294
17372
|
return typeof v === "string" ? v : null;
|
|
@@ -17304,7 +17382,7 @@ async function buildSourceFingerprint(opts) {
|
|
|
17304
17382
|
const sourcePath = rowField(row, "source_path");
|
|
17305
17383
|
const name = rowField(row, "name");
|
|
17306
17384
|
if (!sourcePath) continue;
|
|
17307
|
-
const abs =
|
|
17385
|
+
const abs = resolve23(sourcePath);
|
|
17308
17386
|
if (seen.has(abs)) continue;
|
|
17309
17387
|
seen.add(abs);
|
|
17310
17388
|
try {
|
|
@@ -17319,10 +17397,10 @@ async function buildSourceFingerprint(opts) {
|
|
|
17319
17397
|
let rawTokensMtime = null;
|
|
17320
17398
|
let rawTokensContentHash = null;
|
|
17321
17399
|
if (opts.rawTokensPath) {
|
|
17322
|
-
const abs =
|
|
17400
|
+
const abs = resolve23(opts.rawTokensPath);
|
|
17323
17401
|
rawTokensPath = abs;
|
|
17324
17402
|
try {
|
|
17325
|
-
const [st, buf] = await Promise.all([stat5(abs),
|
|
17403
|
+
const [st, buf] = await Promise.all([stat5(abs), readFile24(abs)]);
|
|
17326
17404
|
rawTokensMtime = st.mtime.toISOString();
|
|
17327
17405
|
rawTokensContentHash = sha256Hex(buf);
|
|
17328
17406
|
} catch {
|
|
@@ -17453,7 +17531,7 @@ var init_WelcomeStep = __esm({
|
|
|
17453
17531
|
import { useState as useState13, useEffect as useEffect5 } from "react";
|
|
17454
17532
|
import { Box as Box25, Text as Text25 } from "ink";
|
|
17455
17533
|
import { promises as fs } from "node:fs";
|
|
17456
|
-
import { join as
|
|
17534
|
+
import { join as join23 } from "node:path";
|
|
17457
17535
|
import { jsx as jsx25, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
17458
17536
|
async function countFiles(dir) {
|
|
17459
17537
|
const counts = {
|
|
@@ -17477,7 +17555,7 @@ async function countFiles(dir) {
|
|
|
17477
17555
|
await Promise.all(
|
|
17478
17556
|
entries.map(async (entry) => {
|
|
17479
17557
|
if (IGNORE_DIRS.has(entry)) return;
|
|
17480
|
-
const full =
|
|
17558
|
+
const full = join23(current, entry);
|
|
17481
17559
|
let stat8;
|
|
17482
17560
|
try {
|
|
17483
17561
|
stat8 = await fs.stat(full);
|
|
@@ -17935,8 +18013,11 @@ function CredentialsStep({
|
|
|
17935
18013
|
"\u2713 ",
|
|
17936
18014
|
summary
|
|
17937
18015
|
] }),
|
|
17938
|
-
/* @__PURE__ */
|
|
17939
|
-
|
|
18016
|
+
/* @__PURE__ */ jsxs28(Box28, { flexDirection: "column", marginTop: 1, gap: 0, children: [
|
|
18017
|
+
/* @__PURE__ */ jsx28(Text28, { children: initialSpaceId && initialCmaToken ? "Credentials pre-filled from experiences setup. Press Enter to continue or edit any field to update." : "Enter the Contentful space you want to import into." }),
|
|
18018
|
+
!(initialSpaceId && initialCmaToken) && /* @__PURE__ */ jsx28(Text28, { dimColor: true, children: "These credentials are used both to align agent suggestions with what already exists in the space and to push your import at the end. Press S to skip and run without space context (push will be disabled)." }),
|
|
18019
|
+
!(initialSpaceId && initialCmaToken) && /* @__PURE__ */ jsx28(Text28, { dimColor: true, children: "Tip: run experiences setup to save these to ~/.config/experiences/credentials.json so they pre-fill here automatically." })
|
|
18020
|
+
] }),
|
|
17940
18021
|
/* @__PURE__ */ jsxs28(Box28, { flexDirection: "column", gap: 0, marginTop: 1, children: [
|
|
17941
18022
|
renderField("Space ID", spaceId, "spaceId"),
|
|
17942
18023
|
renderField("Environment", environmentId, "environmentId"),
|
|
@@ -19103,9 +19184,9 @@ function spawnGenerateChild(opts) {
|
|
|
19103
19184
|
stderr += chunk;
|
|
19104
19185
|
opts.onStderr?.(chunk);
|
|
19105
19186
|
});
|
|
19106
|
-
const donePromise = new Promise((
|
|
19187
|
+
const donePromise = new Promise((resolve28) => {
|
|
19107
19188
|
child.on("close", (code, signal) => {
|
|
19108
|
-
|
|
19189
|
+
resolve28({
|
|
19109
19190
|
exitCode: code ?? 0,
|
|
19110
19191
|
signal: signal ?? null,
|
|
19111
19192
|
stdout,
|
|
@@ -19113,7 +19194,7 @@ function spawnGenerateChild(opts) {
|
|
|
19113
19194
|
});
|
|
19114
19195
|
});
|
|
19115
19196
|
child.on("error", (err) => {
|
|
19116
|
-
|
|
19197
|
+
resolve28({
|
|
19117
19198
|
exitCode: 1,
|
|
19118
19199
|
signal: null,
|
|
19119
19200
|
stdout,
|
|
@@ -27656,9 +27737,9 @@ __export(WizardApp_exports, {
|
|
|
27656
27737
|
});
|
|
27657
27738
|
import { useEffect as useEffect15, useRef as useRef9, useState as useState28 } from "react";
|
|
27658
27739
|
import { Box as Box49, Text as Text51, useStdout as useStdout8 } from "ink";
|
|
27659
|
-
import { join as
|
|
27740
|
+
import { join as join24, resolve as resolve24 } from "node:path";
|
|
27660
27741
|
import { appendFileSync as appendFileSync2, writeFileSync } from "node:fs";
|
|
27661
|
-
import { access as access9, readFile as
|
|
27742
|
+
import { access as access9, readFile as readFile25, stat as stat6 } from "node:fs/promises";
|
|
27662
27743
|
import { tmpdir } from "node:os";
|
|
27663
27744
|
import { execFile as execFile4, spawn as spawn4 } from "node:child_process";
|
|
27664
27745
|
import { mkdir as mkdir7 } from "node:fs/promises";
|
|
@@ -27670,6 +27751,7 @@ function buildSelectAgentArgs(opts) {
|
|
|
27670
27751
|
if (opts.bedrock) args.push("--bedrock");
|
|
27671
27752
|
if (opts.selectPromptPath) args.push("--select-prompt-path", opts.selectPromptPath);
|
|
27672
27753
|
if (opts.noCache) args.push("--no-cache");
|
|
27754
|
+
if (opts.existingEntitiesPath) args.push("--existing-entities-path", opts.existingEntitiesPath);
|
|
27673
27755
|
return args;
|
|
27674
27756
|
}
|
|
27675
27757
|
function parseAutoFilterProgressLine(line) {
|
|
@@ -27706,6 +27788,7 @@ function buildGenerateComponentsArgs(opts) {
|
|
|
27706
27788
|
if (opts.bedrock) args.push("--bedrock");
|
|
27707
27789
|
if (opts.noCache) args.push("--no-cache");
|
|
27708
27790
|
if (opts.generatePromptPath) args.push("--generate-prompt-path", opts.generatePromptPath);
|
|
27791
|
+
if (opts.existingEntitiesPath) args.push("--existing-entities-path", opts.existingEntitiesPath);
|
|
27709
27792
|
return args;
|
|
27710
27793
|
}
|
|
27711
27794
|
function buildMapTokensArgs(opts) {
|
|
@@ -27713,6 +27796,7 @@ function buildMapTokensArgs(opts) {
|
|
|
27713
27796
|
if (opts.model) args.push("--model", opts.model);
|
|
27714
27797
|
if (opts.noCache) args.push("--no-cache");
|
|
27715
27798
|
if (opts.skipAgent) args.push("--skip-agent");
|
|
27799
|
+
if (opts.existingEntitiesPath) args.push("--existing-entities-path", opts.existingEntitiesPath);
|
|
27716
27800
|
return args;
|
|
27717
27801
|
}
|
|
27718
27802
|
function shouldRunMapTokens(opts) {
|
|
@@ -27802,8 +27886,8 @@ function WizardApp({
|
|
|
27802
27886
|
const rawTokensEntryReady = !modifyEntryReady && !pushFromPickerReady && !!initialRawTokensPath;
|
|
27803
27887
|
const effectiveNoCache = resolveNoCacheForGenerate({ cliNoCache: noCache });
|
|
27804
27888
|
const initialStepResolved = modifyEntryReady ? "final-review" : pushFromPickerReady ? "push-from-picker" : rawTokensEntryReady ? "generating-tokens" : initialProjectPath ? "token-input" : "welcome";
|
|
27805
|
-
const initialOutDir = initialProjectPath ?
|
|
27806
|
-
const initialTokensPath = (modifyEntryReady || pushFromPickerReady) && initialOutDir && seedTokenSessionId ?
|
|
27889
|
+
const initialOutDir = initialProjectPath ? join24(resolve24(initialProjectPath), ".contentful") : "";
|
|
27890
|
+
const initialTokensPath = (modifyEntryReady || pushFromPickerReady) && initialOutDir && seedTokenSessionId ? join24(initialOutDir, "tokens.json") : "";
|
|
27807
27891
|
const [state, setState] = useState28({
|
|
27808
27892
|
step: modifyEntryReady || rawTokensEntryReady || pushFromPickerReady ? initialStepResolved : initialRuns && initialRuns.length > 0 ? "run-picker" : initialStepResolved,
|
|
27809
27893
|
agent: initialAgent ?? "claude",
|
|
@@ -27856,6 +27940,7 @@ function WizardApp({
|
|
|
27856
27940
|
generatePrefetchError: null,
|
|
27857
27941
|
mapTokensEligible: null,
|
|
27858
27942
|
credentialsSkipped: false,
|
|
27943
|
+
existingEntitiesPath: null,
|
|
27859
27944
|
lastRunId: null,
|
|
27860
27945
|
finalizeErrorBanner: null,
|
|
27861
27946
|
finalReviewPassed: modifyEntryReady || pushFromPickerReady,
|
|
@@ -27970,7 +28055,7 @@ If you are using AWS Bedrock, run:
|
|
|
27970
28055
|
}
|
|
27971
28056
|
const sessionMatch = /^session=(.+)$/m.exec(result.stdout);
|
|
27972
28057
|
const tokenSessionId = sessionMatch ? sessionMatch[1].trim() : null;
|
|
27973
|
-
const tokensPath =
|
|
28058
|
+
const tokensPath = join24(outDir, "tokens.json");
|
|
27974
28059
|
const printArgs = ["print", "tokens", "--out", tokensPath];
|
|
27975
28060
|
if (tokenSessionId) printArgs.push("--session", tokenSessionId);
|
|
27976
28061
|
const r = await runCli2(printArgs);
|
|
@@ -27990,7 +28075,7 @@ If you are using AWS Bedrock, run:
|
|
|
27990
28075
|
tokenCount,
|
|
27991
28076
|
skipComponents: true,
|
|
27992
28077
|
acceptedCount: 0,
|
|
27993
|
-
outDir: state.outDir ||
|
|
28078
|
+
outDir: state.outDir || join24(process.cwd(), ".contentful")
|
|
27994
28079
|
});
|
|
27995
28080
|
if (noPush) {
|
|
27996
28081
|
void startSaveFlow();
|
|
@@ -28042,7 +28127,8 @@ If you are using AWS Bedrock, run:
|
|
|
28042
28127
|
agent: state.agent,
|
|
28043
28128
|
...state.agentModel ? { model: state.agentModel } : {},
|
|
28044
28129
|
noCache: effectiveNoCache,
|
|
28045
|
-
skipAgent: skipMapTokens
|
|
28130
|
+
skipAgent: skipMapTokens,
|
|
28131
|
+
...state.existingEntitiesPath ? { existingEntitiesPath: state.existingEntitiesPath } : {}
|
|
28046
28132
|
});
|
|
28047
28133
|
const result = await runCli2(args);
|
|
28048
28134
|
if (result.exitCode !== 0) {
|
|
@@ -28056,7 +28142,7 @@ If you are using AWS Bedrock, run:
|
|
|
28056
28142
|
return true;
|
|
28057
28143
|
};
|
|
28058
28144
|
const runExtract = async (projectPath) => {
|
|
28059
|
-
const outDir =
|
|
28145
|
+
const outDir = join24(resolve24(projectPath), ".contentful");
|
|
28060
28146
|
update({ step: "extracting", outDir, extractProgress: null, compositionPhase: null });
|
|
28061
28147
|
const r = await new Promise((res) => {
|
|
28062
28148
|
const extractArgs = [findCliPath(), "analyze", "extract", "--project", projectPath];
|
|
@@ -28163,7 +28249,8 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
|
|
|
28163
28249
|
...state.agentModel ? { model: state.agentModel } : {},
|
|
28164
28250
|
...state.bedrock ? { bedrock: true } : {},
|
|
28165
28251
|
selectPromptPath,
|
|
28166
|
-
noCache
|
|
28252
|
+
noCache,
|
|
28253
|
+
...state.existingEntitiesPath ? { existingEntitiesPath: state.existingEntitiesPath } : {}
|
|
28167
28254
|
});
|
|
28168
28255
|
const child = spawn4("node", [findCliPath(), ...args]);
|
|
28169
28256
|
autoFilterChildRef.current = child;
|
|
@@ -28261,7 +28348,8 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
|
|
|
28261
28348
|
agent: state.agent,
|
|
28262
28349
|
...state.agentModel ? { model: state.agentModel } : {},
|
|
28263
28350
|
...state.bedrock ? { bedrock: true } : {},
|
|
28264
|
-
noCache: effectiveNoCache
|
|
28351
|
+
noCache: effectiveNoCache,
|
|
28352
|
+
...state.existingEntitiesPath ? { existingEntitiesPath: state.existingEntitiesPath } : {}
|
|
28265
28353
|
})
|
|
28266
28354
|
];
|
|
28267
28355
|
let progressCursor = null;
|
|
@@ -28332,7 +28420,8 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
|
|
|
28332
28420
|
...state.agentModel ? { model: state.agentModel } : {},
|
|
28333
28421
|
...state.bedrock ? { bedrock: true } : {},
|
|
28334
28422
|
noCache: effectiveNoCache,
|
|
28335
|
-
generatePromptPath
|
|
28423
|
+
generatePromptPath,
|
|
28424
|
+
...state.existingEntitiesPath ? { existingEntitiesPath: state.existingEntitiesPath } : {}
|
|
28336
28425
|
})
|
|
28337
28426
|
];
|
|
28338
28427
|
let progressCursor = state.generateProgress;
|
|
@@ -28372,7 +28461,7 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
|
|
|
28372
28461
|
if (await runMapTokens2(mappedSessionId)) update({ step: "final-review" });
|
|
28373
28462
|
};
|
|
28374
28463
|
const advanceToPushFlow = (generatedAcceptedCount) => {
|
|
28375
|
-
update({ generatedAcceptedCount, step: "
|
|
28464
|
+
update({ generatedAcceptedCount, step: "push-decision-gate" });
|
|
28376
28465
|
};
|
|
28377
28466
|
const runEditFromPreview = async () => {
|
|
28378
28467
|
update({ step: "final-review" });
|
|
@@ -28443,6 +28532,24 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
|
|
|
28443
28532
|
}
|
|
28444
28533
|
};
|
|
28445
28534
|
const advanceAfterCredentialsValidated = async () => {
|
|
28535
|
+
if (!state.credentialsSkipped && state.spaceId && state.environmentId && state.cmaToken && state.projectPath) {
|
|
28536
|
+
const outDir = join24(resolve24(state.projectPath), ".contentful");
|
|
28537
|
+
await mkdir7(outDir, { recursive: true });
|
|
28538
|
+
const result = await fetchAndPersistExistingContentfulEntities({
|
|
28539
|
+
spaceId: state.spaceId,
|
|
28540
|
+
environmentId: state.environmentId,
|
|
28541
|
+
cmaToken: state.cmaToken,
|
|
28542
|
+
...state.host ? { host: state.host } : {},
|
|
28543
|
+
outDir
|
|
28544
|
+
});
|
|
28545
|
+
if (result.ok) {
|
|
28546
|
+
update({ existingEntitiesPath: result.path });
|
|
28547
|
+
}
|
|
28548
|
+
}
|
|
28549
|
+
if (!sessionRef.current.extractSessionId && state.projectPath) {
|
|
28550
|
+
void runExtract(state.projectPath);
|
|
28551
|
+
return;
|
|
28552
|
+
}
|
|
28446
28553
|
if (shouldSkipFinalReviewAfterCredentials(state)) {
|
|
28447
28554
|
update({ step: "push-decision-gate" });
|
|
28448
28555
|
return;
|
|
@@ -28798,7 +28905,7 @@ If using a custom --host, make sure the space exists on that host.`
|
|
|
28798
28905
|
};
|
|
28799
28906
|
const runPrintFiles = async (extractSessionId, outDir, opts = {}) => {
|
|
28800
28907
|
update({ step: "printing" });
|
|
28801
|
-
const componentsPath =
|
|
28908
|
+
const componentsPath = join24(outDir, "components.json");
|
|
28802
28909
|
const printArgs = ["print", "components", "--out", componentsPath];
|
|
28803
28910
|
if (extractSessionId) printArgs.push("--session", extractSessionId);
|
|
28804
28911
|
if (opts.allowEmpty) printArgs.push("--allow-empty");
|
|
@@ -28814,7 +28921,7 @@ If using a custom --host, make sure the space exists on that host.`
|
|
|
28814
28921
|
let emittedTokensPath;
|
|
28815
28922
|
let emittedTokenCount;
|
|
28816
28923
|
if (opts.tokenSessionId) {
|
|
28817
|
-
const tokensOut =
|
|
28924
|
+
const tokensOut = join24(outDir, "tokens.json");
|
|
28818
28925
|
const tokenArgs = ["print", "tokens", "--out", tokensOut, "--session", opts.tokenSessionId];
|
|
28819
28926
|
const tr = await runCli2(tokenArgs);
|
|
28820
28927
|
if (tr.exitCode !== 0) {
|
|
@@ -28901,8 +29008,8 @@ If using a custom --host, make sure the space exists on that host.`
|
|
|
28901
29008
|
);
|
|
28902
29009
|
}
|
|
28903
29010
|
try {
|
|
28904
|
-
const componentsBuf = await
|
|
28905
|
-
const tokensBuf = recordedTokensPath ? await
|
|
29011
|
+
const componentsBuf = await readFile25(join24(path, "components.json")).catch(() => null);
|
|
29012
|
+
const tokensBuf = recordedTokensPath ? await readFile25(recordedTokensPath).catch(() => null) : null;
|
|
28906
29013
|
savedFingerprint = buildSavedFingerprint({
|
|
28907
29014
|
componentsJson: componentsBuf,
|
|
28908
29015
|
tokensJson: tokensBuf
|
|
@@ -28943,7 +29050,7 @@ If using a custom --host, make sure the space exists on that host.`
|
|
|
28943
29050
|
if (state.step === "generating-tokens") {
|
|
28944
29051
|
if (tokenReuseChecked.current) return;
|
|
28945
29052
|
tokenReuseChecked.current = true;
|
|
28946
|
-
const existingTokensPath =
|
|
29053
|
+
const existingTokensPath = join24(state.outDir, "tokens.json");
|
|
28947
29054
|
(async () => {
|
|
28948
29055
|
try {
|
|
28949
29056
|
await access9(existingTokensPath);
|
|
@@ -29019,7 +29126,7 @@ If using a custom --host, make sure the space exists on that host.`
|
|
|
29019
29126
|
{
|
|
29020
29127
|
onContinue: (path) => {
|
|
29021
29128
|
const projectPath = normalizePath(path);
|
|
29022
|
-
const outDir =
|
|
29129
|
+
const outDir = join24(projectPath, ".contentful");
|
|
29023
29130
|
update({ step: "token-input", projectPath, outDir });
|
|
29024
29131
|
},
|
|
29025
29132
|
onQuit: () => process.exit(0)
|
|
@@ -29084,7 +29191,7 @@ If using a custom --host, make sure the space exists on that host.`
|
|
|
29084
29191
|
{
|
|
29085
29192
|
projectPath: state.projectPath,
|
|
29086
29193
|
onConfirm: (path) => {
|
|
29087
|
-
|
|
29194
|
+
update({ projectPath: path, step: "credentials" });
|
|
29088
29195
|
},
|
|
29089
29196
|
onSkipComponents: () => {
|
|
29090
29197
|
if (noPush) {
|
|
@@ -29168,12 +29275,7 @@ If using a custom --host, make sure the space exists on that host.`
|
|
|
29168
29275
|
}
|
|
29169
29276
|
return;
|
|
29170
29277
|
}
|
|
29171
|
-
|
|
29172
|
-
if (await runAgentAuthCheck("credentials")) {
|
|
29173
|
-
startGeneratePrefetch(sid, state.tokensPath);
|
|
29174
|
-
}
|
|
29175
|
-
}
|
|
29176
|
-
update({ step: "credentials" });
|
|
29278
|
+
update({ step: "push-decision-gate" });
|
|
29177
29279
|
},
|
|
29178
29280
|
onAdvanceToPushFlow: (count) => {
|
|
29179
29281
|
update({ acceptedCount: count, autoRejectedCount: 0 });
|
|
@@ -29644,10 +29746,11 @@ var init_WizardApp = __esm({
|
|
|
29644
29746
|
init_path_utils();
|
|
29645
29747
|
init_host_utils();
|
|
29646
29748
|
init_credentials_store();
|
|
29749
|
+
init_fetch_and_persist_existing_contentful_entities();
|
|
29647
29750
|
init_wizard_state_transitions();
|
|
29648
29751
|
init_cycle_auto_reject();
|
|
29649
29752
|
init_cli_path();
|
|
29650
|
-
WIZARD_LOG =
|
|
29753
|
+
WIZARD_LOG = join24(tmpdir(), "experiences-import-wizard.log");
|
|
29651
29754
|
}
|
|
29652
29755
|
});
|
|
29653
29756
|
|
|
@@ -29658,8 +29761,8 @@ __export(staleness_exports, {
|
|
|
29658
29761
|
formatStalenessDetail: () => formatStalenessDetail,
|
|
29659
29762
|
shortStalenessSummary: () => shortStalenessSummary
|
|
29660
29763
|
});
|
|
29661
|
-
import { readFile as
|
|
29662
|
-
import { join as
|
|
29764
|
+
import { readFile as readFile26, stat as stat7 } from "node:fs/promises";
|
|
29765
|
+
import { join as join25 } from "node:path";
|
|
29663
29766
|
async function checkRunStaleness(run) {
|
|
29664
29767
|
if (!run.sourceFingerprint) return { ...UNKNOWN };
|
|
29665
29768
|
const result = {
|
|
@@ -29685,7 +29788,7 @@ async function checkRunStaleness(run) {
|
|
|
29685
29788
|
if (run.sourceFingerprint.rawTokensPath) {
|
|
29686
29789
|
const absPath = run.sourceFingerprint.rawTokensPath;
|
|
29687
29790
|
try {
|
|
29688
|
-
const [st, buf] = await Promise.all([stat7(absPath),
|
|
29791
|
+
const [st, buf] = await Promise.all([stat7(absPath), readFile26(absPath)]);
|
|
29689
29792
|
const mtime = st.mtime.toISOString();
|
|
29690
29793
|
const hash = sha256Hex(buf);
|
|
29691
29794
|
const mtimeChanged = run.sourceFingerprint.rawTokensMtime !== null && mtime !== run.sourceFingerprint.rawTokensMtime;
|
|
@@ -29701,9 +29804,9 @@ async function checkRunStaleness(run) {
|
|
|
29701
29804
|
}
|
|
29702
29805
|
if (run.savedFingerprint) {
|
|
29703
29806
|
if (run.savedFingerprint.componentsJsonHash !== null) {
|
|
29704
|
-
const compPath =
|
|
29807
|
+
const compPath = join25(run.savePath, "components.json");
|
|
29705
29808
|
try {
|
|
29706
|
-
const buf = await
|
|
29809
|
+
const buf = await readFile26(compPath);
|
|
29707
29810
|
if (sha256Hex(buf) !== run.savedFingerprint.componentsJsonHash) {
|
|
29708
29811
|
result.savedComponentsEdited = true;
|
|
29709
29812
|
result.stale = true;
|
|
@@ -29714,9 +29817,9 @@ async function checkRunStaleness(run) {
|
|
|
29714
29817
|
}
|
|
29715
29818
|
}
|
|
29716
29819
|
if (run.savedFingerprint.tokensJsonHash !== null) {
|
|
29717
|
-
const tokensPath = run.tokensPath ??
|
|
29820
|
+
const tokensPath = run.tokensPath ?? join25(run.savePath, "tokens.json");
|
|
29718
29821
|
try {
|
|
29719
|
-
const buf = await
|
|
29822
|
+
const buf = await readFile26(tokensPath);
|
|
29720
29823
|
if (sha256Hex(buf) !== run.savedFingerprint.tokensJsonHash) {
|
|
29721
29824
|
result.savedTokensEdited = true;
|
|
29722
29825
|
result.stale = true;
|
|
@@ -29780,23 +29883,23 @@ __export(push_creds_prompt_exports, {
|
|
|
29780
29883
|
});
|
|
29781
29884
|
import React29 from "react";
|
|
29782
29885
|
async function promptForPushCredentials(opts = {}) {
|
|
29783
|
-
const { render: render7, Box:
|
|
29784
|
-
const { useState:
|
|
29886
|
+
const { render: render7, Box: Box50, Text: Text52 } = await import("ink");
|
|
29887
|
+
const { useState: useState29 } = await import("react");
|
|
29785
29888
|
const { CredentialsStep: CredentialsStep2 } = await Promise.resolve().then(() => (init_CredentialsStep(), CredentialsStep_exports));
|
|
29786
|
-
return new Promise((
|
|
29889
|
+
return new Promise((resolve28, reject) => {
|
|
29787
29890
|
let app = null;
|
|
29788
29891
|
function App2() {
|
|
29789
|
-
const [done, setDone] =
|
|
29892
|
+
const [done, setDone] = useState29(false);
|
|
29790
29893
|
const handle = (spaceId, environmentId, cmaToken, host) => {
|
|
29791
29894
|
if (done) return;
|
|
29792
29895
|
setDone(true);
|
|
29793
29896
|
queueMicrotask(() => {
|
|
29794
29897
|
app?.unmount();
|
|
29795
|
-
|
|
29898
|
+
resolve28({ spaceId, environmentId, cmaToken, host });
|
|
29796
29899
|
});
|
|
29797
29900
|
};
|
|
29798
29901
|
if (done) {
|
|
29799
|
-
return React29.createElement(
|
|
29902
|
+
return React29.createElement(Box50, null, React29.createElement(Text52, null, ""));
|
|
29800
29903
|
}
|
|
29801
29904
|
return React29.createElement(CredentialsStep2, {
|
|
29802
29905
|
summary: opts.summary ?? "Enter Contentful credentials to push this run. Press Enter on each field to advance.",
|
|
@@ -29821,1122 +29924,17 @@ var init_push_creds_prompt = __esm({
|
|
|
29821
29924
|
}
|
|
29822
29925
|
});
|
|
29823
29926
|
|
|
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
29927
|
// packages/experience-design-system-cli/src/program.ts
|
|
30930
29928
|
import { spawn as spawn6 } from "node:child_process";
|
|
30931
29929
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
30932
|
-
import { dirname as dirname14, join as
|
|
30933
|
-
import { readFileSync as
|
|
29930
|
+
import { dirname as dirname14, join as join28, resolve as resolve27 } from "node:path";
|
|
29931
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
30934
29932
|
import { Command } from "commander";
|
|
30935
29933
|
|
|
30936
29934
|
// packages/experience-design-system-cli/src/analyze/command.ts
|
|
30937
29935
|
import { createElement as createElement3 } from "react";
|
|
30938
29936
|
import { render as render3 } from "ink";
|
|
30939
|
-
import { mkdir as mkdir3, readdir as readdir2, readFile as
|
|
29937
|
+
import { mkdir as mkdir3, readdir as readdir2, readFile as readFile17, stat as stat2, writeFile as writeFile3 } from "node:fs/promises";
|
|
30940
29938
|
import { isAbsolute as isAbsolute4, join as join15, relative as relative3, resolve as resolve15 } from "node:path";
|
|
30941
29939
|
|
|
30942
29940
|
// packages/experience-design-system-cli/src/lib/agent-model-options.ts
|
|
@@ -31063,6 +30061,104 @@ init_command2();
|
|
|
31063
30061
|
// packages/experience-design-system-cli/src/analyze/select-agent/command.ts
|
|
31064
30062
|
init_db();
|
|
31065
30063
|
init_cache_keys();
|
|
30064
|
+
|
|
30065
|
+
// packages/experience-design-system-cli/src/helpers/read-existing-contentful-entities-from-session.ts
|
|
30066
|
+
import { readFile as readFile13 } from "node:fs/promises";
|
|
30067
|
+
async function readExistingContentfulEntitiesFromSession(path) {
|
|
30068
|
+
if (!path) return void 0;
|
|
30069
|
+
try {
|
|
30070
|
+
const raw = await readFile13(path, "utf8");
|
|
30071
|
+
const parsed = JSON.parse(raw);
|
|
30072
|
+
if (!Array.isArray(parsed.components) || !Array.isArray(parsed.tokens)) return void 0;
|
|
30073
|
+
return parsed;
|
|
30074
|
+
} catch {
|
|
30075
|
+
return void 0;
|
|
30076
|
+
}
|
|
30077
|
+
}
|
|
30078
|
+
|
|
30079
|
+
// packages/experience-design-system-cli/src/helpers/find-nearly-matching-component.ts
|
|
30080
|
+
var MAX_CHARACTER_EDITS_FOR_LIKELY_MATCH = 2;
|
|
30081
|
+
function findNearlyMatchingComponent(components, codebaseName) {
|
|
30082
|
+
const target = simplifyNameForComparison(codebaseName);
|
|
30083
|
+
if (!target) return void 0;
|
|
30084
|
+
let best;
|
|
30085
|
+
for (const c2 of components) {
|
|
30086
|
+
const edits = countCharacterEdits(target, simplifyNameForComparison(c2.name));
|
|
30087
|
+
if (edits > MAX_CHARACTER_EDITS_FOR_LIKELY_MATCH) continue;
|
|
30088
|
+
if (!best || edits < best.edits) best = { component: c2, edits };
|
|
30089
|
+
if (edits === 0) break;
|
|
30090
|
+
}
|
|
30091
|
+
return best?.component;
|
|
30092
|
+
}
|
|
30093
|
+
function simplifyNameForComparison(name) {
|
|
30094
|
+
const stripped = name.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
30095
|
+
return stripped.endsWith("s") && stripped.length > 1 ? stripped.slice(0, -1) : stripped;
|
|
30096
|
+
}
|
|
30097
|
+
function countCharacterEdits(a, b) {
|
|
30098
|
+
if (a === b) return 0;
|
|
30099
|
+
if (a.length === 0) return b.length;
|
|
30100
|
+
if (b.length === 0) return a.length;
|
|
30101
|
+
if (a.length > b.length) [a, b] = [b, a];
|
|
30102
|
+
let prev = new Array(a.length + 1);
|
|
30103
|
+
let curr = new Array(a.length + 1);
|
|
30104
|
+
for (let i = 0; i <= a.length; i++) prev[i] = i;
|
|
30105
|
+
for (let j = 1; j <= b.length; j++) {
|
|
30106
|
+
curr[0] = j;
|
|
30107
|
+
for (let i = 1; i <= a.length; i++) {
|
|
30108
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
30109
|
+
curr[i] = Math.min(curr[i - 1] + 1, prev[i] + 1, prev[i - 1] + cost);
|
|
30110
|
+
}
|
|
30111
|
+
[prev, curr] = [curr, prev];
|
|
30112
|
+
}
|
|
30113
|
+
return prev[a.length];
|
|
30114
|
+
}
|
|
30115
|
+
|
|
30116
|
+
// packages/experience-design-system-cli/src/helpers/summarize-existing-contentful-entities.ts
|
|
30117
|
+
function summarizeForSelectAgent(entities) {
|
|
30118
|
+
return {
|
|
30119
|
+
components: entities.components.map((c2) => ({
|
|
30120
|
+
id: c2.sys.id,
|
|
30121
|
+
name: c2.name,
|
|
30122
|
+
description: c2.description
|
|
30123
|
+
})),
|
|
30124
|
+
tokens: summarizeTokens(entities.tokens)
|
|
30125
|
+
};
|
|
30126
|
+
}
|
|
30127
|
+
function summarizeForGenerateAgent(entities, codebaseComponentName) {
|
|
30128
|
+
const match2 = findNearlyMatchingComponent(entities.components, codebaseComponentName);
|
|
30129
|
+
const otherComponents = entities.components.filter((c2) => c2.sys.id !== match2?.sys.id).map((c2) => ({ id: c2.sys.id, name: c2.name }));
|
|
30130
|
+
return {
|
|
30131
|
+
likelyMatch: match2 ? {
|
|
30132
|
+
id: match2.sys.id,
|
|
30133
|
+
name: match2.name,
|
|
30134
|
+
designProperties: match2.designProperties.map((p) => ({
|
|
30135
|
+
id: p.id,
|
|
30136
|
+
name: p.name,
|
|
30137
|
+
type: p.type
|
|
30138
|
+
})),
|
|
30139
|
+
contentProperties: match2.contentProperties.map((p) => ({
|
|
30140
|
+
id: p.id,
|
|
30141
|
+
name: p.name,
|
|
30142
|
+
type: p.type
|
|
30143
|
+
})),
|
|
30144
|
+
slots: (match2.slots ?? []).map((s) => ({ id: s.id, name: s.name }))
|
|
30145
|
+
} : void 0,
|
|
30146
|
+
otherComponents,
|
|
30147
|
+
tokens: summarizeTokens(entities.tokens)
|
|
30148
|
+
};
|
|
30149
|
+
}
|
|
30150
|
+
function summarizeForMapTokens(entities) {
|
|
30151
|
+
return {
|
|
30152
|
+
tokens: entities.tokens.map((t) => ({ id: t.sys.id, name: t.name, type: t.type }))
|
|
30153
|
+
};
|
|
30154
|
+
}
|
|
30155
|
+
function summarizeTokens(tokens) {
|
|
30156
|
+
const kinds = /* @__PURE__ */ new Set();
|
|
30157
|
+
for (const t of tokens) kinds.add(t.type);
|
|
30158
|
+
return { count: tokens.length, kinds: [...kinds].sort() };
|
|
30159
|
+
}
|
|
30160
|
+
|
|
30161
|
+
// packages/experience-design-system-cli/src/analyze/select-agent/command.ts
|
|
31066
30162
|
init_persistence();
|
|
31067
30163
|
init_parser();
|
|
31068
30164
|
init_src();
|
|
@@ -31164,7 +30260,7 @@ var OutputFormatter = class {
|
|
|
31164
30260
|
};
|
|
31165
30261
|
|
|
31166
30262
|
// packages/experience-design-system-cli/src/analyze/select-agent/context-builder.ts
|
|
31167
|
-
import { readFile as
|
|
30263
|
+
import { readFile as readFile14 } from "node:fs/promises";
|
|
31168
30264
|
import { dirname as dirname10, isAbsolute as isAbsolute2, join as join13, relative as relative2, resolve as resolve11, sep } from "node:path";
|
|
31169
30265
|
var SCANNED_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".astro", ".js", ".jsx", ".svelte", ".ts", ".tsx", ".vue"]);
|
|
31170
30266
|
var IMPORT_PATTERN2 = /import\s+(?:type\s+)?(.+?)\s+from\s+['"]([^'"]+)['"]/g;
|
|
@@ -31293,7 +30389,7 @@ async function buildRepoContextIndex(root, filePaths) {
|
|
|
31293
30389
|
absolutePath,
|
|
31294
30390
|
relativePath: toPosixPath(relative2(resolvedRoot, absolutePath)),
|
|
31295
30391
|
directory: dirname10(absolutePath),
|
|
31296
|
-
text: await
|
|
30392
|
+
text: await readFile14(absolutePath, "utf8").catch(() => "")
|
|
31297
30393
|
})
|
|
31298
30394
|
)
|
|
31299
30395
|
);
|
|
@@ -31506,8 +30602,8 @@ function resolveProjectRoot(sessionId2, projectRootFlag) {
|
|
|
31506
30602
|
db.close();
|
|
31507
30603
|
}
|
|
31508
30604
|
}
|
|
31509
|
-
async function selectBatch(agent, model, batch, total, verbose, skillPathOverride) {
|
|
31510
|
-
const
|
|
30605
|
+
async function selectBatch(agent, model, batch, total, verbose, skillPathOverride, existingComponentsInline) {
|
|
30606
|
+
const prompt2 = await buildPrompt({
|
|
31511
30607
|
skill: "select",
|
|
31512
30608
|
mode: "autonomous",
|
|
31513
30609
|
rawComponentsInline: JSON.stringify(
|
|
@@ -31516,7 +30612,8 @@ async function selectBatch(agent, model, batch, total, verbose, skillPathOverrid
|
|
|
31516
30612
|
2
|
|
31517
30613
|
),
|
|
31518
30614
|
outDir: process.cwd(),
|
|
31519
|
-
skillPathOverride
|
|
30615
|
+
skillPathOverride,
|
|
30616
|
+
existingComponentsInline
|
|
31520
30617
|
});
|
|
31521
30618
|
let outputBuf = "";
|
|
31522
30619
|
const formatter = new OutputFormatter(verbose, (s) => {
|
|
@@ -31525,7 +30622,7 @@ async function selectBatch(agent, model, batch, total, verbose, skillPathOverrid
|
|
|
31525
30622
|
const result = await invoker.invoke({
|
|
31526
30623
|
agent,
|
|
31527
30624
|
model,
|
|
31528
|
-
prompt,
|
|
30625
|
+
prompt: prompt2,
|
|
31529
30626
|
timeoutMs: DEFAULT_TIMEOUT_MS,
|
|
31530
30627
|
onOutput: (chunk) => formatter.push(chunk)
|
|
31531
30628
|
});
|
|
@@ -31611,7 +30708,7 @@ ${outputBuf}`);
|
|
|
31611
30708
|
}
|
|
31612
30709
|
return results;
|
|
31613
30710
|
}
|
|
31614
|
-
async function selectAllComponents(agent, model, components, verbose, skillPathOverride, cacheConfig = { noCache: true }) {
|
|
30711
|
+
async function selectAllComponents(agent, model, components, verbose, skillPathOverride, existingComponentsInline, cacheConfig = { noCache: true }) {
|
|
31615
30712
|
const concurrency = Number(process.env.EDS_GENERATE_CONCURRENCY ?? DEFAULT_CONCURRENCY);
|
|
31616
30713
|
const batchSize = resolveBatchSize();
|
|
31617
30714
|
const total = components.length;
|
|
@@ -31620,7 +30717,13 @@ async function selectAllComponents(agent, model, components, verbose, skillPathO
|
|
|
31620
30717
|
let cliVersion2 = "";
|
|
31621
30718
|
if (!cacheConfig.noCache) {
|
|
31622
30719
|
try {
|
|
31623
|
-
promptHash = await hashPromptForSkill(
|
|
30720
|
+
promptHash = await hashPromptForSkill(
|
|
30721
|
+
"select",
|
|
30722
|
+
agent,
|
|
30723
|
+
model,
|
|
30724
|
+
skillPathOverride,
|
|
30725
|
+
existingComponentsInline ? [hashContent(existingComponentsInline)] : []
|
|
30726
|
+
);
|
|
31624
30727
|
cliVersion2 = await getCliCacheVersion();
|
|
31625
30728
|
const db = openPipelineDb(cacheConfig.dbPath);
|
|
31626
30729
|
try {
|
|
@@ -31676,7 +30779,15 @@ async function selectAllComponents(agent, model, components, verbose, skillPathO
|
|
|
31676
30779
|
while (nextBatch < batches.length) {
|
|
31677
30780
|
const b = nextBatch++;
|
|
31678
30781
|
const batch = batches[b];
|
|
31679
|
-
const batchResults = await selectBatch(
|
|
30782
|
+
const batchResults = await selectBatch(
|
|
30783
|
+
agent,
|
|
30784
|
+
model,
|
|
30785
|
+
batch,
|
|
30786
|
+
total,
|
|
30787
|
+
verbose,
|
|
30788
|
+
skillPathOverride,
|
|
30789
|
+
existingComponentsInline
|
|
30790
|
+
);
|
|
31680
30791
|
for (let k = 0; k < batch.length; k++) {
|
|
31681
30792
|
results[batch[k].index] = batchResults[k];
|
|
31682
30793
|
}
|
|
@@ -31712,6 +30823,9 @@ function registerAnalyzeSelectAgentCommand(program) {
|
|
|
31712
30823
|
"--select-prompt-path <path>",
|
|
31713
30824
|
"Path to a custom .md skill prompt for select-agent (bypasses bundled prompt invariants)"
|
|
31714
30825
|
).option("--no-select-cache", "Skip the per-component select cache and re-LLM every component").option("--no-cache", "Skip ALL fine-grained caches (extract, select, generate)").option(
|
|
30826
|
+
"--existing-entities-path <path>",
|
|
30827
|
+
"Path to the .existing-entities.json file written by the orchestrator when CMA credentials are supplied. When present, the agent gets an existing-components summary to align rejection/acceptance reasoning with the target space. Missing/malformed files are treated as no-op."
|
|
30828
|
+
).option(
|
|
31715
30829
|
"--show-rationale",
|
|
31716
30830
|
"Read-only: print the AI rejection rationale persisted by a prior select-agent run and exit. No LLM call. Combine with --json for machine-readable output."
|
|
31717
30831
|
).option("--json", "When used with --show-rationale, emit a JSON array instead of a human-readable table").action(
|
|
@@ -31820,6 +30934,20 @@ function registerAnalyzeSelectAgentCommand(program) {
|
|
|
31820
30934
|
}));
|
|
31821
30935
|
}
|
|
31822
30936
|
}
|
|
30937
|
+
let existingComponentsInline;
|
|
30938
|
+
if (opts.existingEntitiesPath) {
|
|
30939
|
+
const existingContentfulEntities = await readExistingContentfulEntitiesFromSession(
|
|
30940
|
+
resolve12(opts.existingEntitiesPath)
|
|
30941
|
+
);
|
|
30942
|
+
if (existingContentfulEntities) {
|
|
30943
|
+
existingComponentsInline = JSON.stringify(summarizeForSelectAgent(existingContentfulEntities));
|
|
30944
|
+
} else {
|
|
30945
|
+
process.stderr.write(
|
|
30946
|
+
`warn: --existing-entities-path ${opts.existingEntitiesPath} could not be read as JSON \u2014 proceeding without space-context enrichment
|
|
30947
|
+
`
|
|
30948
|
+
);
|
|
30949
|
+
}
|
|
30950
|
+
}
|
|
31823
30951
|
if (opts.dryRun) {
|
|
31824
30952
|
if (selectionCandidates.length === 0) {
|
|
31825
30953
|
process.stderr.write(
|
|
@@ -31829,14 +30957,15 @@ function registerAnalyzeSelectAgentCommand(program) {
|
|
|
31829
30957
|
return;
|
|
31830
30958
|
}
|
|
31831
30959
|
const first = selectionCandidates[0];
|
|
31832
|
-
const
|
|
30960
|
+
const prompt2 = await buildPrompt({
|
|
31833
30961
|
skill: "select",
|
|
31834
30962
|
mode: "autonomous",
|
|
31835
30963
|
rawComponentsInline: JSON.stringify([buildComponentData(first)], null, 2),
|
|
31836
30964
|
outDir: process.cwd(),
|
|
31837
|
-
skillPathOverride: selectPromptPath ? resolve12(selectPromptPath) : void 0
|
|
30965
|
+
skillPathOverride: selectPromptPath ? resolve12(selectPromptPath) : void 0,
|
|
30966
|
+
existingComponentsInline
|
|
31838
30967
|
});
|
|
31839
|
-
process.stdout.write(
|
|
30968
|
+
process.stdout.write(prompt2 + "\n");
|
|
31840
30969
|
await exitWithAnalytics(0);
|
|
31841
30970
|
return;
|
|
31842
30971
|
}
|
|
@@ -31847,6 +30976,7 @@ function registerAnalyzeSelectAgentCommand(program) {
|
|
|
31847
30976
|
selectionCandidates,
|
|
31848
30977
|
opts.verbose ?? false,
|
|
31849
30978
|
selectPromptPath ? resolve12(selectPromptPath) : void 0,
|
|
30979
|
+
existingComponentsInline,
|
|
31850
30980
|
{ noCache }
|
|
31851
30981
|
);
|
|
31852
30982
|
const decisions = /* @__PURE__ */ new Map();
|
|
@@ -32195,8 +31325,8 @@ async function resolveMapping(input) {
|
|
|
32195
31325
|
const residueParents = input.components.map((c2) => c2.name).filter((n) => !coveredParents.has(n));
|
|
32196
31326
|
const shouldRunAgent = (input.useAgent || input.forceAgent) && (input.forceAgent || residueParents.length > 0);
|
|
32197
31327
|
if (shouldRunAgent) {
|
|
32198
|
-
const
|
|
32199
|
-
const raw = await input.runAgentFn({ prompt, files: input.files });
|
|
31328
|
+
const prompt2 = input.buildPrompt ? input.buildPrompt(input.files, [...componentNames]) : defaultPrompt(input.files, [...componentNames], input.promptOverride);
|
|
31329
|
+
const raw = await input.runAgentFn({ prompt: prompt2, files: input.files });
|
|
32200
31330
|
const parsed = parseMapEdges(raw, { componentNames });
|
|
32201
31331
|
collected.push(...parsed.edges);
|
|
32202
31332
|
agentWarnings.push(...parsed.warnings);
|
|
@@ -32234,11 +31364,11 @@ ${f.content}`).join("\n\n");
|
|
|
32234
31364
|
}
|
|
32235
31365
|
|
|
32236
31366
|
// packages/experience-design-system-cli/src/analyze/composition/resolve-mapping-cli.ts
|
|
32237
|
-
import { readFile as
|
|
31367
|
+
import { readFile as readFile15 } from "node:fs/promises";
|
|
32238
31368
|
async function loadUserMap(path) {
|
|
32239
31369
|
let text;
|
|
32240
31370
|
try {
|
|
32241
|
-
text = await
|
|
31371
|
+
text = await readFile15(path, "utf8");
|
|
32242
31372
|
} catch {
|
|
32243
31373
|
return { ok: false, error: `--composition-map: file not found: ${path}` };
|
|
32244
31374
|
}
|
|
@@ -32474,16 +31604,16 @@ var HEAP_CAP_MB = 128;
|
|
|
32474
31604
|
var MAX_INPUT_BYTES = 8 * 1024 * 1024;
|
|
32475
31605
|
function runParserInSandbox(source, ctx, opts = {}) {
|
|
32476
31606
|
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
32477
|
-
return new Promise((
|
|
31607
|
+
return new Promise((resolve28) => {
|
|
32478
31608
|
let input;
|
|
32479
31609
|
try {
|
|
32480
31610
|
input = JSON.stringify({ source, ctx, timeoutMs });
|
|
32481
31611
|
} catch {
|
|
32482
|
-
|
|
31612
|
+
resolve28({ edges: [], error: "ctx is not serializable" });
|
|
32483
31613
|
return;
|
|
32484
31614
|
}
|
|
32485
31615
|
if (input.length > MAX_INPUT_BYTES) {
|
|
32486
|
-
|
|
31616
|
+
resolve28({ edges: [], error: "parser input exceeds size limit" });
|
|
32487
31617
|
return;
|
|
32488
31618
|
}
|
|
32489
31619
|
let settled = false;
|
|
@@ -32515,7 +31645,7 @@ function runParserInSandbox(source, ctx, opts = {}) {
|
|
|
32515
31645
|
child.kill("SIGKILL");
|
|
32516
31646
|
} catch {
|
|
32517
31647
|
}
|
|
32518
|
-
|
|
31648
|
+
resolve28(r);
|
|
32519
31649
|
};
|
|
32520
31650
|
const timer = setTimeout(
|
|
32521
31651
|
() => done({ edges: [], error: `parser timed out after ${timeoutMs}ms` }),
|
|
@@ -32676,9 +31806,9 @@ async function resolveViaAgentParser(input) {
|
|
|
32676
31806
|
}
|
|
32677
31807
|
return out;
|
|
32678
31808
|
};
|
|
32679
|
-
const attempt = async (
|
|
31809
|
+
const attempt = async (prompt2) => {
|
|
32680
31810
|
input.onPhase?.("authoring");
|
|
32681
|
-
const raw = await input.runAgentFn({ prompt });
|
|
31811
|
+
const raw = await input.runAgentFn({ prompt: prompt2 });
|
|
32682
31812
|
const source = extractParserSource(raw);
|
|
32683
31813
|
if (source === null)
|
|
32684
31814
|
return { error: "agent output had no parser-shaped code block (expected `export default function (ctx) {\u2026}`)" };
|
|
@@ -32727,7 +31857,7 @@ ${loadPrompt("composition-parser-repair-error.md").trim().replace("{{error}}", f
|
|
|
32727
31857
|
}
|
|
32728
31858
|
|
|
32729
31859
|
// packages/experience-design-system-cli/src/lib/prompt-overrides.ts
|
|
32730
|
-
import { readFile as
|
|
31860
|
+
import { readFile as readFile16 } from "node:fs/promises";
|
|
32731
31861
|
import { resolve as resolve14 } from "node:path";
|
|
32732
31862
|
var PROMPT_FILE_EXTENSIONS = [".md", ".txt", ".prompt"];
|
|
32733
31863
|
function looksLikePath(value) {
|
|
@@ -32763,7 +31893,7 @@ async function resolvePromptOverride(override) {
|
|
|
32763
31893
|
if (override.kind === "text") return override.value;
|
|
32764
31894
|
const abs = resolve14(override.value);
|
|
32765
31895
|
try {
|
|
32766
|
-
return await
|
|
31896
|
+
return await readFile16(abs, "utf8");
|
|
32767
31897
|
} catch {
|
|
32768
31898
|
throw new Error(`--prompt: could not read prompt file: ${abs}`);
|
|
32769
31899
|
}
|
|
@@ -32946,7 +32076,7 @@ async function readCandidateFiles(components, extraFiles = []) {
|
|
|
32946
32076
|
await Promise.all(
|
|
32947
32077
|
[...paths].map(async (p) => {
|
|
32948
32078
|
try {
|
|
32949
|
-
const content = await
|
|
32079
|
+
const content = await readFile17(p, "utf8");
|
|
32950
32080
|
out.push({ path: p, content });
|
|
32951
32081
|
} catch {
|
|
32952
32082
|
}
|
|
@@ -33137,10 +32267,10 @@ function registerAnalyzeCommand(program) {
|
|
|
33137
32267
|
const componentNameSet = new Set(validatedComponents.map((c2) => c2.name));
|
|
33138
32268
|
const cacheVersion = await getCliCacheVersion();
|
|
33139
32269
|
let lastAgentExitCode = 0;
|
|
33140
|
-
const spawnAgent = async (
|
|
32270
|
+
const spawnAgent = async (prompt2) => {
|
|
33141
32271
|
const res = await runAgent({
|
|
33142
32272
|
agent: resolverAgent,
|
|
33143
|
-
prompt,
|
|
32273
|
+
prompt: prompt2,
|
|
33144
32274
|
timeoutMs: 12e4,
|
|
33145
32275
|
promptViaStdin: true,
|
|
33146
32276
|
onDebugEvent: (name, payload) => getDebugLogger().event("agent", name, payload)
|
|
@@ -33192,7 +32322,7 @@ function registerAnalyzeCommand(program) {
|
|
|
33192
32322
|
files: promptFiles,
|
|
33193
32323
|
runtimeFiles,
|
|
33194
32324
|
componentNames: componentNameSet,
|
|
33195
|
-
runAgentFn: ({ prompt }) => spawnAgent(
|
|
32325
|
+
runAgentFn: ({ prompt: prompt2 }) => spawnAgent(prompt2),
|
|
33196
32326
|
...compositionPrompt ? { instructionOverride: compositionPrompt } : {},
|
|
33197
32327
|
onPhase: (phase) => emitCompositionProgress(phase),
|
|
33198
32328
|
// The candidate filter selected these files because they carry
|
|
@@ -33236,7 +32366,7 @@ function registerAnalyzeCommand(program) {
|
|
|
33236
32366
|
forceAgent: sources.forceAgent && useEdgeEmission,
|
|
33237
32367
|
files: promptFiles,
|
|
33238
32368
|
...compositionPrompt ? { promptOverride: compositionPrompt } : {},
|
|
33239
|
-
runAgentFn: async ({ prompt }) => {
|
|
32369
|
+
runAgentFn: async ({ prompt: prompt2 }) => {
|
|
33240
32370
|
if (!opts.compositionRefresh) {
|
|
33241
32371
|
const cached = lookupCompositionCache(db, agentCacheKey, cacheVersion);
|
|
33242
32372
|
if (cached !== null) {
|
|
@@ -33245,7 +32375,7 @@ function registerAnalyzeCommand(program) {
|
|
|
33245
32375
|
}
|
|
33246
32376
|
}
|
|
33247
32377
|
emitCompositionProgress(`agent:${resolverAgent}`);
|
|
33248
|
-
const stdout = await spawnAgent(
|
|
32378
|
+
const stdout = await spawnAgent(prompt2);
|
|
33249
32379
|
if (lastAgentExitCode === 0) {
|
|
33250
32380
|
storeCompositionCache(db, agentCacheKey, cacheVersion, stdout);
|
|
33251
32381
|
}
|
|
@@ -33350,7 +32480,7 @@ function registerAnalyzeCommand(program) {
|
|
|
33350
32480
|
init_src();
|
|
33351
32481
|
import { createElement as createElement4 } from "react";
|
|
33352
32482
|
import { render as render4 } from "ink";
|
|
33353
|
-
import { access as access6, readFile as
|
|
32483
|
+
import { access as access6, readFile as readFile19, readdir as readdir3, stat as stat3 } from "node:fs/promises";
|
|
33354
32484
|
import { join as join16, resolve as resolve17 } from "node:path";
|
|
33355
32485
|
init_debug_logger();
|
|
33356
32486
|
|
|
@@ -33391,7 +32521,7 @@ function GenerateView({ result, onExit }) {
|
|
|
33391
32521
|
}
|
|
33392
32522
|
|
|
33393
32523
|
// packages/experience-design-system-cli/src/generate/edit/command.ts
|
|
33394
|
-
import { readFile as
|
|
32524
|
+
import { readFile as readFile18 } from "node:fs/promises";
|
|
33395
32525
|
import { resolve as resolve16 } from "node:path";
|
|
33396
32526
|
var SAFE_PATH_RE2 = /^[a-zA-Z0-9_.$[\]=]+$/;
|
|
33397
32527
|
var PROTO_KEYS2 = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
@@ -33474,7 +32604,7 @@ async function runNonInteractive2(opts, skill) {
|
|
|
33474
32604
|
if (opts.patch) {
|
|
33475
32605
|
let patchOps;
|
|
33476
32606
|
try {
|
|
33477
|
-
const raw = await
|
|
32607
|
+
const raw = await readFile18(resolve16(opts.patch), "utf8");
|
|
33478
32608
|
patchOps = JSON.parse(raw);
|
|
33479
32609
|
} catch {
|
|
33480
32610
|
process.stderr.write(`Error: cannot read or parse --patch file: ${opts.patch}
|
|
@@ -33568,7 +32698,7 @@ async function readFileInline(path) {
|
|
|
33568
32698
|
} catch {
|
|
33569
32699
|
return void 0;
|
|
33570
32700
|
}
|
|
33571
|
-
if (!s.isDirectory()) return
|
|
32701
|
+
if (!s.isDirectory()) return readFile19(resolved, "utf8");
|
|
33572
32702
|
const files = [];
|
|
33573
32703
|
async function walk(dir) {
|
|
33574
32704
|
let entries;
|
|
@@ -33594,7 +32724,7 @@ async function readFileInline(path) {
|
|
|
33594
32724
|
}
|
|
33595
32725
|
await walk(resolved);
|
|
33596
32726
|
if (files.length === 0) return void 0;
|
|
33597
|
-
const parts = await Promise.all(files.map((f) =>
|
|
32727
|
+
const parts = await Promise.all(files.map((f) => readFile19(f, "utf8").catch(() => "")));
|
|
33598
32728
|
return parts.filter(Boolean).join("\n\n");
|
|
33599
32729
|
}
|
|
33600
32730
|
function printFallbackInstructions(options) {
|
|
@@ -33616,7 +32746,7 @@ function printFallbackInstructions(options) {
|
|
|
33616
32746
|
lines.push(` Re-run the generate command with the agent available, or use --dry-run to inspect the prompt.`);
|
|
33617
32747
|
process.stderr.write(lines.join("\n") + "\n");
|
|
33618
32748
|
}
|
|
33619
|
-
async function runOneComponent(agent, model, db, sessionId2, component, tokensInline, tokenMapInline, index, total, verbose, noCache, skillPathOverride, promptHash) {
|
|
32749
|
+
async function runOneComponent(agent, model, db, sessionId2, component, tokensInline, tokenMapInline, index, total, verbose, noCache, skillPathOverride, promptHash, existingContentfulEntities, existingTokensInline) {
|
|
33620
32750
|
const pos = c.dim(`[${index + 1}/${total}]`);
|
|
33621
32751
|
if (!noCache) {
|
|
33622
32752
|
const inputHash = computeComponentInputHash(component);
|
|
@@ -33686,7 +32816,8 @@ async function runOneComponent(agent, model, db, sessionId2, component, tokensIn
|
|
|
33686
32816
|
component.props.map((p) => p.name),
|
|
33687
32817
|
component.props.map((p) => p.type)
|
|
33688
32818
|
);
|
|
33689
|
-
const
|
|
32819
|
+
const existingComponentsInline = existingContentfulEntities ? JSON.stringify(summarizeForGenerateAgent(existingContentfulEntities, component.name)) : void 0;
|
|
32820
|
+
const prompt2 = await buildPrompt({
|
|
33690
32821
|
skill: "components",
|
|
33691
32822
|
mode: "autonomous",
|
|
33692
32823
|
rawComponentsInline,
|
|
@@ -33695,7 +32826,9 @@ async function runOneComponent(agent, model, db, sessionId2, component, tokensIn
|
|
|
33695
32826
|
outDir: process.cwd(),
|
|
33696
32827
|
componentName: component.name,
|
|
33697
32828
|
componentSourceRefs: [sourceRef],
|
|
33698
|
-
skillPathOverride
|
|
32829
|
+
skillPathOverride,
|
|
32830
|
+
existingComponentsInline,
|
|
32831
|
+
existingTokensInline
|
|
33699
32832
|
});
|
|
33700
32833
|
const maxAttempts = 2;
|
|
33701
32834
|
let lastError = "";
|
|
@@ -33708,7 +32841,7 @@ async function runOneComponent(agent, model, db, sessionId2, component, tokensIn
|
|
|
33708
32841
|
const result = await invoker2.invoke({
|
|
33709
32842
|
agent,
|
|
33710
32843
|
model,
|
|
33711
|
-
prompt,
|
|
32844
|
+
prompt: prompt2,
|
|
33712
32845
|
timeoutMs: DEFAULT_TIMEOUT_MS3,
|
|
33713
32846
|
onOutput: (chunk) => formatter.push(chunk)
|
|
33714
32847
|
});
|
|
@@ -33763,7 +32896,7 @@ ${outputBuf}`);
|
|
|
33763
32896
|
renamedSlotsCount: renames.length
|
|
33764
32897
|
};
|
|
33765
32898
|
}
|
|
33766
|
-
async function runAllComponents(agent, model, db, sessionId2, components, tokensInline, tokenMapInline, verbose, noCache, skillPathOverride, promptHash) {
|
|
32899
|
+
async function runAllComponents(agent, model, db, sessionId2, components, tokensInline, tokenMapInline, verbose, noCache, skillPathOverride, promptHash, existingContentfulEntities, existingTokensInline) {
|
|
33767
32900
|
const concurrency = Number(process.env.EDS_GENERATE_CONCURRENCY ?? DEFAULT_COMPONENT_CONCURRENCY);
|
|
33768
32901
|
process.stderr.write(
|
|
33769
32902
|
`Categorizing ${c.bold(String(components.length))} component${components.length === 1 ? "" : "s"}` + c.dim(` (concurrency: ${concurrency})`) + "\n"
|
|
@@ -33787,7 +32920,9 @@ async function runAllComponents(agent, model, db, sessionId2, components, tokens
|
|
|
33787
32920
|
verbose,
|
|
33788
32921
|
noCache,
|
|
33789
32922
|
skillPathOverride,
|
|
33790
|
-
promptHash
|
|
32923
|
+
promptHash,
|
|
32924
|
+
existingContentfulEntities,
|
|
32925
|
+
existingTokensInline
|
|
33791
32926
|
);
|
|
33792
32927
|
completed += 1;
|
|
33793
32928
|
process.stderr.write(`${formatGenerateProgressLine(completed, components.length, results[i].componentName)}
|
|
@@ -33825,7 +32960,7 @@ async function loadAcceptedNames(sessionId2) {
|
|
|
33825
32960
|
try {
|
|
33826
32961
|
const artifactsRoot = getRefineArtifactsRoot();
|
|
33827
32962
|
const paths = await getRefineSessionPaths(sessionId2, artifactsRoot);
|
|
33828
|
-
const raw = await
|
|
32963
|
+
const raw = await readFile19(paths.statePath, "utf8");
|
|
33829
32964
|
const snapshot = JSON.parse(raw);
|
|
33830
32965
|
const accepted = snapshot.components.filter((c2) => c2.status === "accepted").map((c2) => c2.name);
|
|
33831
32966
|
if (accepted.length === 0) return null;
|
|
@@ -33871,6 +33006,19 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
33871
33006
|
readFileInline(opts.tokens),
|
|
33872
33007
|
readFileInline(opts.tokenMap)
|
|
33873
33008
|
]);
|
|
33009
|
+
let existingContentfulEntities;
|
|
33010
|
+
let existingTokensInline;
|
|
33011
|
+
if (opts.existingEntitiesPath) {
|
|
33012
|
+
existingContentfulEntities = await readExistingContentfulEntitiesFromSession(resolve17(opts.existingEntitiesPath));
|
|
33013
|
+
if (existingContentfulEntities) {
|
|
33014
|
+
existingTokensInline = JSON.stringify(summarizeForMapTokens(existingContentfulEntities));
|
|
33015
|
+
} else {
|
|
33016
|
+
process.stderr.write(
|
|
33017
|
+
`warn: --existing-entities-path ${opts.existingEntitiesPath} could not be read as JSON \u2014 proceeding without space-context enrichment
|
|
33018
|
+
`
|
|
33019
|
+
);
|
|
33020
|
+
}
|
|
33021
|
+
}
|
|
33874
33022
|
let sessionId2;
|
|
33875
33023
|
let allComponents;
|
|
33876
33024
|
if (skill === "components") {
|
|
@@ -33931,7 +33079,8 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
33931
33079
|
sampleComponent.props.map((p) => p.name),
|
|
33932
33080
|
sampleComponent.props.map((p) => p.type)
|
|
33933
33081
|
) : void 0;
|
|
33934
|
-
const
|
|
33082
|
+
const dryRunExistingComponentsInline = skill === "components" && existingContentfulEntities && sampleComponent ? JSON.stringify(summarizeForGenerateAgent(existingContentfulEntities, sampleComponent.name)) : void 0;
|
|
33083
|
+
const prompt2 = await buildPrompt({
|
|
33935
33084
|
skill,
|
|
33936
33085
|
mode: "autonomous",
|
|
33937
33086
|
rawComponentsInline: sampleInline ?? rawTokensInline,
|
|
@@ -33941,9 +33090,11 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
33941
33090
|
tokenMapInline,
|
|
33942
33091
|
outDir: process.cwd(),
|
|
33943
33092
|
componentSourceRefs: sampleSourceRef ? [sampleSourceRef] : void 0,
|
|
33944
|
-
skillPathOverride: generatePromptPath
|
|
33093
|
+
skillPathOverride: generatePromptPath,
|
|
33094
|
+
existingComponentsInline: dryRunExistingComponentsInline,
|
|
33095
|
+
existingTokensInline: skill === "components" ? existingTokensInline : void 0
|
|
33945
33096
|
});
|
|
33946
|
-
process.stdout.write(
|
|
33097
|
+
process.stdout.write(prompt2 + "\n");
|
|
33947
33098
|
await exitWithAnalytics(0);
|
|
33948
33099
|
}
|
|
33949
33100
|
const binary = resolveBinary(agent);
|
|
@@ -33959,7 +33110,15 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
33959
33110
|
const db = openPipelineDb();
|
|
33960
33111
|
let componentResults;
|
|
33961
33112
|
try {
|
|
33962
|
-
const
|
|
33113
|
+
const existingContentfulEntitiesHashInputs = [];
|
|
33114
|
+
if (existingTokensInline) existingContentfulEntitiesHashInputs.push(hashContent(existingTokensInline));
|
|
33115
|
+
const promptHash = await hashPromptForSkill(
|
|
33116
|
+
"components",
|
|
33117
|
+
agent,
|
|
33118
|
+
model,
|
|
33119
|
+
generatePromptPath,
|
|
33120
|
+
existingContentfulEntitiesHashInputs
|
|
33121
|
+
);
|
|
33963
33122
|
componentResults = await runAllComponents(
|
|
33964
33123
|
agent,
|
|
33965
33124
|
model,
|
|
@@ -33971,7 +33130,9 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
33971
33130
|
verbose,
|
|
33972
33131
|
opts.cache === false || process.env.EDS_NO_CACHE === "1",
|
|
33973
33132
|
generatePromptPath,
|
|
33974
|
-
promptHash
|
|
33133
|
+
promptHash,
|
|
33134
|
+
existingContentfulEntities,
|
|
33135
|
+
existingTokensInline
|
|
33975
33136
|
);
|
|
33976
33137
|
} finally {
|
|
33977
33138
|
db.close();
|
|
@@ -34063,7 +33224,7 @@ session=${sessionId2 ?? ""}
|
|
|
34063
33224
|
return;
|
|
34064
33225
|
}
|
|
34065
33226
|
}
|
|
34066
|
-
const
|
|
33227
|
+
const prompt2 = await buildPrompt({
|
|
34067
33228
|
skill,
|
|
34068
33229
|
mode: "autonomous",
|
|
34069
33230
|
rawTokensInline,
|
|
@@ -34075,7 +33236,7 @@ session=${sessionId2 ?? ""}
|
|
|
34075
33236
|
const result = await invoker2.invoke({
|
|
34076
33237
|
agent,
|
|
34077
33238
|
model,
|
|
34078
|
-
prompt,
|
|
33239
|
+
prompt: prompt2,
|
|
34079
33240
|
timeoutMs: DEFAULT_TIMEOUT_MS3 * 5
|
|
34080
33241
|
});
|
|
34081
33242
|
if (result.timedOut) {
|
|
@@ -34148,6 +33309,9 @@ function registerGenerateCommand(program) {
|
|
|
34148
33309
|
const componentsCmd = generate.command("components").description("Invoke a coding agent to produce components.json from raw analysis output").option("--session <id>", "Session ID from analyze extract (defaults to most recent)").option("--tokens <path>", "Path to tokens.json for token-linked prop resolution").option("--token-map <path>", "Path to token-name-map.json sidecar").option(
|
|
34149
33310
|
"--generate-prompt-path <path>",
|
|
34150
33311
|
"Path to a custom .md skill prompt for components generation (bypasses bundled prompt invariants)"
|
|
33312
|
+
).option(
|
|
33313
|
+
"--existing-entities-path <path>",
|
|
33314
|
+
"Path to the .existing-entities.json file written by the orchestrator when CMA credentials are supplied. When present, per-component prompts include a summary of the target space so classifications can align to existing prop names/tokens. Missing/malformed files are treated as no-op."
|
|
34151
33315
|
);
|
|
34152
33316
|
addAgentFlags(componentsCmd).action(async (opts) => {
|
|
34153
33317
|
await runGenerateSkill("components", opts, opts.verbose ?? false);
|
|
@@ -34594,9 +33758,9 @@ ${"\u2500".repeat(60)}
|
|
|
34594
33758
|
`);
|
|
34595
33759
|
}
|
|
34596
33760
|
process.stdout.write("\nDelete these sessions? (y/N) ");
|
|
34597
|
-
const answer = await new Promise((
|
|
33761
|
+
const answer = await new Promise((resolve28) => {
|
|
34598
33762
|
process.stdin.setEncoding("utf8");
|
|
34599
|
-
process.stdin.once("data", (chunk) =>
|
|
33763
|
+
process.stdin.once("data", (chunk) => resolve28(String(chunk).trim().toLowerCase()));
|
|
34600
33764
|
});
|
|
34601
33765
|
if (answer !== "y") {
|
|
34602
33766
|
db.close();
|
|
@@ -34631,7 +33795,7 @@ import { access as access7, mkdir as mkdir4, stat as stat4, writeFile as writeFi
|
|
|
34631
33795
|
import { basename as basename5, resolve as resolve19 } from "node:path";
|
|
34632
33796
|
|
|
34633
33797
|
// packages/experience-design-system-cli/src/print/validate/validators/cdf-validator.ts
|
|
34634
|
-
import { readFile as
|
|
33798
|
+
import { readFile as readFile20 } from "node:fs/promises";
|
|
34635
33799
|
import { validateCDF as validateCDF2 } from "@contentful/experience-design-system-types";
|
|
34636
33800
|
function extractValue(input, path) {
|
|
34637
33801
|
if (path === "/") return void 0;
|
|
@@ -34690,7 +33854,7 @@ function rewriteDiagnostic(error, input) {
|
|
|
34690
33854
|
async function validateCDFFile(filePath) {
|
|
34691
33855
|
let content;
|
|
34692
33856
|
try {
|
|
34693
|
-
content = await
|
|
33857
|
+
content = await readFile20(filePath, "utf-8");
|
|
34694
33858
|
} catch (err) {
|
|
34695
33859
|
return {
|
|
34696
33860
|
valid: false,
|
|
@@ -34725,7 +33889,7 @@ async function validateCDFFile(filePath) {
|
|
|
34725
33889
|
}
|
|
34726
33890
|
|
|
34727
33891
|
// packages/experience-design-system-cli/src/print/validate/validators/dtcg-validator.ts
|
|
34728
|
-
import { readFile as
|
|
33892
|
+
import { readFile as readFile21 } from "node:fs/promises";
|
|
34729
33893
|
import { DESIGN_TOKEN_TYPES } from "@contentful/experience-design-system-types";
|
|
34730
33894
|
function walkDTCG(obj, path, diagnostics, counts) {
|
|
34731
33895
|
for (const [key, value] of Object.entries(obj)) {
|
|
@@ -34770,7 +33934,7 @@ function walkDTCG(obj, path, diagnostics, counts) {
|
|
|
34770
33934
|
async function validateDTCGTokenFile(filePath) {
|
|
34771
33935
|
let content;
|
|
34772
33936
|
try {
|
|
34773
|
-
content = await
|
|
33937
|
+
content = await readFile21(filePath, "utf-8");
|
|
34774
33938
|
} catch (err) {
|
|
34775
33939
|
return {
|
|
34776
33940
|
valid: false,
|
|
@@ -35103,7 +34267,8 @@ init_db();
|
|
|
35103
34267
|
init_cache_keys();
|
|
35104
34268
|
import { createElement as createElement6 } from "react";
|
|
35105
34269
|
import { render as render6 } from "ink";
|
|
35106
|
-
import { readFile as
|
|
34270
|
+
import { readFile as readFile22 } from "node:fs/promises";
|
|
34271
|
+
import { resolve as resolve20 } from "node:path";
|
|
35107
34272
|
|
|
35108
34273
|
// packages/experience-design-system-cli/src/map-tokens/apply.ts
|
|
35109
34274
|
init_db();
|
|
@@ -35351,7 +34516,7 @@ async function runMapTokens(opts) {
|
|
|
35351
34516
|
const knownTokenPaths = new Set(tokenLeaves.map((t) => t.path));
|
|
35352
34517
|
const tokenMapDiagnostics = [];
|
|
35353
34518
|
if (opts.tokenMap) {
|
|
35354
|
-
const fileMappings = JSON.parse(await
|
|
34519
|
+
const fileMappings = JSON.parse(await readFile22(opts.tokenMap, "utf8"));
|
|
35355
34520
|
const validMappings = {};
|
|
35356
34521
|
for (const [rawName, path] of Object.entries(fileMappings)) {
|
|
35357
34522
|
if (knownTokenPaths.has(path)) {
|
|
@@ -35426,16 +34591,31 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
|
|
|
35426
34591
|
const generatedCdf = Object.fromEntries(cdfEntries.map((c2) => [c2.key, c2.entry]));
|
|
35427
34592
|
const tokenTree = rebuildDTCGTree(groups, tokens);
|
|
35428
34593
|
const componentSourceRefs = await loadComponentSourceRefs(db, sessionId2);
|
|
34594
|
+
let existingTokensInline;
|
|
34595
|
+
if (opts.existingEntitiesPath) {
|
|
34596
|
+
const existingContentfulEntities = await readExistingContentfulEntitiesFromSession(
|
|
34597
|
+
resolve20(opts.existingEntitiesPath)
|
|
34598
|
+
);
|
|
34599
|
+
if (existingContentfulEntities) {
|
|
34600
|
+
existingTokensInline = JSON.stringify(summarizeForMapTokens(existingContentfulEntities));
|
|
34601
|
+
} else {
|
|
34602
|
+
process.stderr.write(
|
|
34603
|
+
`warn: --existing-entities-path ${opts.existingEntitiesPath} could not be read as JSON \u2014 proceeding without space-context enrichment
|
|
34604
|
+
`
|
|
34605
|
+
);
|
|
34606
|
+
}
|
|
34607
|
+
}
|
|
35429
34608
|
if (opts.printPrompt) {
|
|
35430
|
-
const
|
|
34609
|
+
const prompt3 = await buildPrompt({
|
|
35431
34610
|
skill: "map-tokens",
|
|
35432
34611
|
mode: "autonomous",
|
|
35433
34612
|
generatedCdf,
|
|
35434
34613
|
tokenTree,
|
|
35435
34614
|
componentSourceRefs,
|
|
35436
|
-
outDir: process.cwd()
|
|
34615
|
+
outDir: process.cwd(),
|
|
34616
|
+
existingTokensInline
|
|
35437
34617
|
});
|
|
35438
|
-
process.stdout.write(
|
|
34618
|
+
process.stdout.write(prompt3 + "\n");
|
|
35439
34619
|
await exitWithAnalytics(0);
|
|
35440
34620
|
return;
|
|
35441
34621
|
}
|
|
@@ -35451,7 +34631,13 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
|
|
|
35451
34631
|
}
|
|
35452
34632
|
const agent = configuredAgent;
|
|
35453
34633
|
const noCache = opts.cache === false || process.env.EDS_NO_CACHE === "1";
|
|
35454
|
-
const promptHash = await hashPromptForSkill(
|
|
34634
|
+
const promptHash = await hashPromptForSkill(
|
|
34635
|
+
"map-tokens",
|
|
34636
|
+
agent,
|
|
34637
|
+
model,
|
|
34638
|
+
void 0,
|
|
34639
|
+
existingTokensInline ? [hashContent(existingTokensInline)] : []
|
|
34640
|
+
);
|
|
35455
34641
|
const inputHash = computeMapTokensInputHash(db, sessionId2, componentSourceRefs);
|
|
35456
34642
|
if (!noCache) {
|
|
35457
34643
|
const cached = lookupCache(db, inputHash, "token_mapping", "__map_tokens__", promptHash);
|
|
@@ -35472,16 +34658,17 @@ Install it, choose another agent with --agent, or use --print-prompt to run the
|
|
|
35472
34658
|
);
|
|
35473
34659
|
}
|
|
35474
34660
|
const stepId = createStep(db, sessionId2, "map tokens", { agent, model: model ?? "" });
|
|
35475
|
-
const
|
|
34661
|
+
const prompt2 = await buildPrompt({
|
|
35476
34662
|
skill: "map-tokens",
|
|
35477
34663
|
mode: "autonomous",
|
|
35478
34664
|
generatedCdf,
|
|
35479
34665
|
tokenTree,
|
|
35480
34666
|
componentSourceRefs,
|
|
35481
|
-
outDir: process.cwd()
|
|
34667
|
+
outDir: process.cwd(),
|
|
34668
|
+
existingTokensInline
|
|
35482
34669
|
});
|
|
35483
34670
|
const invoker3 = createLocalCliAgentInvoker();
|
|
35484
|
-
const result = await invoker3.invoke({ agent, model, prompt, timeoutMs: DEFAULT_TIMEOUT_MS4 });
|
|
34671
|
+
const result = await invoker3.invoke({ agent, model, prompt: prompt2, timeoutMs: DEFAULT_TIMEOUT_MS4 });
|
|
35485
34672
|
if (result.timedOut || result.exitCode !== 0) {
|
|
35486
34673
|
const error = result.timedOut ? `timed out after ${DEFAULT_TIMEOUT_MS4 / 6e4} minutes` : describeAgentFailure(result);
|
|
35487
34674
|
updateStep(db, stepId, "failed", {}, error);
|
|
@@ -35505,7 +34692,10 @@ ${warnings.map((w) => ` ${w}`).join("\n")}
|
|
|
35505
34692
|
}
|
|
35506
34693
|
function registerMapTokensCommand(program) {
|
|
35507
34694
|
const map = program.command("map").description("Suggest token restrictions for generated design-token props");
|
|
35508
|
-
const tokensCmd = map.command("tokens").description("Invoke a coding agent to suggest $token.allowed for design-category token props").option("--session <id>", "Session ID from generate components (defaults to most recent)").option("--print-prompt", "Print the prompt without invoking the agent").option("--skip-agent", "Resolve token defaults without agentic $token.allowed inference").option("--no-cache", "Bypass the map-tokens cache and force a re-run").option("--token-map <path>", "Path to token-name-map.json sidecar")
|
|
34695
|
+
const tokensCmd = map.command("tokens").description("Invoke a coding agent to suggest $token.allowed for design-category token props").option("--session <id>", "Session ID from generate components (defaults to most recent)").option("--print-prompt", "Print the prompt without invoking the agent").option("--skip-agent", "Resolve token defaults without agentic $token.allowed inference").option("--no-cache", "Bypass the map-tokens cache and force a re-run").option("--token-map <path>", "Path to token-name-map.json sidecar").option(
|
|
34696
|
+
"--existing-entities-path <path>",
|
|
34697
|
+
"Path to the .existing-entities.json file written by the orchestrator when CMA credentials are supplied. When present, the agent gets a list of the space's existing design tokens so it can prefer binding to them. Missing/malformed files are treated as no-op."
|
|
34698
|
+
);
|
|
35509
34699
|
addAgentModelOptions(tokensCmd).action(async (opts) => {
|
|
35510
34700
|
await runMapTokens(opts);
|
|
35511
34701
|
});
|
|
@@ -35514,45 +34704,22 @@ function registerMapTokensCommand(program) {
|
|
|
35514
34704
|
// packages/experience-design-system-cli/src/import/command.ts
|
|
35515
34705
|
init_src();
|
|
35516
34706
|
init_path_utils();
|
|
35517
|
-
import { resolve as
|
|
34707
|
+
import { resolve as resolve26, join as join26 } from "node:path";
|
|
35518
34708
|
|
|
35519
34709
|
// packages/experience-design-system-cli/src/import/orchestrator.ts
|
|
35520
34710
|
init_db();
|
|
35521
34711
|
init_command();
|
|
35522
34712
|
init_manifest();
|
|
35523
34713
|
init_api_client();
|
|
35524
|
-
|
|
35525
|
-
import { join as join18, resolve as resolve21 } from "node:path";
|
|
35526
|
-
import { execFile as execFile2 } from "node:child_process";
|
|
35527
|
-
|
|
35528
|
-
// packages/experience-design-system-cli/src/helpers/fetch-existing-entities.ts
|
|
35529
|
-
import { fetchAll } from "contentful-management";
|
|
35530
|
-
async function fetchExistingEntities(client2, params) {
|
|
35531
|
-
const scope = { spaceId: params.spaceId, environmentId: params.environmentId, query: {} };
|
|
35532
|
-
const components = await fetchAll(client2.component.getMany, scope);
|
|
35533
|
-
const tokens = await fetchAll(client2.designToken.getMany, scope);
|
|
35534
|
-
return { components, tokens };
|
|
35535
|
-
}
|
|
35536
|
-
|
|
35537
|
-
// packages/experience-design-system-cli/src/helpers/cma-client.ts
|
|
35538
|
-
init_host_utils();
|
|
35539
|
-
import { createClient as createClient2 } from "contentful-management";
|
|
35540
|
-
function createCmaClient(opts) {
|
|
35541
|
-
return createClient2(
|
|
35542
|
-
{
|
|
35543
|
-
accessToken: opts.cmaToken,
|
|
35544
|
-
...opts.host ? { host: toConfiguredHost(opts.host) } : {}
|
|
35545
|
-
},
|
|
35546
|
-
{ type: "plain" }
|
|
35547
|
-
);
|
|
35548
|
-
}
|
|
35549
|
-
|
|
35550
|
-
// packages/experience-design-system-cli/src/import/orchestrator.ts
|
|
34714
|
+
init_fetch_and_persist_existing_contentful_entities();
|
|
35551
34715
|
init_contentful_urls();
|
|
35552
34716
|
init_debug_logger();
|
|
35553
34717
|
init_analytics();
|
|
35554
34718
|
init_env();
|
|
35555
34719
|
init_cli_path();
|
|
34720
|
+
import { mkdir as mkdir5 } from "node:fs/promises";
|
|
34721
|
+
import { join as join19, resolve as resolve22 } from "node:path";
|
|
34722
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
35556
34723
|
async function runStep(args, cliPath, analyticsSessionId, env = {}, streamStderr = false) {
|
|
35557
34724
|
const debug = getDebugLogger();
|
|
35558
34725
|
const startedAt = Date.now();
|
|
@@ -35637,9 +34804,9 @@ function buildPushStepResult(args) {
|
|
|
35637
34804
|
};
|
|
35638
34805
|
}
|
|
35639
34806
|
async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
35640
|
-
const projectRoot =
|
|
35641
|
-
const outDir =
|
|
35642
|
-
const componentsPath =
|
|
34807
|
+
const projectRoot = resolve22(opts.project);
|
|
34808
|
+
const outDir = resolve22(opts.out);
|
|
34809
|
+
const componentsPath = join19(outDir, "components.json");
|
|
35643
34810
|
const cliPath = cliPathOverride ?? findCliPath();
|
|
35644
34811
|
const db = openPipelineDb();
|
|
35645
34812
|
const { sessionId: sessionId2 } = getOrCreateSession(db, void 0, void 0, {
|
|
@@ -35660,67 +34827,56 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
35660
34827
|
await mkdir5(outDir, { recursive: true });
|
|
35661
34828
|
const steps = [];
|
|
35662
34829
|
let stepNum = 0;
|
|
35663
|
-
const
|
|
35664
|
-
const
|
|
35665
|
-
const totalSteps = 5 + (opts.print ? 1 : 0) + (canFetchSpaceContext ? 1 : 0);
|
|
34830
|
+
const canFetchExistingContentfulEntities = !!opts.spaceId && !!opts.environmentId && !!opts.cmaToken;
|
|
34831
|
+
const totalSteps = 5 + (opts.print ? 1 : 0) + (canFetchExistingContentfulEntities ? 1 : 0);
|
|
35666
34832
|
function stepLabel(name) {
|
|
35667
34833
|
stepNum++;
|
|
35668
34834
|
return ` Step ${stepNum}/${totalSteps} ${name} `;
|
|
35669
34835
|
}
|
|
35670
|
-
|
|
35671
|
-
|
|
35672
|
-
" Note: --with-space-context requires --space-id, --environment-id, and --cma-token; skipping context fetch."
|
|
35673
|
-
);
|
|
35674
|
-
}
|
|
35675
|
-
if (canFetchSpaceContext) {
|
|
34836
|
+
let existingEntitiesPath;
|
|
34837
|
+
if (canFetchExistingContentfulEntities) {
|
|
35676
34838
|
const fetchLabel = stepLabel("Fetching existing components + design tokens");
|
|
35677
34839
|
const fetchStepId = createStep(db, sessionId2, "fetch existing entities", {
|
|
35678
34840
|
spaceId: opts.spaceId,
|
|
35679
34841
|
environmentId: opts.environmentId
|
|
35680
34842
|
});
|
|
35681
|
-
const
|
|
35682
|
-
|
|
35683
|
-
|
|
35684
|
-
|
|
35685
|
-
|
|
35686
|
-
|
|
35687
|
-
|
|
35688
|
-
|
|
35689
|
-
|
|
35690
|
-
});
|
|
35691
|
-
const fetchDurationMs = Date.now() - t0;
|
|
35692
|
-
const existingEntitiesPath = join18(outDir, ".existing-entities.json");
|
|
35693
|
-
await writeFile5(existingEntitiesPath, JSON.stringify(existingComponentsAndTokens, null, 2), "utf8");
|
|
34843
|
+
const result = await fetchAndPersistExistingContentfulEntities({
|
|
34844
|
+
spaceId: opts.spaceId,
|
|
34845
|
+
environmentId: opts.environmentId,
|
|
34846
|
+
cmaToken: opts.cmaToken,
|
|
34847
|
+
...opts.host ? { host: opts.host } : {},
|
|
34848
|
+
outDir
|
|
34849
|
+
});
|
|
34850
|
+
if (result.ok) {
|
|
34851
|
+
existingEntitiesPath = result.path;
|
|
35694
34852
|
updateStep(db, fetchStepId, "complete", {
|
|
35695
|
-
components: String(
|
|
35696
|
-
tokens: String(
|
|
35697
|
-
path:
|
|
34853
|
+
components: String(result.entities.components.length),
|
|
34854
|
+
tokens: String(result.entities.tokens.length),
|
|
34855
|
+
path: result.path
|
|
35698
34856
|
});
|
|
35699
34857
|
progressWriter(
|
|
35700
|
-
`${fetchLabel}\u2713 ${
|
|
34858
|
+
`${fetchLabel}\u2713 ${result.entities.components.length} component${result.entities.components.length === 1 ? "" : "s"}, ${result.entities.tokens.length} token${result.entities.tokens.length === 1 ? "" : "s"} (${(result.durationMs / 1e3).toFixed(1)}s)`
|
|
35701
34859
|
);
|
|
35702
34860
|
steps.push({
|
|
35703
34861
|
step: "fetch existing entities",
|
|
35704
34862
|
status: "complete",
|
|
35705
|
-
durationMs:
|
|
34863
|
+
durationMs: result.durationMs,
|
|
35706
34864
|
detail: {
|
|
35707
|
-
components:
|
|
35708
|
-
tokens:
|
|
34865
|
+
components: result.entities.components.length,
|
|
34866
|
+
tokens: result.entities.tokens.length
|
|
35709
34867
|
}
|
|
35710
34868
|
});
|
|
35711
|
-
}
|
|
35712
|
-
|
|
35713
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
35714
|
-
updateStep(db, fetchStepId, "complete", {}, message);
|
|
34869
|
+
} else {
|
|
34870
|
+
updateStep(db, fetchStepId, "complete", {}, result.error);
|
|
35715
34871
|
progressWriter(
|
|
35716
|
-
`${fetchLabel}\u26A0 fetch failed, continuing without space context (${(
|
|
34872
|
+
`${fetchLabel}\u26A0 fetch failed, continuing without space context (${(result.durationMs / 1e3).toFixed(1)}s)`
|
|
35717
34873
|
);
|
|
35718
|
-
progressWriter(` ${
|
|
34874
|
+
progressWriter(` ${result.error.split("\n")[0]}`);
|
|
35719
34875
|
steps.push({
|
|
35720
34876
|
step: "fetch existing entities",
|
|
35721
34877
|
status: "skipped",
|
|
35722
|
-
durationMs:
|
|
35723
|
-
reason: `fetch failed: ${
|
|
34878
|
+
durationMs: result.durationMs,
|
|
34879
|
+
reason: `fetch failed: ${result.error.split("\n")[0]}`
|
|
35724
34880
|
});
|
|
35725
34881
|
}
|
|
35726
34882
|
}
|
|
@@ -35806,6 +34962,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
35806
34962
|
if (opts.excludeInvalid) editArgs.push("--exclude-invalid");
|
|
35807
34963
|
if (opts.noCache) editArgs.push("--no-cache");
|
|
35808
34964
|
if (opts.selectPromptPath) editArgs.push("--select-prompt-path", opts.selectPromptPath);
|
|
34965
|
+
if (existingEntitiesPath) editArgs.push("--existing-entities-path", existingEntitiesPath);
|
|
35809
34966
|
} else {
|
|
35810
34967
|
editArgs = ["analyze", "select", "--session", extractSessionId];
|
|
35811
34968
|
if (opts.select && opts.select.length > 0) {
|
|
@@ -35868,6 +35025,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
35868
35025
|
if (extractSessionId) generateArgs.push("--session", extractSessionId);
|
|
35869
35026
|
if (opts.dryRun) generateArgs.push("--dry-run");
|
|
35870
35027
|
if (opts.verbose) generateArgs.push("--verbose");
|
|
35028
|
+
if (existingEntitiesPath) generateArgs.push("--existing-entities-path", existingEntitiesPath);
|
|
35871
35029
|
const stepId = createStep(db, sessionId2, "generate components", {
|
|
35872
35030
|
extractSession: extractSessionId ?? ""
|
|
35873
35031
|
});
|
|
@@ -35922,6 +35080,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
35922
35080
|
if (opts.model) mapTokensArgs.push("--model", opts.model);
|
|
35923
35081
|
if (opts.noCache) mapTokensArgs.push("--no-cache");
|
|
35924
35082
|
if (opts.skipMapTokens) mapTokensArgs.push("--skip-agent");
|
|
35083
|
+
if (existingEntitiesPath) mapTokensArgs.push("--existing-entities-path", existingEntitiesPath);
|
|
35925
35084
|
const mapTokensStepId = createStep(db, sessionId2, "map tokens", {
|
|
35926
35085
|
extractSession: extractSessionId,
|
|
35927
35086
|
skipAgent: String(opts.skipMapTokens === true)
|
|
@@ -36283,7 +35442,7 @@ init_host_utils();
|
|
|
36283
35442
|
// packages/experience-design-system-cli/src/runs/replay-helpers.ts
|
|
36284
35443
|
init_resolve_run_target();
|
|
36285
35444
|
init_store();
|
|
36286
|
-
import { resolve as
|
|
35445
|
+
import { resolve as resolve25 } from "node:path";
|
|
36287
35446
|
|
|
36288
35447
|
// packages/experience-design-system-cli/src/runs/push-helpers.ts
|
|
36289
35448
|
init_cli_path();
|
|
@@ -36390,7 +35549,7 @@ async function replayRun(opts) {
|
|
|
36390
35549
|
if (!opts.interactive) {
|
|
36391
35550
|
throw new Error(MISSING_CREDS_ERROR);
|
|
36392
35551
|
}
|
|
36393
|
-
const
|
|
35552
|
+
const prompt2 = opts.promptForCredentials ?? (async (need) => {
|
|
36394
35553
|
const { promptForPushCredentials: promptForPushCredentials2 } = await Promise.resolve().then(() => (init_push_creds_prompt(), push_creds_prompt_exports));
|
|
36395
35554
|
return promptForPushCredentials2({
|
|
36396
35555
|
...need.spaceId ? { initialSpaceId: need.spaceId } : {},
|
|
@@ -36400,7 +35559,7 @@ async function replayRun(opts) {
|
|
|
36400
35559
|
summary: `Push run ${run.id} \u2192 enter credentials. Defaults reflect the run record and your saved setup.`
|
|
36401
35560
|
});
|
|
36402
35561
|
});
|
|
36403
|
-
const collected = await
|
|
35562
|
+
const collected = await prompt2({
|
|
36404
35563
|
spaceId,
|
|
36405
35564
|
environmentId,
|
|
36406
35565
|
cmaToken,
|
|
@@ -36473,7 +35632,7 @@ async function modifyRun(opts) {
|
|
|
36473
35632
|
entryStep: "final-review",
|
|
36474
35633
|
saveMode,
|
|
36475
35634
|
...run.compositionMode ? { compositionMode: run.compositionMode } : {},
|
|
36476
|
-
...opts.outDir ? { outDirOverride:
|
|
35635
|
+
...opts.outDir ? { outDirOverride: resolve25(opts.outDir) } : {},
|
|
36477
35636
|
...mergedSpaceId ? { initialSpaceId: mergedSpaceId } : {},
|
|
36478
35637
|
...mergedEnvironmentId ? { initialEnvironmentId: mergedEnvironmentId } : {},
|
|
36479
35638
|
...mergedHost ? { initialHost: mergedHost } : {},
|
|
@@ -36550,7 +35709,7 @@ function resolvePromptFlags(flags) {
|
|
|
36550
35709
|
|
|
36551
35710
|
// packages/experience-design-system-cli/src/runs/run-picker-mount.ts
|
|
36552
35711
|
init_store();
|
|
36553
|
-
import { readFile as
|
|
35712
|
+
import { readFile as readFile27 } from "node:fs/promises";
|
|
36554
35713
|
function migrateRecord2(rec) {
|
|
36555
35714
|
return {
|
|
36556
35715
|
...rec,
|
|
@@ -36573,7 +35732,7 @@ async function shouldShowRunPicker(input) {
|
|
|
36573
35732
|
const path = input.runsJsonPath ?? runsFilePath();
|
|
36574
35733
|
let raw;
|
|
36575
35734
|
try {
|
|
36576
|
-
raw = await
|
|
35735
|
+
raw = await readFile27(path, "utf8");
|
|
36577
35736
|
} catch {
|
|
36578
35737
|
return { shouldShow: false, runs: [] };
|
|
36579
35738
|
}
|
|
@@ -36678,10 +35837,7 @@ function registerImportCommand(program) {
|
|
|
36678
35837
|
"Override a stage prompt (repeatable). value is a file path or literal text, e.g. --prompt composition=./p.md",
|
|
36679
35838
|
(v, acc) => [...acc, v],
|
|
36680
35839
|
[]
|
|
36681
|
-
).option("--auto-reject-cycles", "Automatically reject components involved in slot cycles and retry").option(
|
|
36682
|
-
"--with-space-context",
|
|
36683
|
-
"Fetch existing Components + DesignTokens from the target space+env and persist them under <out>/.existing-entities.json for future agent-context enrichment. Requires --space-id, --environment-id, and --cma-token."
|
|
36684
|
-
).option("--auto-filter", "Force the AI auto-filter ON (overrides the credentials.json autoFilter preference)").option(
|
|
35840
|
+
).option("--auto-reject-cycles", "Automatically reject components involved in slot cycles and retry").option("--auto-filter", "Force the AI auto-filter ON (overrides the credentials.json autoFilter preference)").option(
|
|
36685
35841
|
"--no-auto-filter",
|
|
36686
35842
|
"Skip the automatic AI pre-filter; jump straight to manual scope-gate (overrides the credentials.json autoFilter preference; no-op when paired with --auto-accept-scope)"
|
|
36687
35843
|
).option(
|
|
@@ -36949,7 +36105,7 @@ function registerImportCommand(program) {
|
|
|
36949
36105
|
livePreview: opts.livePreview !== false,
|
|
36950
36106
|
noPush: noPushRequested,
|
|
36951
36107
|
noSave: opts.save === false,
|
|
36952
|
-
...opts.outDir ? { outDirOverride:
|
|
36108
|
+
...opts.outDir ? { outDirOverride: resolve26(opts.outDir) } : {},
|
|
36953
36109
|
...opts.onConflict ? { onConflictMode: opts.onConflict } : {},
|
|
36954
36110
|
selectPromptPath: opts.selectPromptPath ?? creds.selectPromptPath,
|
|
36955
36111
|
generatePromptPath: opts.generatePromptPath ?? creds.generatePromptPath,
|
|
@@ -36990,7 +36146,7 @@ function registerImportCommand(program) {
|
|
|
36990
36146
|
return;
|
|
36991
36147
|
}
|
|
36992
36148
|
const projectRoot = normalizePath(opts.project);
|
|
36993
|
-
const outDir = opts.out ?
|
|
36149
|
+
const outDir = opts.out ? resolve26(opts.out) : join26(projectRoot, ".contentful");
|
|
36994
36150
|
const headlessCreds = await readExperiencesCredentials();
|
|
36995
36151
|
const headlessAgent = resolveAgent(opts.agent, headlessCreds.agent);
|
|
36996
36152
|
const headlessModel = resolveModel(opts.model, headlessCreds.agentModel);
|
|
@@ -37028,7 +36184,6 @@ function registerImportCommand(program) {
|
|
|
37028
36184
|
dryRun: dryRunForward,
|
|
37029
36185
|
selectPromptPath: opts.selectPromptPath,
|
|
37030
36186
|
autoRejectCycles: opts.autoRejectCycles ?? false,
|
|
37031
|
-
withSpaceContext: opts.withSpaceContext ?? false,
|
|
37032
36187
|
allowDeletions: opts.allowDeletions ?? false,
|
|
37033
36188
|
compositionMode: headlessCompositionMode,
|
|
37034
36189
|
...opts.compositionMap ? { compositionMap: opts.compositionMap } : {},
|
|
@@ -37050,18 +36205,54 @@ function registerImportCommand(program) {
|
|
|
37050
36205
|
);
|
|
37051
36206
|
}
|
|
37052
36207
|
|
|
37053
|
-
// packages/experience-design-system-cli/src/
|
|
37054
|
-
init_cli_path();
|
|
37055
|
-
|
|
37056
|
-
// packages/experience-design-system-cli/src/doctor/checks.ts
|
|
36208
|
+
// packages/experience-design-system-cli/src/setup/command.ts
|
|
37057
36209
|
init_credentials_store();
|
|
37058
|
-
|
|
37059
|
-
|
|
37060
|
-
|
|
37061
|
-
import { homedir as
|
|
37062
|
-
import {
|
|
36210
|
+
import { execFile as execFile5, spawn as spawn5 } from "node:child_process";
|
|
36211
|
+
import { appendFile as appendFile2, readFile as readFile28, access as access10 } from "node:fs/promises";
|
|
36212
|
+
import { join as join27 } from "node:path";
|
|
36213
|
+
import { homedir as homedir9 } from "node:os";
|
|
36214
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
36215
|
+
import { createInterface } from "node:readline";
|
|
36216
|
+
import { promisify as promisify2 } from "node:util";
|
|
36217
|
+
|
|
36218
|
+
// packages/experience-design-system-cli/src/setup/auto-filter-prompt.ts
|
|
36219
|
+
async function promptAutoFilterPreference(ask, current) {
|
|
36220
|
+
const defaultValue = current ?? true;
|
|
36221
|
+
const hint = defaultValue ? "[Y/n]" : "[y/N]";
|
|
36222
|
+
const answer = (await ask(` Enable AI auto-filter by default? ${hint} `)).trim().toLowerCase();
|
|
36223
|
+
if (answer === "") return defaultValue;
|
|
36224
|
+
if (answer.startsWith("y")) return true;
|
|
36225
|
+
if (answer.startsWith("n")) return false;
|
|
36226
|
+
return defaultValue;
|
|
36227
|
+
}
|
|
36228
|
+
|
|
36229
|
+
// packages/experience-design-system-cli/src/setup/debug-mode-prompt.ts
|
|
36230
|
+
async function promptDebugModePreference(ask, current) {
|
|
36231
|
+
const defaultValue = current ?? false;
|
|
36232
|
+
const hint = defaultValue ? "[Y/n]" : "[y/N]";
|
|
36233
|
+
const answer = (await ask(` Enable debug logging by default? ${hint} `)).trim().toLowerCase();
|
|
36234
|
+
if (answer === "") return defaultValue;
|
|
36235
|
+
if (answer.startsWith("y")) return true;
|
|
36236
|
+
if (answer.startsWith("n")) return false;
|
|
36237
|
+
return defaultValue;
|
|
36238
|
+
}
|
|
37063
36239
|
|
|
37064
|
-
// packages/experience-design-system-cli/src/
|
|
36240
|
+
// packages/experience-design-system-cli/src/setup/analytics-prompt.ts
|
|
36241
|
+
async function promptAnalyticsPreference(ask, current) {
|
|
36242
|
+
const defaultValue = current ?? false;
|
|
36243
|
+
const hint = defaultValue ? "[Y/n]" : "[y/N]";
|
|
36244
|
+
const answer = (await ask(` Disable anonymous usage analytics? ${hint} `)).trim().toLowerCase();
|
|
36245
|
+
if (answer === "") return defaultValue;
|
|
36246
|
+
if (answer.startsWith("y")) return true;
|
|
36247
|
+
if (answer.startsWith("n")) return false;
|
|
36248
|
+
return defaultValue;
|
|
36249
|
+
}
|
|
36250
|
+
|
|
36251
|
+
// packages/experience-design-system-cli/src/setup/command.ts
|
|
36252
|
+
init_host_utils();
|
|
36253
|
+
init_cli_path();
|
|
36254
|
+
var execFileAsync2 = promisify2(execFile5);
|
|
36255
|
+
var REQUIRED_NODE_MAJOR = 24;
|
|
37065
36256
|
function ok(msg) {
|
|
37066
36257
|
process.stdout.write(` \x1B[32m\u2713\x1B[0m ${msg}
|
|
37067
36258
|
`);
|
|
@@ -37078,56 +36269,618 @@ function info(msg) {
|
|
|
37078
36269
|
process.stdout.write(` ${msg}
|
|
37079
36270
|
`);
|
|
37080
36271
|
}
|
|
37081
|
-
function section(title) {
|
|
36272
|
+
function section(title, tag) {
|
|
36273
|
+
const tagStr = tag ? tag === "[required]" ? ` \x1B[31m[required]\x1B[0m` : ` \x1B[2m[optional]\x1B[0m` : "";
|
|
37082
36274
|
process.stdout.write(`
|
|
37083
|
-
\x1B[1m${title}\x1B[0m
|
|
36275
|
+
\x1B[1m${title}\x1B[0m${tagStr}
|
|
36276
|
+
`);
|
|
36277
|
+
}
|
|
36278
|
+
function dim(msg) {
|
|
36279
|
+
process.stdout.write(`\x1B[2m${msg}\x1B[0m
|
|
37084
36280
|
`);
|
|
37085
36281
|
}
|
|
37086
|
-
function
|
|
37087
|
-
|
|
36282
|
+
function isInteractivePromptSession() {
|
|
36283
|
+
return !!(process.stdin.isTTY && process.stdout.isTTY);
|
|
37088
36284
|
}
|
|
37089
|
-
|
|
37090
|
-
|
|
37091
|
-
|
|
37092
|
-
|
|
37093
|
-
const
|
|
37094
|
-
|
|
37095
|
-
|
|
36285
|
+
function prompt(question) {
|
|
36286
|
+
if (!isInteractivePromptSession()) {
|
|
36287
|
+
return Promise.resolve("");
|
|
36288
|
+
}
|
|
36289
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
36290
|
+
return new Promise((resolve28) => {
|
|
36291
|
+
rl.question(question, (answer) => {
|
|
36292
|
+
rl.close();
|
|
36293
|
+
resolve28(answer.trim());
|
|
36294
|
+
});
|
|
36295
|
+
});
|
|
36296
|
+
}
|
|
36297
|
+
function promptSecret(question) {
|
|
36298
|
+
if (!isInteractivePromptSession()) {
|
|
36299
|
+
return Promise.resolve("");
|
|
36300
|
+
}
|
|
36301
|
+
return new Promise((resolve28) => {
|
|
36302
|
+
const rl = createInterface({
|
|
36303
|
+
input: process.stdin,
|
|
36304
|
+
output: process.stdout,
|
|
36305
|
+
terminal: process.stdin.isTTY
|
|
36306
|
+
});
|
|
36307
|
+
let value = "";
|
|
36308
|
+
process.stdout.write(question);
|
|
36309
|
+
let origWrite = null;
|
|
36310
|
+
if (process.stdin.isTTY) {
|
|
36311
|
+
origWrite = rl.output.write.bind(
|
|
36312
|
+
rl.output
|
|
36313
|
+
);
|
|
36314
|
+
rl.output.write = (s) => {
|
|
36315
|
+
if (s === "\r\n" || s === "\n" || s === "\r") origWrite(s);
|
|
36316
|
+
};
|
|
36317
|
+
}
|
|
36318
|
+
rl.on("line", (line) => {
|
|
36319
|
+
value = line;
|
|
36320
|
+
rl.close();
|
|
36321
|
+
});
|
|
36322
|
+
rl.once("close", () => {
|
|
36323
|
+
if (origWrite) {
|
|
36324
|
+
rl.output.write = origWrite;
|
|
36325
|
+
}
|
|
36326
|
+
if (!process.stdin.isTTY) process.stdout.write("\n");
|
|
36327
|
+
process.stdin.resume();
|
|
36328
|
+
resolve28(value);
|
|
36329
|
+
});
|
|
36330
|
+
});
|
|
36331
|
+
}
|
|
36332
|
+
async function confirm(question, defaultYes = true) {
|
|
36333
|
+
if (!isInteractivePromptSession()) {
|
|
36334
|
+
return false;
|
|
36335
|
+
}
|
|
36336
|
+
const hint = defaultYes ? "[Y/n]" : "[y/N]";
|
|
36337
|
+
const answer = await prompt(` ${question} ${hint} `);
|
|
36338
|
+
if (!answer) return defaultYes;
|
|
36339
|
+
return answer.toLowerCase().startsWith("y");
|
|
36340
|
+
}
|
|
36341
|
+
async function binaryExists(name) {
|
|
36342
|
+
try {
|
|
36343
|
+
await execFileAsync2("which", [name]);
|
|
37096
36344
|
return true;
|
|
36345
|
+
} catch {
|
|
36346
|
+
return false;
|
|
36347
|
+
}
|
|
36348
|
+
}
|
|
36349
|
+
function runSpawn(cmd, args, opts = {}) {
|
|
36350
|
+
return new Promise((resolve28) => {
|
|
36351
|
+
const child = spawn5(cmd, args, {
|
|
36352
|
+
cwd: opts.cwd,
|
|
36353
|
+
env: opts.env ?? process.env,
|
|
36354
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
36355
|
+
});
|
|
36356
|
+
let settled = false;
|
|
36357
|
+
let stdout = "";
|
|
36358
|
+
let stderr = "";
|
|
36359
|
+
child.on("error", (err) => {
|
|
36360
|
+
if (!settled) {
|
|
36361
|
+
settled = true;
|
|
36362
|
+
resolve28({ exitCode: 1, stdout: "", stderr: err.message });
|
|
36363
|
+
}
|
|
36364
|
+
});
|
|
36365
|
+
child.stdout.on("data", (d) => {
|
|
36366
|
+
stdout += String(d);
|
|
36367
|
+
});
|
|
36368
|
+
child.stderr.on("data", (d) => {
|
|
36369
|
+
stderr += String(d);
|
|
36370
|
+
});
|
|
36371
|
+
child.on("exit", (code) => {
|
|
36372
|
+
if (!settled) {
|
|
36373
|
+
settled = true;
|
|
36374
|
+
resolve28({ exitCode: code ?? 1, stdout, stderr });
|
|
36375
|
+
}
|
|
36376
|
+
});
|
|
36377
|
+
});
|
|
36378
|
+
}
|
|
36379
|
+
async function detectShellProfile() {
|
|
36380
|
+
const shell = process.env["SHELL"] ?? "";
|
|
36381
|
+
const home = homedir9();
|
|
36382
|
+
if (shell.includes("zsh")) {
|
|
36383
|
+
return join27(home, ".zshrc");
|
|
36384
|
+
}
|
|
36385
|
+
if (shell.includes("bash")) {
|
|
36386
|
+
const bashProfile = join27(home, ".bash_profile");
|
|
36387
|
+
const exists = await access10(bashProfile).then(() => true).catch(() => false);
|
|
36388
|
+
return exists ? bashProfile : join27(home, ".bashrc");
|
|
37097
36389
|
}
|
|
37098
|
-
|
|
36390
|
+
if (shell.includes("fish")) {
|
|
36391
|
+
return join27(home, ".config", "fish", "config.fish");
|
|
36392
|
+
}
|
|
36393
|
+
return join27(home, ".profile");
|
|
36394
|
+
}
|
|
36395
|
+
async function profileContains(profilePath, str) {
|
|
36396
|
+
try {
|
|
36397
|
+
const content = await readFile28(profilePath, "utf8");
|
|
36398
|
+
return content.includes(str);
|
|
36399
|
+
} catch {
|
|
36400
|
+
return false;
|
|
36401
|
+
}
|
|
36402
|
+
}
|
|
36403
|
+
async function appendToProfile(profilePath, lines) {
|
|
36404
|
+
await appendFile2(profilePath, `
|
|
36405
|
+
${lines}
|
|
36406
|
+
`, "utf8");
|
|
36407
|
+
}
|
|
36408
|
+
async function setupNode() {
|
|
36409
|
+
section("Step 1: Node.js", "[required]");
|
|
36410
|
+
const current = process.versions.node;
|
|
36411
|
+
const major = parseInt(current.split(".")[0], 10);
|
|
36412
|
+
if (major >= REQUIRED_NODE_MAJOR) {
|
|
36413
|
+
ok(`Node.js v${current} \u2014 already good`);
|
|
36414
|
+
return true;
|
|
36415
|
+
}
|
|
36416
|
+
fail(`Node.js v${current} \u2014 need v${REQUIRED_NODE_MAJOR}+`);
|
|
37099
36417
|
info("");
|
|
37100
|
-
|
|
37101
|
-
const
|
|
37102
|
-
if (
|
|
37103
|
-
info(`
|
|
37104
|
-
|
|
37105
|
-
|
|
37106
|
-
|
|
37107
|
-
|
|
37108
|
-
|
|
37109
|
-
|
|
37110
|
-
|
|
36418
|
+
const hasNvm = await binaryExists("nvm") || await access10(join27(homedir9(), ".nvm", "nvm.sh")).then(() => true).catch(() => false);
|
|
36419
|
+
const hasFnm = await binaryExists("fnm");
|
|
36420
|
+
if (hasNvm) {
|
|
36421
|
+
info(`nvm detected. Will run: nvm install ${REQUIRED_NODE_MAJOR} && nvm use ${REQUIRED_NODE_MAJOR}`);
|
|
36422
|
+
const go = await confirm(`Install and switch to Node ${REQUIRED_NODE_MAJOR} via nvm?`);
|
|
36423
|
+
if (!go) {
|
|
36424
|
+
warn(`Skipped. Re-run experiences setup after switching to Node ${REQUIRED_NODE_MAJOR}.`);
|
|
36425
|
+
return false;
|
|
36426
|
+
}
|
|
36427
|
+
const nvmScript = join27(homedir9(), ".nvm", "nvm.sh");
|
|
36428
|
+
const result = await runSpawn("bash", [
|
|
36429
|
+
"-c",
|
|
36430
|
+
`source "${nvmScript}" && nvm install ${REQUIRED_NODE_MAJOR} && nvm alias default ${REQUIRED_NODE_MAJOR}`
|
|
36431
|
+
]);
|
|
36432
|
+
if (result.exitCode !== 0) {
|
|
36433
|
+
fail("nvm install failed");
|
|
36434
|
+
info(result.stderr.trim().split("\n").slice(0, 5).join("\n"));
|
|
36435
|
+
info(`Run manually: nvm install ${REQUIRED_NODE_MAJOR} && nvm use ${REQUIRED_NODE_MAJOR}`);
|
|
36436
|
+
return false;
|
|
36437
|
+
}
|
|
36438
|
+
ok(`Node ${REQUIRED_NODE_MAJOR} installed via nvm. Re-run experiences setup in a fresh shell to pick it up.`);
|
|
36439
|
+
return false;
|
|
36440
|
+
}
|
|
36441
|
+
if (hasFnm) {
|
|
36442
|
+
info(`fnm detected. Will run: fnm install ${REQUIRED_NODE_MAJOR} && fnm use ${REQUIRED_NODE_MAJOR}`);
|
|
36443
|
+
const go = await confirm(`Install and switch to Node ${REQUIRED_NODE_MAJOR} via fnm?`);
|
|
36444
|
+
if (!go) {
|
|
36445
|
+
warn(`Skipped. Re-run experiences setup after switching to Node ${REQUIRED_NODE_MAJOR}.`);
|
|
36446
|
+
return false;
|
|
36447
|
+
}
|
|
36448
|
+
const result = await runSpawn("fnm", ["install", String(REQUIRED_NODE_MAJOR)]);
|
|
36449
|
+
if (result.exitCode !== 0) {
|
|
36450
|
+
fail("fnm install failed");
|
|
36451
|
+
info(`Run manually: fnm install ${REQUIRED_NODE_MAJOR} && fnm use ${REQUIRED_NODE_MAJOR}`);
|
|
36452
|
+
return false;
|
|
36453
|
+
}
|
|
36454
|
+
const useResult = await runSpawn("fnm", ["use", String(REQUIRED_NODE_MAJOR)]);
|
|
36455
|
+
if (useResult.exitCode !== 0) {
|
|
36456
|
+
warn(`fnm use ${REQUIRED_NODE_MAJOR} failed \u2014 node installed but not activated`);
|
|
36457
|
+
info(`Run manually: fnm use ${REQUIRED_NODE_MAJOR} && fnm default ${REQUIRED_NODE_MAJOR}`);
|
|
36458
|
+
} else {
|
|
36459
|
+
const defaultResult = await runSpawn("fnm", ["default", String(REQUIRED_NODE_MAJOR)]);
|
|
36460
|
+
if (defaultResult.exitCode !== 0) {
|
|
36461
|
+
warn(`fnm default ${REQUIRED_NODE_MAJOR} failed \u2014 version won't persist across new shells`);
|
|
36462
|
+
info(`Run manually: fnm default ${REQUIRED_NODE_MAJOR}`);
|
|
36463
|
+
}
|
|
36464
|
+
}
|
|
36465
|
+
ok(`Node ${REQUIRED_NODE_MAJOR} installed via fnm. Re-run experiences setup in a fresh shell.`);
|
|
36466
|
+
return false;
|
|
36467
|
+
}
|
|
36468
|
+
info("No Node version manager detected (nvm or fnm).");
|
|
36469
|
+
const installNvm = await confirm("Install nvm now? (recommended)");
|
|
36470
|
+
if (installNvm) {
|
|
36471
|
+
info("Running nvm install script...");
|
|
36472
|
+
const result = await runSpawn("bash", [
|
|
36473
|
+
"-c",
|
|
36474
|
+
"curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash"
|
|
36475
|
+
]);
|
|
36476
|
+
if (result.exitCode !== 0) {
|
|
36477
|
+
fail("nvm install failed");
|
|
36478
|
+
info("Install manually: https://github.com/nvm-sh/nvm#installing-and-updating");
|
|
36479
|
+
return false;
|
|
36480
|
+
}
|
|
36481
|
+
ok("nvm installed. Open a new shell, then re-run experiences setup.");
|
|
36482
|
+
return false;
|
|
37111
36483
|
}
|
|
36484
|
+
info(`Install Node ${REQUIRED_NODE_MAJOR} manually from https://nodejs.org`);
|
|
37112
36485
|
return false;
|
|
37113
36486
|
}
|
|
37114
|
-
async function
|
|
36487
|
+
async function setupPnpm() {
|
|
36488
|
+
section("Step 2: pnpm", "[required]");
|
|
36489
|
+
if (await binaryExists("pnpm")) {
|
|
36490
|
+
const v = await runSpawn("pnpm", ["--version"]);
|
|
36491
|
+
ok(`pnpm v${v.stdout.trim()} \u2014 already installed`);
|
|
36492
|
+
return true;
|
|
36493
|
+
}
|
|
36494
|
+
fail("pnpm not found");
|
|
36495
|
+
info("");
|
|
36496
|
+
const hasCorecpack = await binaryExists("corepack");
|
|
36497
|
+
if (hasCorecpack) {
|
|
36498
|
+
info("Will run: corepack enable && corepack prepare pnpm@latest --activate");
|
|
36499
|
+
const go2 = await confirm("Install pnpm via corepack?");
|
|
36500
|
+
if (go2) {
|
|
36501
|
+
const r1 = await runSpawn("corepack", ["enable"]);
|
|
36502
|
+
const r2 = r1.exitCode === 0 ? await runSpawn("corepack", ["prepare", "pnpm@latest", "--activate"]) : r1;
|
|
36503
|
+
if (r2.exitCode !== 0) {
|
|
36504
|
+
fail("corepack install failed");
|
|
36505
|
+
info("Try: npm install -g pnpm");
|
|
36506
|
+
return false;
|
|
36507
|
+
}
|
|
36508
|
+
ok("pnpm installed via corepack");
|
|
36509
|
+
return true;
|
|
36510
|
+
}
|
|
36511
|
+
}
|
|
36512
|
+
info("Will run: npm install -g pnpm");
|
|
36513
|
+
const go = await confirm("Install pnpm via npm?");
|
|
36514
|
+
if (!go) {
|
|
36515
|
+
warn("Skipped. Install pnpm manually: npm install -g pnpm");
|
|
36516
|
+
return false;
|
|
36517
|
+
}
|
|
36518
|
+
const result = await runSpawn("npm", ["install", "-g", "pnpm"]);
|
|
36519
|
+
if (result.exitCode !== 0) {
|
|
36520
|
+
fail("npm install -g pnpm failed");
|
|
36521
|
+
info(result.stderr.trim().split("\n").slice(0, 5).join("\n"));
|
|
36522
|
+
return false;
|
|
36523
|
+
}
|
|
36524
|
+
ok("pnpm installed");
|
|
36525
|
+
return true;
|
|
36526
|
+
}
|
|
36527
|
+
async function setupBuild(repoRoot) {
|
|
36528
|
+
section("Step 3: Install dependencies & build", "[required]");
|
|
36529
|
+
info("Running pnpm install...");
|
|
36530
|
+
const installResult = await runSpawn("pnpm", ["install", "--frozen-lockfile"], { cwd: repoRoot });
|
|
36531
|
+
if (installResult.exitCode !== 0) {
|
|
36532
|
+
fail("pnpm install failed");
|
|
36533
|
+
const errLines = installResult.stderr.trim().split("\n").slice(0, 8);
|
|
36534
|
+
for (const line of errLines) info(line);
|
|
36535
|
+
info("");
|
|
36536
|
+
info("Try: pnpm install (without --frozen-lockfile) to update the lockfile");
|
|
36537
|
+
return false;
|
|
36538
|
+
}
|
|
36539
|
+
ok("Dependencies installed");
|
|
36540
|
+
info("Building CLI...");
|
|
36541
|
+
const buildResult = await runSpawn("pnpm", ["--filter", "@contentful/experience-design-system-cli", "run", "build"], {
|
|
36542
|
+
cwd: repoRoot
|
|
36543
|
+
});
|
|
36544
|
+
if (buildResult.exitCode !== 0) {
|
|
36545
|
+
fail("Build failed");
|
|
36546
|
+
const errLines = buildResult.stderr.trim().split("\n").slice(0, 10);
|
|
36547
|
+
for (const line of errLines) info(line);
|
|
36548
|
+
return false;
|
|
36549
|
+
}
|
|
36550
|
+
ok("CLI built successfully");
|
|
36551
|
+
return true;
|
|
36552
|
+
}
|
|
36553
|
+
var AGENT_DEFS = [
|
|
36554
|
+
{ name: "Claude Code", binary: "claude", installHint: "npm install -g @anthropic-ai/claude-code && claude login" },
|
|
36555
|
+
{ name: "OpenAI Codex", binary: "codex", installHint: "npm install -g @openai/codex (requires OPENAI_API_KEY)" },
|
|
36556
|
+
{ name: "OpenCode", binary: "opencode", installHint: "npm install -g opencode-ai && opencode auth" },
|
|
36557
|
+
{ name: "GitHub Copilot", binary: "copilot", installHint: "npm install -g @github/copilot && copilot" }
|
|
36558
|
+
];
|
|
36559
|
+
function pick(items, defaultIdx = 0) {
|
|
36560
|
+
items.forEach((item, i) => {
|
|
36561
|
+
const num = `\x1B[1m[${i + 1}]\x1B[0m`;
|
|
36562
|
+
const desc = item.description ? ` \x1B[2m${item.description}\x1B[0m` : "";
|
|
36563
|
+
const def = i === defaultIdx ? ` \x1B[2m(default)\x1B[0m` : "";
|
|
36564
|
+
process.stdout.write(` ${num} ${item.label}${desc}${def}
|
|
36565
|
+
`);
|
|
36566
|
+
});
|
|
36567
|
+
process.stdout.write(` \x1B[2m[s] Skip\x1B[0m
|
|
36568
|
+
`);
|
|
36569
|
+
}
|
|
36570
|
+
async function promptCodexModel(ask = prompt) {
|
|
36571
|
+
if (process.env["OPENAI_API_KEY"]) return void 0;
|
|
36572
|
+
info("");
|
|
36573
|
+
process.stdout.write(` \x1B[33m\u26A0\x1B[0m No OPENAI_API_KEY \u2014 using ChatGPT account authentication.
|
|
36574
|
+
`);
|
|
36575
|
+
info(" Tip: run \x1B[1mcodex\x1B[0m then type \x1B[1m/model\x1B[0m to browse the models available to your account.");
|
|
36576
|
+
const model = await ask(" Model name (optional - press Enter for Codex default): ");
|
|
36577
|
+
const trimmed = model.trim();
|
|
36578
|
+
return trimmed || void 0;
|
|
36579
|
+
}
|
|
36580
|
+
async function setupAgent() {
|
|
36581
|
+
section("Step 4: Coding agent (claude, codex, opencode, or copilot)", "[required]");
|
|
36582
|
+
info("experiences import uses a coding agent to generate component definitions.");
|
|
36583
|
+
info("");
|
|
36584
|
+
const found = (await Promise.all(AGENT_DEFS.map(async (a) => await binaryExists(a.binary) ? a : null))).filter(
|
|
36585
|
+
(a) => a !== null
|
|
36586
|
+
);
|
|
36587
|
+
if (found.length === 1) {
|
|
36588
|
+
ok(`${found[0].name} (${found[0].binary}) found`);
|
|
36589
|
+
const agentModel = found[0].binary === "codex" ? await promptCodexModel() : void 0;
|
|
36590
|
+
return { agent: found[0].binary, agentModel };
|
|
36591
|
+
}
|
|
36592
|
+
if (found.length > 1) {
|
|
36593
|
+
info("Multiple coding agents found. Choose one to use as the default:");
|
|
36594
|
+
info("");
|
|
36595
|
+
pick(found.map((a) => ({ label: `${a.name}`, description: a.binary })));
|
|
36596
|
+
info("");
|
|
36597
|
+
const choice2 = await prompt(" \x1B[2m\u203A\x1B[0m Your choice [1]: ");
|
|
36598
|
+
if (choice2.toLowerCase() === "s") {
|
|
36599
|
+
warn("Skipped. Install a coding agent before running experiences import.");
|
|
36600
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36601
|
+
}
|
|
36602
|
+
const parsed = choice2 === "" ? 1 : parseInt(choice2, 10);
|
|
36603
|
+
const idx = Number.isNaN(parsed) || parsed < 1 || parsed > found.length ? 0 : parsed - 1;
|
|
36604
|
+
const selected = found[idx];
|
|
36605
|
+
const agentModel = selected.binary === "codex" ? await promptCodexModel() : void 0;
|
|
36606
|
+
return { agent: selected.binary, agentModel };
|
|
36607
|
+
}
|
|
36608
|
+
warn("No coding agent found on PATH");
|
|
36609
|
+
info("");
|
|
36610
|
+
info("Choose one to install:");
|
|
36611
|
+
info("");
|
|
36612
|
+
pick([
|
|
36613
|
+
{ label: "Claude Code", description: "npm install -g @anthropic-ai/claude-code" },
|
|
36614
|
+
{ label: "OpenAI Codex", description: "npm install -g @openai/codex" },
|
|
36615
|
+
{ label: "OpenCode", description: "npm install -g opencode-ai" }
|
|
36616
|
+
]);
|
|
36617
|
+
info("");
|
|
36618
|
+
const choice = await prompt(" Your choice: ");
|
|
36619
|
+
if (choice === "1" || choice === "") {
|
|
36620
|
+
const r = await runSpawn("npm", ["install", "-g", "@anthropic-ai/claude-code"]);
|
|
36621
|
+
if (r.exitCode !== 0) {
|
|
36622
|
+
fail("Install failed");
|
|
36623
|
+
info(r.stderr.trim().split("\n").slice(0, 5).join("\n"));
|
|
36624
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36625
|
+
}
|
|
36626
|
+
if (!await binaryExists("claude")) {
|
|
36627
|
+
fail("claude binary not found on PATH after install \u2014 check your npm global bin directory");
|
|
36628
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36629
|
+
}
|
|
36630
|
+
ok("Claude Code installed");
|
|
36631
|
+
info("");
|
|
36632
|
+
info("Next: run `claude login` to authenticate (browser OAuth).");
|
|
36633
|
+
info("Or set ANTHROPIC_API_KEY in your shell profile.");
|
|
36634
|
+
return { agent: "claude", agentModel: void 0 };
|
|
36635
|
+
}
|
|
36636
|
+
if (choice === "2") {
|
|
36637
|
+
const r = await runSpawn("npm", ["install", "-g", "@openai/codex"]);
|
|
36638
|
+
if (r.exitCode !== 0) {
|
|
36639
|
+
fail("Install failed");
|
|
36640
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36641
|
+
}
|
|
36642
|
+
if (!await binaryExists("codex")) {
|
|
36643
|
+
fail("codex binary not found on PATH after install \u2014 check your npm global bin directory");
|
|
36644
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36645
|
+
}
|
|
36646
|
+
ok("OpenAI Codex installed");
|
|
36647
|
+
const agentModel = await promptCodexModel();
|
|
36648
|
+
return { agent: "codex", agentModel };
|
|
36649
|
+
}
|
|
36650
|
+
if (choice === "3") {
|
|
36651
|
+
const r = await runSpawn("npm", ["install", "-g", "opencode-ai"]);
|
|
36652
|
+
if (r.exitCode !== 0) {
|
|
36653
|
+
fail("Install failed");
|
|
36654
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36655
|
+
}
|
|
36656
|
+
if (!await binaryExists("opencode")) {
|
|
36657
|
+
fail("opencode binary not found on PATH after install \u2014 check your npm global bin directory");
|
|
36658
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36659
|
+
}
|
|
36660
|
+
ok("OpenCode installed");
|
|
36661
|
+
info("Run `opencode auth` to configure your provider.");
|
|
36662
|
+
return { agent: "opencode", agentModel: void 0 };
|
|
36663
|
+
}
|
|
36664
|
+
warn("Skipped. Install a coding agent before running experiences import.");
|
|
36665
|
+
return { agent: void 0, agentModel: void 0 };
|
|
36666
|
+
}
|
|
36667
|
+
async function setupContentfulCredentials() {
|
|
36668
|
+
section("Step 5: Contentful credentials", "[optional]");
|
|
36669
|
+
info(`Saved to ${experiencesCredentialsPath()} \u2014 loaded automatically by experiences import.`);
|
|
36670
|
+
info("");
|
|
36671
|
+
const envShadowing = [
|
|
36672
|
+
process.env["CONTENTFUL_SPACE_ID"] ? "CONTENTFUL_SPACE_ID" : null,
|
|
36673
|
+
process.env["CONTENTFUL_ENVIRONMENT_ID"] ? "CONTENTFUL_ENVIRONMENT_ID" : null,
|
|
36674
|
+
process.env["CONTENTFUL_MANAGEMENT_TOKEN"] ? "CONTENTFUL_MANAGEMENT_TOKEN" : null,
|
|
36675
|
+
process.env["EDS_HOST"] ? "EDS_HOST" : null
|
|
36676
|
+
].filter((v) => !!v);
|
|
36677
|
+
if (envShadowing.length > 0) {
|
|
36678
|
+
warn(
|
|
36679
|
+
`Env vars set: ${envShadowing.join(", ")}. Values saved here take precedence; env vars only apply where disk is empty.`
|
|
36680
|
+
);
|
|
36681
|
+
info("");
|
|
36682
|
+
}
|
|
36683
|
+
const stored = await readExperiencesCredentials();
|
|
36684
|
+
const currentSpace = stored.spaceId;
|
|
36685
|
+
const currentEnv = stored.environmentId;
|
|
36686
|
+
const currentToken = stored.cmaToken;
|
|
36687
|
+
const storedHost = stored.host;
|
|
36688
|
+
const currentHost = storedHost ?? DEFAULT_CONFIGURED_HOST;
|
|
36689
|
+
const hasAny = !!(currentSpace || currentEnv || currentToken);
|
|
36690
|
+
if (hasAny) {
|
|
36691
|
+
info("Current values:");
|
|
36692
|
+
if (currentSpace) {
|
|
36693
|
+
ok(`Space ID ${currentSpace}`);
|
|
36694
|
+
} else {
|
|
36695
|
+
warn("Space ID (not set)");
|
|
36696
|
+
}
|
|
36697
|
+
if (currentEnv) {
|
|
36698
|
+
ok(`Environment ID ${currentEnv}`);
|
|
36699
|
+
} else {
|
|
36700
|
+
warn("Environment ID (not set)");
|
|
36701
|
+
}
|
|
36702
|
+
if (currentToken) {
|
|
36703
|
+
ok(`CMA Token ${"\u2022".repeat(Math.min(currentToken.length, 8))}...`);
|
|
36704
|
+
} else {
|
|
36705
|
+
warn("CMA Token (not set)");
|
|
36706
|
+
}
|
|
36707
|
+
ok(`API Host ${currentHost}`);
|
|
36708
|
+
info("");
|
|
36709
|
+
}
|
|
36710
|
+
const allSet = !!(currentSpace && currentEnv && currentToken);
|
|
36711
|
+
const doUpdate = await confirm(hasAny ? "Update credentials?" : "Configure Contentful credentials?", !allSet);
|
|
36712
|
+
if (!doUpdate) {
|
|
36713
|
+
if (allSet) {
|
|
36714
|
+
ok("Credentials already configured \u2014 no changes made");
|
|
36715
|
+
} else {
|
|
36716
|
+
warn("Skipped. experiences import will prompt for credentials interactively.");
|
|
36717
|
+
}
|
|
36718
|
+
return true;
|
|
36719
|
+
}
|
|
36720
|
+
info("");
|
|
36721
|
+
info("Get your CMA token: Contentful web app \u2192 Settings \u2192 API keys \u2192 Content management tokens");
|
|
36722
|
+
info("");
|
|
36723
|
+
const spaceIdInput = await prompt(` Space ID${currentSpace ? ` [${currentSpace}]` : ""}: `);
|
|
36724
|
+
const spaceId = spaceIdInput || currentSpace;
|
|
36725
|
+
const envIdInput = await prompt(` Environment ID [${currentEnv || "master"}]: `);
|
|
36726
|
+
const environmentId = envIdInput || currentEnv || "master";
|
|
36727
|
+
const tokenInput = await promptSecret(
|
|
36728
|
+
` CMA token${currentToken ? " [press Enter to keep existing]" : " (paste here)"}: `
|
|
36729
|
+
);
|
|
36730
|
+
const cmaToken = tokenInput || currentToken;
|
|
36731
|
+
if (!cmaToken || !spaceId) {
|
|
36732
|
+
warn("Space ID and CMA token are required. Skipped.");
|
|
36733
|
+
return false;
|
|
36734
|
+
}
|
|
36735
|
+
const hostInput = await prompt(` API host [${currentHost}]: `);
|
|
36736
|
+
const host = toConfiguredHost(hostInput) ?? storedHost;
|
|
36737
|
+
const existing = await readExperiencesCredentials();
|
|
36738
|
+
await writeExperiencesCredentials({ ...existing, spaceId, environmentId, cmaToken, ...host ? { host } : {} });
|
|
36739
|
+
ok(`Credentials saved to ${experiencesCredentialsPath()}`);
|
|
36740
|
+
ok(`API host set to ${host ?? DEFAULT_CONFIGURED_HOST}`);
|
|
36741
|
+
info("Run experiences import \u2014 credentials will be pre-filled automatically.");
|
|
36742
|
+
return true;
|
|
36743
|
+
}
|
|
36744
|
+
async function promptCustomSkillPath(kind, current, ask = prompt) {
|
|
36745
|
+
const flagName = kind === "select" ? "--select-prompt-path" : "--generate-prompt-path";
|
|
36746
|
+
void flagName;
|
|
36747
|
+
const label = kind === "select" ? "select (analyze select-agent)" : "generate (generate components)";
|
|
36748
|
+
const currentLabel = current ? ` [${current}]` : " [none]";
|
|
36749
|
+
const answer = await ask(` Custom ${label} prompt path${currentLabel} (empty=keep, "-"=clear): `);
|
|
36750
|
+
const trimmed = answer.trim();
|
|
36751
|
+
if (trimmed === "") return void 0;
|
|
36752
|
+
if (trimmed === "-") return null;
|
|
36753
|
+
return trimmed;
|
|
36754
|
+
}
|
|
36755
|
+
async function setupQoL(profilePath) {
|
|
36756
|
+
section("Step 6: Optional extras", "[optional]");
|
|
36757
|
+
info("These are not required for experiences import but improve the experience.");
|
|
36758
|
+
info("");
|
|
36759
|
+
const existingCreds = await readExperiencesCredentials();
|
|
36760
|
+
info("AI auto-filter \u2014 runs an agent pass before the manual scope-gate to prefilter components.");
|
|
36761
|
+
info("Operators who prefer to review every component can default this OFF and override per run with --auto-filter.");
|
|
36762
|
+
const autoFilter = await promptAutoFilterPreference((q) => prompt(q), existingCreds.autoFilter);
|
|
36763
|
+
if (autoFilter !== (existingCreds.autoFilter ?? true)) {
|
|
36764
|
+
await writeExperiencesCredentials({ ...existingCreds, autoFilter });
|
|
36765
|
+
ok(`AI auto-filter default set to ${autoFilter ? "ON" : "OFF"}`);
|
|
36766
|
+
} else {
|
|
36767
|
+
dim(" unchanged");
|
|
36768
|
+
}
|
|
36769
|
+
info("");
|
|
36770
|
+
const hasConcurrency = await profileContains(profilePath, "EDS_EXTRACT_CONCURRENCY");
|
|
36771
|
+
if (!hasConcurrency) {
|
|
36772
|
+
info("EDS_EXTRACT_CONCURRENCY \u2014 controls how many components are analyzed in parallel.");
|
|
36773
|
+
info("Default is 4. Set higher (e.g. 8) on fast machines to speed up large codebases.");
|
|
36774
|
+
const setConcurrency = await confirm("Add EDS_EXTRACT_CONCURRENCY=8 to your profile?", false);
|
|
36775
|
+
if (setConcurrency) {
|
|
36776
|
+
await appendToProfile(profilePath, "# experiences performance\nexport EDS_EXTRACT_CONCURRENCY=8");
|
|
36777
|
+
ok(`EDS_EXTRACT_CONCURRENCY=8 written to ${profilePath}`);
|
|
36778
|
+
} else {
|
|
36779
|
+
dim(" skipped");
|
|
36780
|
+
}
|
|
36781
|
+
} else {
|
|
36782
|
+
ok("EDS_EXTRACT_CONCURRENCY \u2014 already set");
|
|
36783
|
+
}
|
|
36784
|
+
info("");
|
|
36785
|
+
info("Custom skill prompt paths \u2014 point select-agent and/or generate components at your own .md prompts.");
|
|
36786
|
+
info("When set, the bundled invariants (utility-wrapper rejection, description rules) do NOT apply.");
|
|
36787
|
+
const offerCustomPrompts = await confirm("Configure custom skill prompt paths?", false);
|
|
36788
|
+
if (offerCustomPrompts) {
|
|
36789
|
+
const stored = await readExperiencesCredentials();
|
|
36790
|
+
const selectAnswer = await promptCustomSkillPath("select", stored.selectPromptPath);
|
|
36791
|
+
const generateAnswer = await promptCustomSkillPath("generate", stored.generatePromptPath);
|
|
36792
|
+
const updated = { ...stored };
|
|
36793
|
+
if (selectAnswer === null) delete updated.selectPromptPath;
|
|
36794
|
+
else if (selectAnswer !== void 0) updated.selectPromptPath = selectAnswer;
|
|
36795
|
+
if (generateAnswer === null) delete updated.generatePromptPath;
|
|
36796
|
+
else if (generateAnswer !== void 0) updated.generatePromptPath = generateAnswer;
|
|
36797
|
+
await writeExperiencesCredentials(updated);
|
|
36798
|
+
ok(`Custom prompt paths saved to ${experiencesCredentialsPath()}`);
|
|
36799
|
+
} else {
|
|
36800
|
+
dim(" skipped");
|
|
36801
|
+
}
|
|
36802
|
+
info("");
|
|
36803
|
+
info("Debug logging \u2014 writes a JSONL trace of every command decision (agent calls, tool calls,");
|
|
36804
|
+
info("apply actions, filter decisions, etc.) to ~/.contentful/experience-design-system-cli/debug/.");
|
|
36805
|
+
info("Useful for developers debugging the CLI; OFF by default because traces are verbose.");
|
|
36806
|
+
const debugCreds = await readExperiencesCredentials();
|
|
36807
|
+
const debugChoice = await promptDebugModePreference((q) => prompt(q), debugCreds.debug);
|
|
36808
|
+
if (debugChoice !== (debugCreds.debug ?? false)) {
|
|
36809
|
+
await writeExperiencesCredentials({ ...debugCreds, debug: debugChoice });
|
|
36810
|
+
ok(`Debug logging default set to ${debugChoice ? "ON" : "OFF"}`);
|
|
36811
|
+
} else {
|
|
36812
|
+
dim(" unchanged");
|
|
36813
|
+
}
|
|
36814
|
+
info("");
|
|
36815
|
+
info("");
|
|
36816
|
+
info("Anonymous usage analytics \u2014 helps us see which commands are used and where imports");
|
|
36817
|
+
info("succeed or fail. Never includes source code, file paths, credentials, or authored content.");
|
|
36818
|
+
info("Disabling here persists the opt-out; it will not silently re-enable later. See README > Usage data.");
|
|
36819
|
+
const analyticsCreds = await readExperiencesCredentials();
|
|
36820
|
+
const analyticsDisabled = await promptAnalyticsPreference((q) => prompt(q), analyticsCreds.analyticsDisabled);
|
|
36821
|
+
if (analyticsDisabled !== (analyticsCreds.analyticsDisabled ?? false)) {
|
|
36822
|
+
await writeExperiencesCredentials({ ...analyticsCreds, analyticsDisabled });
|
|
36823
|
+
ok(`Analytics ${analyticsDisabled ? "disabled" : "enabled"}`);
|
|
36824
|
+
} else {
|
|
36825
|
+
dim(" unchanged");
|
|
36826
|
+
}
|
|
36827
|
+
info("");
|
|
36828
|
+
info("");
|
|
36829
|
+
info("NO_COLOR \u2014 set to 1 to disable ANSI color output (useful in CI or plain terminals).");
|
|
36830
|
+
const setNoColor = await confirm("Add NO_COLOR=1 (disable colors) to your profile?", false);
|
|
36831
|
+
if (setNoColor) {
|
|
36832
|
+
const hasNoColor = await profileContains(profilePath, "NO_COLOR");
|
|
36833
|
+
if (!hasNoColor) {
|
|
36834
|
+
await appendToProfile(profilePath, "export NO_COLOR=1");
|
|
36835
|
+
ok(`NO_COLOR=1 written to ${profilePath}`);
|
|
36836
|
+
} else {
|
|
36837
|
+
warn("NO_COLOR already present in profile \u2014 skipping");
|
|
36838
|
+
}
|
|
36839
|
+
} else {
|
|
36840
|
+
dim(" skipped");
|
|
36841
|
+
}
|
|
36842
|
+
}
|
|
36843
|
+
async function checkNode() {
|
|
36844
|
+
section("Checking Node.js version");
|
|
36845
|
+
const current = process.versions.node;
|
|
36846
|
+
const major = parseInt(current.split(".")[0], 10);
|
|
36847
|
+
if (major < REQUIRED_NODE_MAJOR) {
|
|
36848
|
+
fail(`Node.js v${current} \u2014 need v${REQUIRED_NODE_MAJOR}+`);
|
|
36849
|
+
info("");
|
|
36850
|
+
info("How to fix:");
|
|
36851
|
+
if (await binaryExists("nvm")) {
|
|
36852
|
+
info(` nvm install ${REQUIRED_NODE_MAJOR}`);
|
|
36853
|
+
info(` nvm use ${REQUIRED_NODE_MAJOR}`);
|
|
36854
|
+
info(` nvm alias default ${REQUIRED_NODE_MAJOR} # make it permanent`);
|
|
36855
|
+
} else if (await binaryExists("fnm")) {
|
|
36856
|
+
info(` fnm install ${REQUIRED_NODE_MAJOR}`);
|
|
36857
|
+
info(` fnm use ${REQUIRED_NODE_MAJOR}`);
|
|
36858
|
+
} else {
|
|
36859
|
+
info(` Download Node v${REQUIRED_NODE_MAJOR} from https://nodejs.org`);
|
|
36860
|
+
}
|
|
36861
|
+
return false;
|
|
36862
|
+
}
|
|
36863
|
+
ok(`Node.js v${current}`);
|
|
36864
|
+
return true;
|
|
36865
|
+
}
|
|
36866
|
+
async function checkPnpm(pkgRoot) {
|
|
37115
36867
|
section("Checking pnpm");
|
|
37116
|
-
|
|
37117
|
-
if (check.status === "missing") {
|
|
36868
|
+
if (!await binaryExists("pnpm")) {
|
|
37118
36869
|
fail("pnpm not found");
|
|
37119
36870
|
info("How to fix:");
|
|
37120
36871
|
info(" npm install -g pnpm");
|
|
37121
36872
|
info(" # or: corepack enable pnpm");
|
|
37122
36873
|
return false;
|
|
37123
36874
|
}
|
|
37124
|
-
|
|
36875
|
+
const versionResult = await runSpawn("pnpm", ["--version"]);
|
|
36876
|
+
if (versionResult.exitCode !== 0) {
|
|
37125
36877
|
fail("pnpm found but not working");
|
|
37126
36878
|
info("Try reinstalling: npm install -g pnpm --force");
|
|
37127
36879
|
return false;
|
|
37128
36880
|
}
|
|
37129
|
-
ok(`pnpm v${
|
|
37130
|
-
|
|
36881
|
+
ok(`pnpm v${versionResult.stdout.trim()}`);
|
|
36882
|
+
const pingResult = await runSpawn("pnpm", ["exec", "node", "--version"], { cwd: pkgRoot });
|
|
36883
|
+
if (pingResult.exitCode !== 0) {
|
|
37131
36884
|
fail("pnpm cannot execute in repo root");
|
|
37132
36885
|
info("The pnpm global store may be mismatched with your current Node version.");
|
|
37133
36886
|
info("How to fix:");
|
|
@@ -37136,18 +36889,21 @@ async function reportPnpm(pkgRoot) {
|
|
|
37136
36889
|
}
|
|
37137
36890
|
return true;
|
|
37138
36891
|
}
|
|
37139
|
-
async function
|
|
36892
|
+
async function checkDependencies(pkgRoot) {
|
|
37140
36893
|
section("Checking dependencies (pnpm install)");
|
|
37141
|
-
|
|
36894
|
+
const nodeModulesExists = await access10(join27(pkgRoot, "node_modules")).then(() => true).catch(() => false);
|
|
36895
|
+
if (!nodeModulesExists) {
|
|
37142
36896
|
info("node_modules not found \u2014 running pnpm install...");
|
|
37143
36897
|
} else {
|
|
37144
36898
|
info("Running pnpm install to ensure dependencies are up to date...");
|
|
37145
36899
|
}
|
|
37146
|
-
const
|
|
37147
|
-
|
|
36900
|
+
const repoRoot = join27(pkgRoot, "..", "..");
|
|
36901
|
+
const result = await runSpawn("pnpm", ["install", "--frozen-lockfile"], { cwd: repoRoot });
|
|
36902
|
+
if (result.exitCode !== 0) {
|
|
37148
36903
|
fail("pnpm install failed");
|
|
37149
36904
|
info("");
|
|
37150
|
-
|
|
36905
|
+
const errLines = result.stderr.trim().split("\n").slice(0, 10);
|
|
36906
|
+
for (const line of errLines) info(line);
|
|
37151
36907
|
info("");
|
|
37152
36908
|
info("How to fix:");
|
|
37153
36909
|
info(" \u2022 Try: pnpm install (without --frozen-lockfile) to update the lockfile");
|
|
@@ -37157,14 +36913,18 @@ async function reportDependencies(pkgRoot) {
|
|
|
37157
36913
|
ok("Dependencies installed");
|
|
37158
36914
|
return true;
|
|
37159
36915
|
}
|
|
37160
|
-
async function
|
|
36916
|
+
async function checkBuild(pkgRoot) {
|
|
37161
36917
|
section("Building CLI");
|
|
37162
36918
|
info("Running pnpm build...");
|
|
37163
|
-
const
|
|
37164
|
-
|
|
36919
|
+
const repoRoot = join27(pkgRoot, "..", "..");
|
|
36920
|
+
const result = await runSpawn("pnpm", ["--filter", "@contentful/experience-design-system-cli", "run", "build"], {
|
|
36921
|
+
cwd: repoRoot
|
|
36922
|
+
});
|
|
36923
|
+
if (result.exitCode !== 0) {
|
|
37165
36924
|
fail("Build failed");
|
|
37166
36925
|
info("");
|
|
37167
|
-
|
|
36926
|
+
const errLines = result.stderr.trim().split("\n").slice(0, 15);
|
|
36927
|
+
for (const line of errLines) info(line);
|
|
37168
36928
|
info("");
|
|
37169
36929
|
info("How to fix:");
|
|
37170
36930
|
info(" \u2022 Check for TypeScript errors: pnpm typecheck");
|
|
@@ -37174,22 +36934,25 @@ async function reportBuild(pkgRoot) {
|
|
|
37174
36934
|
ok("Build succeeded");
|
|
37175
36935
|
return true;
|
|
37176
36936
|
}
|
|
37177
|
-
async function
|
|
36937
|
+
async function checkAgent() {
|
|
37178
36938
|
section("Checking coding agent");
|
|
36939
|
+
const agents = AGENT_DEFS;
|
|
37179
36940
|
const creds = await readExperiencesCredentials();
|
|
37180
36941
|
const savedAgent = creds.agent;
|
|
37181
36942
|
const savedModel = creds.agentModel;
|
|
37182
36943
|
if (savedAgent) {
|
|
37183
|
-
|
|
36944
|
+
const found = await binaryExists(savedAgent);
|
|
36945
|
+
if (found) {
|
|
37184
36946
|
const modelStr = savedModel ? ` \u2014 model: ${savedModel}` : "";
|
|
37185
36947
|
ok(`${savedAgent}${modelStr} (saved preference)`);
|
|
37186
36948
|
return true;
|
|
36949
|
+
} else {
|
|
36950
|
+
warn(`Saved agent '${savedAgent}' not found on PATH`);
|
|
36951
|
+
info(`Re-run experiences setup to reconfigure.`);
|
|
36952
|
+
return false;
|
|
37187
36953
|
}
|
|
37188
|
-
warn(`Saved agent '${savedAgent}' not found on PATH`);
|
|
37189
|
-
info(`Re-run experiences setup to reconfigure.`);
|
|
37190
|
-
return false;
|
|
37191
36954
|
}
|
|
37192
|
-
for (const agent of
|
|
36955
|
+
for (const agent of agents) {
|
|
37193
36956
|
if (await binaryExists(agent.binary)) {
|
|
37194
36957
|
ok(`${agent.name} (${agent.binary}) found`);
|
|
37195
36958
|
info("Tip: run experiences setup to save a default agent and model.");
|
|
@@ -37204,147 +36967,152 @@ async function reportAgent() {
|
|
|
37204
36967
|
info(" \u2022 OpenCode: npm install -g opencode-ai");
|
|
37205
36968
|
return false;
|
|
37206
36969
|
}
|
|
37207
|
-
|
|
37208
|
-
|
|
37209
|
-
|
|
37210
|
-
|
|
37211
|
-
|
|
37212
|
-
|
|
37213
|
-
|
|
37214
|
-
|
|
37215
|
-
|
|
37216
|
-
|
|
37217
|
-
|
|
37218
|
-
|
|
37219
|
-
|
|
37220
|
-
|
|
37221
|
-
|
|
37222
|
-
|
|
37223
|
-
|
|
37224
|
-
|
|
36970
|
+
function registerSetupCommand(program) {
|
|
36971
|
+
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) => {
|
|
36972
|
+
process.stderr.write("\x1B[1mexperiences doctor\x1B[0m \u2014 checking your environment\n");
|
|
36973
|
+
const pkgRoot = findPkgRoot();
|
|
36974
|
+
const results = [];
|
|
36975
|
+
const nodeOk = await checkNode();
|
|
36976
|
+
results.push({ name: "Node.js version", ok: nodeOk, required: true });
|
|
36977
|
+
if (nodeOk) {
|
|
36978
|
+
const pnpmOk = await checkPnpm(pkgRoot);
|
|
36979
|
+
results.push({ name: "pnpm", ok: pnpmOk, required: true });
|
|
36980
|
+
if (!opts.skipBuild) {
|
|
36981
|
+
if (pnpmOk) {
|
|
36982
|
+
const depsOk = await checkDependencies(pkgRoot);
|
|
36983
|
+
results.push({ name: "dependencies", ok: depsOk, required: true });
|
|
36984
|
+
if (depsOk) {
|
|
36985
|
+
const buildOk = await checkBuild(pkgRoot);
|
|
36986
|
+
results.push({ name: "build", ok: buildOk, required: true });
|
|
36987
|
+
}
|
|
37225
36988
|
}
|
|
36989
|
+
} else {
|
|
36990
|
+
info("\nSkipping install + build (--skip-build)");
|
|
37226
36991
|
}
|
|
36992
|
+
}
|
|
36993
|
+
if (!opts.skipAgent) {
|
|
36994
|
+
const agentOk = await checkAgent();
|
|
36995
|
+
results.push({ name: "coding agent", ok: agentOk, required: false });
|
|
36996
|
+
}
|
|
36997
|
+
section("Summary");
|
|
36998
|
+
const failed = results.filter((r) => !r.ok);
|
|
36999
|
+
const requiredFailed = failed.filter((r) => r.required);
|
|
37000
|
+
for (const r of results) {
|
|
37001
|
+
if (r.ok) {
|
|
37002
|
+
ok(r.name);
|
|
37003
|
+
} else if (r.required) {
|
|
37004
|
+
fail(`${r.name} \u2014 required`);
|
|
37005
|
+
} else {
|
|
37006
|
+
warn(`${r.name} \u2014 optional`);
|
|
37007
|
+
}
|
|
37008
|
+
}
|
|
37009
|
+
if (requiredFailed.length === 0 && failed.length === 0) {
|
|
37010
|
+
process.stderr.write(
|
|
37011
|
+
"\n\x1B[32m\x1B[1m\u2713 All checks passed. You are ready to run: experiences import\x1B[0m\n\n"
|
|
37012
|
+
);
|
|
37013
|
+
process.exit(0);
|
|
37014
|
+
} else if (requiredFailed.length === 0) {
|
|
37015
|
+
process.stderr.write("\n\x1B[33m\x1B[1m\u26A0 Required checks passed, but optional checks failed.\x1B[0m\n");
|
|
37016
|
+
process.stderr.write(
|
|
37017
|
+
" You can run \x1B[1mexperiences import\x1B[0m but the generate steps may fail without a coding agent.\n\n"
|
|
37018
|
+
);
|
|
37019
|
+
process.exit(0);
|
|
37227
37020
|
} 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
|
-
`
|
|
37021
|
+
process.stderr.write(
|
|
37022
|
+
`
|
|
37255
37023
|
\x1B[31m\x1B[1m\u2717 ${requiredFailed.length} required check${requiredFailed.length === 1 ? "" : "s"} failed.\x1B[0m
|
|
37256
37024
|
`
|
|
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?.();
|
|
37025
|
+
);
|
|
37026
|
+
process.stderr.write(" Fix the issues above, then re-run \x1B[1mexperiences doctor\x1B[0m.\n\n");
|
|
37027
|
+
process.exit(1);
|
|
37028
|
+
}
|
|
37029
|
+
});
|
|
37030
|
+
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(
|
|
37031
|
+
async (opts) => {
|
|
37032
|
+
process.stdout.write("\n\x1B[1mexperiences setup\x1B[0m \u2014 interactive setup wizard\n");
|
|
37033
|
+
process.stdout.write("Sets up everything you need to run \x1B[1mexperiences import\x1B[0m.\n");
|
|
37034
|
+
const pkgRoot = findPkgRoot();
|
|
37035
|
+
const repoRoot = join27(pkgRoot, "..", "..");
|
|
37036
|
+
const profilePath = await detectShellProfile();
|
|
37037
|
+
const results = [];
|
|
37038
|
+
const nodeOk = await setupNode();
|
|
37039
|
+
results.push({ name: "Node.js 24+", passed: nodeOk, required: true });
|
|
37040
|
+
if (!nodeOk) {
|
|
37041
|
+
process.stdout.write(
|
|
37042
|
+
"\n\x1B[33mNode.js setup requires a shell restart. Re-run experiences setup afterwards.\x1B[0m\n\n"
|
|
37043
|
+
);
|
|
37044
|
+
process.exit(0);
|
|
37045
|
+
}
|
|
37046
|
+
const pnpmOk = await setupPnpm();
|
|
37047
|
+
results.push({ name: "pnpm", passed: pnpmOk, required: true });
|
|
37048
|
+
if (!opts.skipBuild && pnpmOk) {
|
|
37049
|
+
const buildOk = await setupBuild(repoRoot);
|
|
37050
|
+
results.push({ name: "install & build", passed: buildOk, required: true });
|
|
37051
|
+
} else if (opts.skipBuild) {
|
|
37052
|
+
info("\nSkipping install + build (--skip-build)");
|
|
37053
|
+
}
|
|
37054
|
+
if (!opts.skipAgent) {
|
|
37055
|
+
const { agent, agentModel } = await setupAgent();
|
|
37056
|
+
if (agent) {
|
|
37057
|
+
const stored = await readExperiencesCredentials();
|
|
37058
|
+
const { agentModel: _staleModel, ...storedWithoutModel } = stored;
|
|
37059
|
+
await writeExperiencesCredentials({ ...storedWithoutModel, agent, ...agentModel ? { agentModel } : {} });
|
|
37060
|
+
}
|
|
37061
|
+
results.push({ name: "coding agent", passed: !!agent, required: true });
|
|
37062
|
+
} else {
|
|
37063
|
+
info("\nSkipping agent check (--skip-agent)");
|
|
37064
|
+
results.push({ name: "coding agent", passed: true, required: false });
|
|
37325
37065
|
}
|
|
37326
|
-
|
|
37066
|
+
if (!opts.skipCredentials) {
|
|
37067
|
+
const credsOk = await setupContentfulCredentials();
|
|
37068
|
+
results.push({ name: "Contentful credentials", passed: credsOk, required: false });
|
|
37069
|
+
} else {
|
|
37070
|
+
info("\nSkipping credentials (--skip-credentials)");
|
|
37071
|
+
}
|
|
37072
|
+
if (!opts.skipOptional) {
|
|
37073
|
+
await setupQoL(profilePath);
|
|
37074
|
+
}
|
|
37075
|
+
section("Summary");
|
|
37076
|
+
const requiredFailed = results.filter((r) => r.required && !r.passed);
|
|
37077
|
+
const optionalFailed = results.filter((r) => !r.required && !r.passed);
|
|
37078
|
+
for (const r of results) {
|
|
37079
|
+
if (r.passed) {
|
|
37080
|
+
ok(`${r.name}`);
|
|
37081
|
+
} else if (r.required) {
|
|
37082
|
+
fail(`${r.name} \u2014 required`);
|
|
37083
|
+
} else {
|
|
37084
|
+
warn(`${r.name} \u2014 optional`);
|
|
37085
|
+
}
|
|
37086
|
+
}
|
|
37087
|
+
process.stdout.write("\n");
|
|
37088
|
+
if (requiredFailed.length === 0) {
|
|
37089
|
+
process.stdout.write("\x1B[32m\x1B[1m\u2713 Setup complete. You can now run: experiences import\x1B[0m\n");
|
|
37090
|
+
if (optionalFailed.length > 0) {
|
|
37091
|
+
process.stdout.write(" (Some optional steps were skipped \u2014 that's fine.)\n");
|
|
37092
|
+
}
|
|
37093
|
+
} else {
|
|
37094
|
+
process.stdout.write(
|
|
37095
|
+
`\x1B[33m\x1B[1m\u26A0 ${requiredFailed.length} required step${requiredFailed.length === 1 ? "" : "s"} incomplete.\x1B[0m
|
|
37096
|
+
`
|
|
37097
|
+
);
|
|
37098
|
+
process.stdout.write(" Complete the steps above, then re-run \x1B[1mexperiences setup\x1B[0m.\n");
|
|
37099
|
+
}
|
|
37100
|
+
process.stdout.write("\n");
|
|
37101
|
+
const runDoctor = process.stdout.isTTY && await confirm("Run experiences doctor now to verify your environment?", requiredFailed.length === 0);
|
|
37102
|
+
if (runDoctor) {
|
|
37103
|
+
process.stdout.write("\n");
|
|
37104
|
+
const cliBin = process.argv[1] ?? fileURLToPath4(import.meta.url);
|
|
37105
|
+
const doctorResult = await runSpawn(process.execPath, [cliBin, "doctor"], {
|
|
37106
|
+
env: process.env
|
|
37107
|
+
});
|
|
37108
|
+
process.stdout.write(doctorResult.stdout);
|
|
37109
|
+
process.stderr.write(doctorResult.stderr);
|
|
37110
|
+
process.exit(doctorResult.exitCode);
|
|
37111
|
+
}
|
|
37112
|
+
process.stdout.write("\nRun \x1B[1mexperiences doctor\x1B[0m at any time to re-check your environment.\n\n");
|
|
37113
|
+
process.exit(requiredFailed.length === 0 ? 0 : 1);
|
|
37114
|
+
}
|
|
37327
37115
|
);
|
|
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
37116
|
}
|
|
37349
37117
|
|
|
37350
37118
|
// packages/experience-design-system-cli/src/runs/ls-command.ts
|
|
@@ -37504,7 +37272,7 @@ async function beginCommand(command, opts) {
|
|
|
37504
37272
|
init_analytics();
|
|
37505
37273
|
init_credentials_store();
|
|
37506
37274
|
init_cli_path();
|
|
37507
|
-
var pkg3 = JSON.parse(
|
|
37275
|
+
var pkg3 = JSON.parse(readFileSync10(join28(findPkgRoot(), "package.json"), "utf8"));
|
|
37508
37276
|
async function runBuild(opts) {
|
|
37509
37277
|
return new Promise((resolvePromise) => {
|
|
37510
37278
|
const child = opts.spawnFn();
|
|
@@ -37541,7 +37309,7 @@ function registerImportV2Command(program) {
|
|
|
37541
37309
|
}
|
|
37542
37310
|
function registerBuildCommand(program) {
|
|
37543
37311
|
program.command("build").description("Rebuild from source and re-link exo/experiences binaries to this build").action(async () => {
|
|
37544
|
-
const pkgRoot =
|
|
37312
|
+
const pkgRoot = resolve27(dirname14(fileURLToPath5(import.meta.url)), "..", "..");
|
|
37545
37313
|
process.stderr.write("\u2699 Building from source...\n");
|
|
37546
37314
|
const { exitCode } = await runBuild({
|
|
37547
37315
|
spawnFn: () => spawn6("pnpm", ["build"], { cwd: pkgRoot, stdio: "inherit" }),
|
|
@@ -37560,7 +37328,6 @@ function createProgram() {
|
|
|
37560
37328
|
registerSessionCommand(program);
|
|
37561
37329
|
registerImportCommand(program);
|
|
37562
37330
|
registerImportV2Command(program);
|
|
37563
|
-
registerDoctorCommand(program);
|
|
37564
37331
|
registerSetupCommand(program);
|
|
37565
37332
|
registerRunsCommand(program);
|
|
37566
37333
|
registerBuildCommand(program);
|