@contentful/experience-design-system-cli 2.32.1-dev-build-403b769.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 -1
- 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 +483 -223
- package/dist/src/session/cache-keys.d.ts +1 -1
- package/package.json +6 -6
- package/skills/generate-components.md +27 -0
- package/skills/map-tokens.md +12 -0
- package/skills/select-components.md +11 -0
- package/dist/src/helpers/cma-client.d.ts +0 -17
- package/dist/src/helpers/fetch-existing-entities.d.ts +0 -16
package/dist/src/index.js
CHANGED
|
@@ -335,7 +335,7 @@ async function runAgent(options) {
|
|
|
335
335
|
promptLen: prompt2.length,
|
|
336
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"],
|
|
@@ -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`);
|
|
@@ -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 {
|
|
@@ -17401,7 +17479,7 @@ function WelcomeStep({ onContinue, onQuit }) {
|
|
|
17401
17479
|
});
|
|
17402
17480
|
const displayValue2 = inputValue + (cursorVisible ? "\u2588" : " ");
|
|
17403
17481
|
return /* @__PURE__ */ jsxs24(Box24, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [
|
|
17404
|
-
/* @__PURE__ */ jsx24(Text24, { bold: true, color: PALETTE.
|
|
17482
|
+
/* @__PURE__ */ jsx24(Text24, { bold: true, color: PALETTE.success, children: "\u{1F44B} Hey! Let's import your design system into Contentful." }),
|
|
17405
17483
|
/* @__PURE__ */ jsx24(Text24, { dimColor: true, children: "I'll walk you through 5 steps to get your components into Contentful ExO." }),
|
|
17406
17484
|
/* @__PURE__ */ jsxs24(Box24, { flexDirection: "column", marginTop: 1, gap: 0, children: [
|
|
17407
17485
|
/* @__PURE__ */ jsx24(Text24, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
@@ -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;
|
|
@@ -29783,7 +29886,7 @@ async function promptForPushCredentials(opts = {}) {
|
|
|
29783
29886
|
const { render: render7, Box: Box50, Text: Text52 } = await import("ink");
|
|
29784
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
29892
|
const [done, setDone] = useState29(false);
|
|
@@ -29792,7 +29895,7 @@ async function promptForPushCredentials(opts = {}) {
|
|
|
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) {
|
|
@@ -29824,14 +29927,14 @@ var init_push_creds_prompt = __esm({
|
|
|
29824
29927
|
// packages/experience-design-system-cli/src/program.ts
|
|
29825
29928
|
import { spawn as spawn6 } from "node:child_process";
|
|
29826
29929
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
29827
|
-
import { dirname as dirname14, join as
|
|
29930
|
+
import { dirname as dirname14, join as join28, resolve as resolve27 } from "node:path";
|
|
29828
29931
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
29829
29932
|
import { Command } from "commander";
|
|
29830
29933
|
|
|
29831
29934
|
// packages/experience-design-system-cli/src/analyze/command.ts
|
|
29832
29935
|
import { createElement as createElement3 } from "react";
|
|
29833
29936
|
import { render as render3 } from "ink";
|
|
29834
|
-
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";
|
|
29835
29938
|
import { isAbsolute as isAbsolute4, join as join15, relative as relative3, resolve as resolve15 } from "node:path";
|
|
29836
29939
|
|
|
29837
29940
|
// packages/experience-design-system-cli/src/lib/agent-model-options.ts
|
|
@@ -29905,7 +30008,7 @@ function AnalyzeView({ result, onExit }) {
|
|
|
29905
30008
|
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "Session: " + result.sessionId }),
|
|
29906
30009
|
/* @__PURE__ */ jsx2(Text2, { children: " " }),
|
|
29907
30010
|
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "\u2500".repeat(70) }),
|
|
29908
|
-
/* @__PURE__ */ jsx2(Text2, { bold: true,
|
|
30011
|
+
/* @__PURE__ */ jsx2(Text2, { bold: true, children: "Components" + (showScrollUp || showScrollDown ? " (" + (scrollOffset + 1) + "\u2013" + Math.min(scrollOffset + visibleCount, result.components.length) + " of " + result.components.length + ")" : "") }),
|
|
29909
30012
|
/* @__PURE__ */ jsx2(Text2, { dimColor: true, children: "\u2500".repeat(70) }),
|
|
29910
30013
|
/* @__PURE__ */ jsx2(Text2, { children: " " }),
|
|
29911
30014
|
showScrollUp && /* @__PURE__ */ jsx2(Text2, { dimColor: true, children: " \u25B2 scroll up" }),
|
|
@@ -29958,6 +30061,104 @@ init_command2();
|
|
|
29958
30061
|
// packages/experience-design-system-cli/src/analyze/select-agent/command.ts
|
|
29959
30062
|
init_db();
|
|
29960
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
|
|
29961
30162
|
init_persistence();
|
|
29962
30163
|
init_parser();
|
|
29963
30164
|
init_src();
|
|
@@ -30059,7 +30260,7 @@ var OutputFormatter = class {
|
|
|
30059
30260
|
};
|
|
30060
30261
|
|
|
30061
30262
|
// packages/experience-design-system-cli/src/analyze/select-agent/context-builder.ts
|
|
30062
|
-
import { readFile as
|
|
30263
|
+
import { readFile as readFile14 } from "node:fs/promises";
|
|
30063
30264
|
import { dirname as dirname10, isAbsolute as isAbsolute2, join as join13, relative as relative2, resolve as resolve11, sep } from "node:path";
|
|
30064
30265
|
var SCANNED_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".astro", ".js", ".jsx", ".svelte", ".ts", ".tsx", ".vue"]);
|
|
30065
30266
|
var IMPORT_PATTERN2 = /import\s+(?:type\s+)?(.+?)\s+from\s+['"]([^'"]+)['"]/g;
|
|
@@ -30188,7 +30389,7 @@ async function buildRepoContextIndex(root, filePaths) {
|
|
|
30188
30389
|
absolutePath,
|
|
30189
30390
|
relativePath: toPosixPath(relative2(resolvedRoot, absolutePath)),
|
|
30190
30391
|
directory: dirname10(absolutePath),
|
|
30191
|
-
text: await
|
|
30392
|
+
text: await readFile14(absolutePath, "utf8").catch(() => "")
|
|
30192
30393
|
})
|
|
30193
30394
|
)
|
|
30194
30395
|
);
|
|
@@ -30401,7 +30602,7 @@ function resolveProjectRoot(sessionId2, projectRootFlag) {
|
|
|
30401
30602
|
db.close();
|
|
30402
30603
|
}
|
|
30403
30604
|
}
|
|
30404
|
-
async function selectBatch(agent, model, batch, total, verbose, skillPathOverride) {
|
|
30605
|
+
async function selectBatch(agent, model, batch, total, verbose, skillPathOverride, existingComponentsInline) {
|
|
30405
30606
|
const prompt2 = await buildPrompt({
|
|
30406
30607
|
skill: "select",
|
|
30407
30608
|
mode: "autonomous",
|
|
@@ -30411,7 +30612,8 @@ async function selectBatch(agent, model, batch, total, verbose, skillPathOverrid
|
|
|
30411
30612
|
2
|
|
30412
30613
|
),
|
|
30413
30614
|
outDir: process.cwd(),
|
|
30414
|
-
skillPathOverride
|
|
30615
|
+
skillPathOverride,
|
|
30616
|
+
existingComponentsInline
|
|
30415
30617
|
});
|
|
30416
30618
|
let outputBuf = "";
|
|
30417
30619
|
const formatter = new OutputFormatter(verbose, (s) => {
|
|
@@ -30506,7 +30708,7 @@ ${outputBuf}`);
|
|
|
30506
30708
|
}
|
|
30507
30709
|
return results;
|
|
30508
30710
|
}
|
|
30509
|
-
async function selectAllComponents(agent, model, components, verbose, skillPathOverride, cacheConfig = { noCache: true }) {
|
|
30711
|
+
async function selectAllComponents(agent, model, components, verbose, skillPathOverride, existingComponentsInline, cacheConfig = { noCache: true }) {
|
|
30510
30712
|
const concurrency = Number(process.env.EDS_GENERATE_CONCURRENCY ?? DEFAULT_CONCURRENCY);
|
|
30511
30713
|
const batchSize = resolveBatchSize();
|
|
30512
30714
|
const total = components.length;
|
|
@@ -30515,7 +30717,13 @@ async function selectAllComponents(agent, model, components, verbose, skillPathO
|
|
|
30515
30717
|
let cliVersion2 = "";
|
|
30516
30718
|
if (!cacheConfig.noCache) {
|
|
30517
30719
|
try {
|
|
30518
|
-
promptHash = await hashPromptForSkill(
|
|
30720
|
+
promptHash = await hashPromptForSkill(
|
|
30721
|
+
"select",
|
|
30722
|
+
agent,
|
|
30723
|
+
model,
|
|
30724
|
+
skillPathOverride,
|
|
30725
|
+
existingComponentsInline ? [hashContent(existingComponentsInline)] : []
|
|
30726
|
+
);
|
|
30519
30727
|
cliVersion2 = await getCliCacheVersion();
|
|
30520
30728
|
const db = openPipelineDb(cacheConfig.dbPath);
|
|
30521
30729
|
try {
|
|
@@ -30571,7 +30779,15 @@ async function selectAllComponents(agent, model, components, verbose, skillPathO
|
|
|
30571
30779
|
while (nextBatch < batches.length) {
|
|
30572
30780
|
const b = nextBatch++;
|
|
30573
30781
|
const batch = batches[b];
|
|
30574
|
-
const batchResults = await selectBatch(
|
|
30782
|
+
const batchResults = await selectBatch(
|
|
30783
|
+
agent,
|
|
30784
|
+
model,
|
|
30785
|
+
batch,
|
|
30786
|
+
total,
|
|
30787
|
+
verbose,
|
|
30788
|
+
skillPathOverride,
|
|
30789
|
+
existingComponentsInline
|
|
30790
|
+
);
|
|
30575
30791
|
for (let k = 0; k < batch.length; k++) {
|
|
30576
30792
|
results[batch[k].index] = batchResults[k];
|
|
30577
30793
|
}
|
|
@@ -30607,6 +30823,9 @@ function registerAnalyzeSelectAgentCommand(program) {
|
|
|
30607
30823
|
"--select-prompt-path <path>",
|
|
30608
30824
|
"Path to a custom .md skill prompt for select-agent (bypasses bundled prompt invariants)"
|
|
30609
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(
|
|
30610
30829
|
"--show-rationale",
|
|
30611
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."
|
|
30612
30831
|
).option("--json", "When used with --show-rationale, emit a JSON array instead of a human-readable table").action(
|
|
@@ -30715,6 +30934,20 @@ function registerAnalyzeSelectAgentCommand(program) {
|
|
|
30715
30934
|
}));
|
|
30716
30935
|
}
|
|
30717
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
|
+
}
|
|
30718
30951
|
if (opts.dryRun) {
|
|
30719
30952
|
if (selectionCandidates.length === 0) {
|
|
30720
30953
|
process.stderr.write(
|
|
@@ -30729,7 +30962,8 @@ function registerAnalyzeSelectAgentCommand(program) {
|
|
|
30729
30962
|
mode: "autonomous",
|
|
30730
30963
|
rawComponentsInline: JSON.stringify([buildComponentData(first)], null, 2),
|
|
30731
30964
|
outDir: process.cwd(),
|
|
30732
|
-
skillPathOverride: selectPromptPath ? resolve12(selectPromptPath) : void 0
|
|
30965
|
+
skillPathOverride: selectPromptPath ? resolve12(selectPromptPath) : void 0,
|
|
30966
|
+
existingComponentsInline
|
|
30733
30967
|
});
|
|
30734
30968
|
process.stdout.write(prompt2 + "\n");
|
|
30735
30969
|
await exitWithAnalytics(0);
|
|
@@ -30742,6 +30976,7 @@ function registerAnalyzeSelectAgentCommand(program) {
|
|
|
30742
30976
|
selectionCandidates,
|
|
30743
30977
|
opts.verbose ?? false,
|
|
30744
30978
|
selectPromptPath ? resolve12(selectPromptPath) : void 0,
|
|
30979
|
+
existingComponentsInline,
|
|
30745
30980
|
{ noCache }
|
|
30746
30981
|
);
|
|
30747
30982
|
const decisions = /* @__PURE__ */ new Map();
|
|
@@ -31129,11 +31364,11 @@ ${f.content}`).join("\n\n");
|
|
|
31129
31364
|
}
|
|
31130
31365
|
|
|
31131
31366
|
// packages/experience-design-system-cli/src/analyze/composition/resolve-mapping-cli.ts
|
|
31132
|
-
import { readFile as
|
|
31367
|
+
import { readFile as readFile15 } from "node:fs/promises";
|
|
31133
31368
|
async function loadUserMap(path) {
|
|
31134
31369
|
let text;
|
|
31135
31370
|
try {
|
|
31136
|
-
text = await
|
|
31371
|
+
text = await readFile15(path, "utf8");
|
|
31137
31372
|
} catch {
|
|
31138
31373
|
return { ok: false, error: `--composition-map: file not found: ${path}` };
|
|
31139
31374
|
}
|
|
@@ -31369,16 +31604,16 @@ var HEAP_CAP_MB = 128;
|
|
|
31369
31604
|
var MAX_INPUT_BYTES = 8 * 1024 * 1024;
|
|
31370
31605
|
function runParserInSandbox(source, ctx, opts = {}) {
|
|
31371
31606
|
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
31372
|
-
return new Promise((
|
|
31607
|
+
return new Promise((resolve28) => {
|
|
31373
31608
|
let input;
|
|
31374
31609
|
try {
|
|
31375
31610
|
input = JSON.stringify({ source, ctx, timeoutMs });
|
|
31376
31611
|
} catch {
|
|
31377
|
-
|
|
31612
|
+
resolve28({ edges: [], error: "ctx is not serializable" });
|
|
31378
31613
|
return;
|
|
31379
31614
|
}
|
|
31380
31615
|
if (input.length > MAX_INPUT_BYTES) {
|
|
31381
|
-
|
|
31616
|
+
resolve28({ edges: [], error: "parser input exceeds size limit" });
|
|
31382
31617
|
return;
|
|
31383
31618
|
}
|
|
31384
31619
|
let settled = false;
|
|
@@ -31410,7 +31645,7 @@ function runParserInSandbox(source, ctx, opts = {}) {
|
|
|
31410
31645
|
child.kill("SIGKILL");
|
|
31411
31646
|
} catch {
|
|
31412
31647
|
}
|
|
31413
|
-
|
|
31648
|
+
resolve28(r);
|
|
31414
31649
|
};
|
|
31415
31650
|
const timer = setTimeout(
|
|
31416
31651
|
() => done({ edges: [], error: `parser timed out after ${timeoutMs}ms` }),
|
|
@@ -31622,7 +31857,7 @@ ${loadPrompt("composition-parser-repair-error.md").trim().replace("{{error}}", f
|
|
|
31622
31857
|
}
|
|
31623
31858
|
|
|
31624
31859
|
// packages/experience-design-system-cli/src/lib/prompt-overrides.ts
|
|
31625
|
-
import { readFile as
|
|
31860
|
+
import { readFile as readFile16 } from "node:fs/promises";
|
|
31626
31861
|
import { resolve as resolve14 } from "node:path";
|
|
31627
31862
|
var PROMPT_FILE_EXTENSIONS = [".md", ".txt", ".prompt"];
|
|
31628
31863
|
function looksLikePath(value) {
|
|
@@ -31658,7 +31893,7 @@ async function resolvePromptOverride(override) {
|
|
|
31658
31893
|
if (override.kind === "text") return override.value;
|
|
31659
31894
|
const abs = resolve14(override.value);
|
|
31660
31895
|
try {
|
|
31661
|
-
return await
|
|
31896
|
+
return await readFile16(abs, "utf8");
|
|
31662
31897
|
} catch {
|
|
31663
31898
|
throw new Error(`--prompt: could not read prompt file: ${abs}`);
|
|
31664
31899
|
}
|
|
@@ -31841,7 +32076,7 @@ async function readCandidateFiles(components, extraFiles = []) {
|
|
|
31841
32076
|
await Promise.all(
|
|
31842
32077
|
[...paths].map(async (p) => {
|
|
31843
32078
|
try {
|
|
31844
|
-
const content = await
|
|
32079
|
+
const content = await readFile17(p, "utf8");
|
|
31845
32080
|
out.push({ path: p, content });
|
|
31846
32081
|
} catch {
|
|
31847
32082
|
}
|
|
@@ -32245,7 +32480,7 @@ function registerAnalyzeCommand(program) {
|
|
|
32245
32480
|
init_src();
|
|
32246
32481
|
import { createElement as createElement4 } from "react";
|
|
32247
32482
|
import { render as render4 } from "ink";
|
|
32248
|
-
import { access as access6, readFile as
|
|
32483
|
+
import { access as access6, readFile as readFile19, readdir as readdir3, stat as stat3 } from "node:fs/promises";
|
|
32249
32484
|
import { join as join16, resolve as resolve17 } from "node:path";
|
|
32250
32485
|
init_debug_logger();
|
|
32251
32486
|
|
|
@@ -32286,7 +32521,7 @@ function GenerateView({ result, onExit }) {
|
|
|
32286
32521
|
}
|
|
32287
32522
|
|
|
32288
32523
|
// packages/experience-design-system-cli/src/generate/edit/command.ts
|
|
32289
|
-
import { readFile as
|
|
32524
|
+
import { readFile as readFile18 } from "node:fs/promises";
|
|
32290
32525
|
import { resolve as resolve16 } from "node:path";
|
|
32291
32526
|
var SAFE_PATH_RE2 = /^[a-zA-Z0-9_.$[\]=]+$/;
|
|
32292
32527
|
var PROTO_KEYS2 = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
@@ -32369,7 +32604,7 @@ async function runNonInteractive2(opts, skill) {
|
|
|
32369
32604
|
if (opts.patch) {
|
|
32370
32605
|
let patchOps;
|
|
32371
32606
|
try {
|
|
32372
|
-
const raw = await
|
|
32607
|
+
const raw = await readFile18(resolve16(opts.patch), "utf8");
|
|
32373
32608
|
patchOps = JSON.parse(raw);
|
|
32374
32609
|
} catch {
|
|
32375
32610
|
process.stderr.write(`Error: cannot read or parse --patch file: ${opts.patch}
|
|
@@ -32463,7 +32698,7 @@ async function readFileInline(path) {
|
|
|
32463
32698
|
} catch {
|
|
32464
32699
|
return void 0;
|
|
32465
32700
|
}
|
|
32466
|
-
if (!s.isDirectory()) return
|
|
32701
|
+
if (!s.isDirectory()) return readFile19(resolved, "utf8");
|
|
32467
32702
|
const files = [];
|
|
32468
32703
|
async function walk(dir) {
|
|
32469
32704
|
let entries;
|
|
@@ -32489,7 +32724,7 @@ async function readFileInline(path) {
|
|
|
32489
32724
|
}
|
|
32490
32725
|
await walk(resolved);
|
|
32491
32726
|
if (files.length === 0) return void 0;
|
|
32492
|
-
const parts = await Promise.all(files.map((f) =>
|
|
32727
|
+
const parts = await Promise.all(files.map((f) => readFile19(f, "utf8").catch(() => "")));
|
|
32493
32728
|
return parts.filter(Boolean).join("\n\n");
|
|
32494
32729
|
}
|
|
32495
32730
|
function printFallbackInstructions(options) {
|
|
@@ -32511,7 +32746,7 @@ function printFallbackInstructions(options) {
|
|
|
32511
32746
|
lines.push(` Re-run the generate command with the agent available, or use --dry-run to inspect the prompt.`);
|
|
32512
32747
|
process.stderr.write(lines.join("\n") + "\n");
|
|
32513
32748
|
}
|
|
32514
|
-
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) {
|
|
32515
32750
|
const pos = c.dim(`[${index + 1}/${total}]`);
|
|
32516
32751
|
if (!noCache) {
|
|
32517
32752
|
const inputHash = computeComponentInputHash(component);
|
|
@@ -32581,6 +32816,7 @@ async function runOneComponent(agent, model, db, sessionId2, component, tokensIn
|
|
|
32581
32816
|
component.props.map((p) => p.name),
|
|
32582
32817
|
component.props.map((p) => p.type)
|
|
32583
32818
|
);
|
|
32819
|
+
const existingComponentsInline = existingContentfulEntities ? JSON.stringify(summarizeForGenerateAgent(existingContentfulEntities, component.name)) : void 0;
|
|
32584
32820
|
const prompt2 = await buildPrompt({
|
|
32585
32821
|
skill: "components",
|
|
32586
32822
|
mode: "autonomous",
|
|
@@ -32590,7 +32826,9 @@ async function runOneComponent(agent, model, db, sessionId2, component, tokensIn
|
|
|
32590
32826
|
outDir: process.cwd(),
|
|
32591
32827
|
componentName: component.name,
|
|
32592
32828
|
componentSourceRefs: [sourceRef],
|
|
32593
|
-
skillPathOverride
|
|
32829
|
+
skillPathOverride,
|
|
32830
|
+
existingComponentsInline,
|
|
32831
|
+
existingTokensInline
|
|
32594
32832
|
});
|
|
32595
32833
|
const maxAttempts = 2;
|
|
32596
32834
|
let lastError = "";
|
|
@@ -32658,7 +32896,7 @@ ${outputBuf}`);
|
|
|
32658
32896
|
renamedSlotsCount: renames.length
|
|
32659
32897
|
};
|
|
32660
32898
|
}
|
|
32661
|
-
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) {
|
|
32662
32900
|
const concurrency = Number(process.env.EDS_GENERATE_CONCURRENCY ?? DEFAULT_COMPONENT_CONCURRENCY);
|
|
32663
32901
|
process.stderr.write(
|
|
32664
32902
|
`Categorizing ${c.bold(String(components.length))} component${components.length === 1 ? "" : "s"}` + c.dim(` (concurrency: ${concurrency})`) + "\n"
|
|
@@ -32682,7 +32920,9 @@ async function runAllComponents(agent, model, db, sessionId2, components, tokens
|
|
|
32682
32920
|
verbose,
|
|
32683
32921
|
noCache,
|
|
32684
32922
|
skillPathOverride,
|
|
32685
|
-
promptHash
|
|
32923
|
+
promptHash,
|
|
32924
|
+
existingContentfulEntities,
|
|
32925
|
+
existingTokensInline
|
|
32686
32926
|
);
|
|
32687
32927
|
completed += 1;
|
|
32688
32928
|
process.stderr.write(`${formatGenerateProgressLine(completed, components.length, results[i].componentName)}
|
|
@@ -32720,7 +32960,7 @@ async function loadAcceptedNames(sessionId2) {
|
|
|
32720
32960
|
try {
|
|
32721
32961
|
const artifactsRoot = getRefineArtifactsRoot();
|
|
32722
32962
|
const paths = await getRefineSessionPaths(sessionId2, artifactsRoot);
|
|
32723
|
-
const raw = await
|
|
32963
|
+
const raw = await readFile19(paths.statePath, "utf8");
|
|
32724
32964
|
const snapshot = JSON.parse(raw);
|
|
32725
32965
|
const accepted = snapshot.components.filter((c2) => c2.status === "accepted").map((c2) => c2.name);
|
|
32726
32966
|
if (accepted.length === 0) return null;
|
|
@@ -32766,6 +33006,19 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
32766
33006
|
readFileInline(opts.tokens),
|
|
32767
33007
|
readFileInline(opts.tokenMap)
|
|
32768
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
|
+
}
|
|
32769
33022
|
let sessionId2;
|
|
32770
33023
|
let allComponents;
|
|
32771
33024
|
if (skill === "components") {
|
|
@@ -32826,6 +33079,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
32826
33079
|
sampleComponent.props.map((p) => p.name),
|
|
32827
33080
|
sampleComponent.props.map((p) => p.type)
|
|
32828
33081
|
) : void 0;
|
|
33082
|
+
const dryRunExistingComponentsInline = skill === "components" && existingContentfulEntities && sampleComponent ? JSON.stringify(summarizeForGenerateAgent(existingContentfulEntities, sampleComponent.name)) : void 0;
|
|
32829
33083
|
const prompt2 = await buildPrompt({
|
|
32830
33084
|
skill,
|
|
32831
33085
|
mode: "autonomous",
|
|
@@ -32836,7 +33090,9 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
32836
33090
|
tokenMapInline,
|
|
32837
33091
|
outDir: process.cwd(),
|
|
32838
33092
|
componentSourceRefs: sampleSourceRef ? [sampleSourceRef] : void 0,
|
|
32839
|
-
skillPathOverride: generatePromptPath
|
|
33093
|
+
skillPathOverride: generatePromptPath,
|
|
33094
|
+
existingComponentsInline: dryRunExistingComponentsInline,
|
|
33095
|
+
existingTokensInline: skill === "components" ? existingTokensInline : void 0
|
|
32840
33096
|
});
|
|
32841
33097
|
process.stdout.write(prompt2 + "\n");
|
|
32842
33098
|
await exitWithAnalytics(0);
|
|
@@ -32854,7 +33110,15 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
32854
33110
|
const db = openPipelineDb();
|
|
32855
33111
|
let componentResults;
|
|
32856
33112
|
try {
|
|
32857
|
-
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
|
+
);
|
|
32858
33122
|
componentResults = await runAllComponents(
|
|
32859
33123
|
agent,
|
|
32860
33124
|
model,
|
|
@@ -32866,7 +33130,9 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
32866
33130
|
verbose,
|
|
32867
33131
|
opts.cache === false || process.env.EDS_NO_CACHE === "1",
|
|
32868
33132
|
generatePromptPath,
|
|
32869
|
-
promptHash
|
|
33133
|
+
promptHash,
|
|
33134
|
+
existingContentfulEntities,
|
|
33135
|
+
existingTokensInline
|
|
32870
33136
|
);
|
|
32871
33137
|
} finally {
|
|
32872
33138
|
db.close();
|
|
@@ -33043,6 +33309,9 @@ function registerGenerateCommand(program) {
|
|
|
33043
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(
|
|
33044
33310
|
"--generate-prompt-path <path>",
|
|
33045
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."
|
|
33046
33315
|
);
|
|
33047
33316
|
addAgentFlags(componentsCmd).action(async (opts) => {
|
|
33048
33317
|
await runGenerateSkill("components", opts, opts.verbose ?? false);
|
|
@@ -33489,9 +33758,9 @@ ${"\u2500".repeat(60)}
|
|
|
33489
33758
|
`);
|
|
33490
33759
|
}
|
|
33491
33760
|
process.stdout.write("\nDelete these sessions? (y/N) ");
|
|
33492
|
-
const answer = await new Promise((
|
|
33761
|
+
const answer = await new Promise((resolve28) => {
|
|
33493
33762
|
process.stdin.setEncoding("utf8");
|
|
33494
|
-
process.stdin.once("data", (chunk) =>
|
|
33763
|
+
process.stdin.once("data", (chunk) => resolve28(String(chunk).trim().toLowerCase()));
|
|
33495
33764
|
});
|
|
33496
33765
|
if (answer !== "y") {
|
|
33497
33766
|
db.close();
|
|
@@ -33526,7 +33795,7 @@ import { access as access7, mkdir as mkdir4, stat as stat4, writeFile as writeFi
|
|
|
33526
33795
|
import { basename as basename5, resolve as resolve19 } from "node:path";
|
|
33527
33796
|
|
|
33528
33797
|
// packages/experience-design-system-cli/src/print/validate/validators/cdf-validator.ts
|
|
33529
|
-
import { readFile as
|
|
33798
|
+
import { readFile as readFile20 } from "node:fs/promises";
|
|
33530
33799
|
import { validateCDF as validateCDF2 } from "@contentful/experience-design-system-types";
|
|
33531
33800
|
function extractValue(input, path) {
|
|
33532
33801
|
if (path === "/") return void 0;
|
|
@@ -33585,7 +33854,7 @@ function rewriteDiagnostic(error, input) {
|
|
|
33585
33854
|
async function validateCDFFile(filePath) {
|
|
33586
33855
|
let content;
|
|
33587
33856
|
try {
|
|
33588
|
-
content = await
|
|
33857
|
+
content = await readFile20(filePath, "utf-8");
|
|
33589
33858
|
} catch (err) {
|
|
33590
33859
|
return {
|
|
33591
33860
|
valid: false,
|
|
@@ -33620,7 +33889,7 @@ async function validateCDFFile(filePath) {
|
|
|
33620
33889
|
}
|
|
33621
33890
|
|
|
33622
33891
|
// packages/experience-design-system-cli/src/print/validate/validators/dtcg-validator.ts
|
|
33623
|
-
import { readFile as
|
|
33892
|
+
import { readFile as readFile21 } from "node:fs/promises";
|
|
33624
33893
|
import { DESIGN_TOKEN_TYPES } from "@contentful/experience-design-system-types";
|
|
33625
33894
|
function walkDTCG(obj, path, diagnostics, counts) {
|
|
33626
33895
|
for (const [key, value] of Object.entries(obj)) {
|
|
@@ -33665,7 +33934,7 @@ function walkDTCG(obj, path, diagnostics, counts) {
|
|
|
33665
33934
|
async function validateDTCGTokenFile(filePath) {
|
|
33666
33935
|
let content;
|
|
33667
33936
|
try {
|
|
33668
|
-
content = await
|
|
33937
|
+
content = await readFile21(filePath, "utf-8");
|
|
33669
33938
|
} catch (err) {
|
|
33670
33939
|
return {
|
|
33671
33940
|
valid: false,
|
|
@@ -33998,7 +34267,8 @@ init_db();
|
|
|
33998
34267
|
init_cache_keys();
|
|
33999
34268
|
import { createElement as createElement6 } from "react";
|
|
34000
34269
|
import { render as render6 } from "ink";
|
|
34001
|
-
import { readFile as
|
|
34270
|
+
import { readFile as readFile22 } from "node:fs/promises";
|
|
34271
|
+
import { resolve as resolve20 } from "node:path";
|
|
34002
34272
|
|
|
34003
34273
|
// packages/experience-design-system-cli/src/map-tokens/apply.ts
|
|
34004
34274
|
init_db();
|
|
@@ -34246,7 +34516,7 @@ async function runMapTokens(opts) {
|
|
|
34246
34516
|
const knownTokenPaths = new Set(tokenLeaves.map((t) => t.path));
|
|
34247
34517
|
const tokenMapDiagnostics = [];
|
|
34248
34518
|
if (opts.tokenMap) {
|
|
34249
|
-
const fileMappings = JSON.parse(await
|
|
34519
|
+
const fileMappings = JSON.parse(await readFile22(opts.tokenMap, "utf8"));
|
|
34250
34520
|
const validMappings = {};
|
|
34251
34521
|
for (const [rawName, path] of Object.entries(fileMappings)) {
|
|
34252
34522
|
if (knownTokenPaths.has(path)) {
|
|
@@ -34321,6 +34591,20 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
|
|
|
34321
34591
|
const generatedCdf = Object.fromEntries(cdfEntries.map((c2) => [c2.key, c2.entry]));
|
|
34322
34592
|
const tokenTree = rebuildDTCGTree(groups, tokens);
|
|
34323
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
|
+
}
|
|
34324
34608
|
if (opts.printPrompt) {
|
|
34325
34609
|
const prompt3 = await buildPrompt({
|
|
34326
34610
|
skill: "map-tokens",
|
|
@@ -34328,7 +34612,8 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
|
|
|
34328
34612
|
generatedCdf,
|
|
34329
34613
|
tokenTree,
|
|
34330
34614
|
componentSourceRefs,
|
|
34331
|
-
outDir: process.cwd()
|
|
34615
|
+
outDir: process.cwd(),
|
|
34616
|
+
existingTokensInline
|
|
34332
34617
|
});
|
|
34333
34618
|
process.stdout.write(prompt3 + "\n");
|
|
34334
34619
|
await exitWithAnalytics(0);
|
|
@@ -34346,7 +34631,13 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
|
|
|
34346
34631
|
}
|
|
34347
34632
|
const agent = configuredAgent;
|
|
34348
34633
|
const noCache = opts.cache === false || process.env.EDS_NO_CACHE === "1";
|
|
34349
|
-
const promptHash = await hashPromptForSkill(
|
|
34634
|
+
const promptHash = await hashPromptForSkill(
|
|
34635
|
+
"map-tokens",
|
|
34636
|
+
agent,
|
|
34637
|
+
model,
|
|
34638
|
+
void 0,
|
|
34639
|
+
existingTokensInline ? [hashContent(existingTokensInline)] : []
|
|
34640
|
+
);
|
|
34350
34641
|
const inputHash = computeMapTokensInputHash(db, sessionId2, componentSourceRefs);
|
|
34351
34642
|
if (!noCache) {
|
|
34352
34643
|
const cached = lookupCache(db, inputHash, "token_mapping", "__map_tokens__", promptHash);
|
|
@@ -34373,7 +34664,8 @@ Install it, choose another agent with --agent, or use --print-prompt to run the
|
|
|
34373
34664
|
generatedCdf,
|
|
34374
34665
|
tokenTree,
|
|
34375
34666
|
componentSourceRefs,
|
|
34376
|
-
outDir: process.cwd()
|
|
34667
|
+
outDir: process.cwd(),
|
|
34668
|
+
existingTokensInline
|
|
34377
34669
|
});
|
|
34378
34670
|
const invoker3 = createLocalCliAgentInvoker();
|
|
34379
34671
|
const result = await invoker3.invoke({ agent, model, prompt: prompt2, timeoutMs: DEFAULT_TIMEOUT_MS4 });
|
|
@@ -34400,7 +34692,10 @@ ${warnings.map((w) => ` ${w}`).join("\n")}
|
|
|
34400
34692
|
}
|
|
34401
34693
|
function registerMapTokensCommand(program) {
|
|
34402
34694
|
const map = program.command("map").description("Suggest token restrictions for generated design-token props");
|
|
34403
|
-
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
|
+
);
|
|
34404
34699
|
addAgentModelOptions(tokensCmd).action(async (opts) => {
|
|
34405
34700
|
await runMapTokens(opts);
|
|
34406
34701
|
});
|
|
@@ -34409,45 +34704,22 @@ function registerMapTokensCommand(program) {
|
|
|
34409
34704
|
// packages/experience-design-system-cli/src/import/command.ts
|
|
34410
34705
|
init_src();
|
|
34411
34706
|
init_path_utils();
|
|
34412
|
-
import { resolve as
|
|
34707
|
+
import { resolve as resolve26, join as join26 } from "node:path";
|
|
34413
34708
|
|
|
34414
34709
|
// packages/experience-design-system-cli/src/import/orchestrator.ts
|
|
34415
34710
|
init_db();
|
|
34416
34711
|
init_command();
|
|
34417
34712
|
init_manifest();
|
|
34418
34713
|
init_api_client();
|
|
34419
|
-
|
|
34420
|
-
import { join as join18, resolve as resolve21 } from "node:path";
|
|
34421
|
-
import { execFile as execFile2 } from "node:child_process";
|
|
34422
|
-
|
|
34423
|
-
// packages/experience-design-system-cli/src/helpers/fetch-existing-entities.ts
|
|
34424
|
-
import { fetchAll } from "contentful-management";
|
|
34425
|
-
async function fetchExistingEntities(client2, params) {
|
|
34426
|
-
const scope = { spaceId: params.spaceId, environmentId: params.environmentId, query: {} };
|
|
34427
|
-
const components = await fetchAll(client2.component.getMany, scope);
|
|
34428
|
-
const tokens = await fetchAll(client2.designToken.getMany, scope);
|
|
34429
|
-
return { components, tokens };
|
|
34430
|
-
}
|
|
34431
|
-
|
|
34432
|
-
// packages/experience-design-system-cli/src/helpers/cma-client.ts
|
|
34433
|
-
init_host_utils();
|
|
34434
|
-
import { createClient as createClient2 } from "contentful-management";
|
|
34435
|
-
function createCmaClient(opts) {
|
|
34436
|
-
return createClient2(
|
|
34437
|
-
{
|
|
34438
|
-
accessToken: opts.cmaToken,
|
|
34439
|
-
...opts.host ? { host: toConfiguredHost(opts.host) } : {}
|
|
34440
|
-
},
|
|
34441
|
-
{ type: "plain" }
|
|
34442
|
-
);
|
|
34443
|
-
}
|
|
34444
|
-
|
|
34445
|
-
// packages/experience-design-system-cli/src/import/orchestrator.ts
|
|
34714
|
+
init_fetch_and_persist_existing_contentful_entities();
|
|
34446
34715
|
init_contentful_urls();
|
|
34447
34716
|
init_debug_logger();
|
|
34448
34717
|
init_analytics();
|
|
34449
34718
|
init_env();
|
|
34450
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";
|
|
34451
34723
|
async function runStep(args, cliPath, analyticsSessionId, env = {}, streamStderr = false) {
|
|
34452
34724
|
const debug = getDebugLogger();
|
|
34453
34725
|
const startedAt = Date.now();
|
|
@@ -34532,9 +34804,9 @@ function buildPushStepResult(args) {
|
|
|
34532
34804
|
};
|
|
34533
34805
|
}
|
|
34534
34806
|
async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
34535
|
-
const projectRoot =
|
|
34536
|
-
const outDir =
|
|
34537
|
-
const componentsPath =
|
|
34807
|
+
const projectRoot = resolve22(opts.project);
|
|
34808
|
+
const outDir = resolve22(opts.out);
|
|
34809
|
+
const componentsPath = join19(outDir, "components.json");
|
|
34538
34810
|
const cliPath = cliPathOverride ?? findCliPath();
|
|
34539
34811
|
const db = openPipelineDb();
|
|
34540
34812
|
const { sessionId: sessionId2 } = getOrCreateSession(db, void 0, void 0, {
|
|
@@ -34555,67 +34827,56 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
34555
34827
|
await mkdir5(outDir, { recursive: true });
|
|
34556
34828
|
const steps = [];
|
|
34557
34829
|
let stepNum = 0;
|
|
34558
|
-
const
|
|
34559
|
-
const
|
|
34560
|
-
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);
|
|
34561
34832
|
function stepLabel(name) {
|
|
34562
34833
|
stepNum++;
|
|
34563
34834
|
return ` Step ${stepNum}/${totalSteps} ${name} `;
|
|
34564
34835
|
}
|
|
34565
|
-
|
|
34566
|
-
|
|
34567
|
-
" Note: --with-space-context requires --space-id, --environment-id, and --cma-token; skipping context fetch."
|
|
34568
|
-
);
|
|
34569
|
-
}
|
|
34570
|
-
if (canFetchSpaceContext) {
|
|
34836
|
+
let existingEntitiesPath;
|
|
34837
|
+
if (canFetchExistingContentfulEntities) {
|
|
34571
34838
|
const fetchLabel = stepLabel("Fetching existing components + design tokens");
|
|
34572
34839
|
const fetchStepId = createStep(db, sessionId2, "fetch existing entities", {
|
|
34573
34840
|
spaceId: opts.spaceId,
|
|
34574
34841
|
environmentId: opts.environmentId
|
|
34575
34842
|
});
|
|
34576
|
-
const
|
|
34577
|
-
|
|
34578
|
-
|
|
34579
|
-
|
|
34580
|
-
|
|
34581
|
-
|
|
34582
|
-
|
|
34583
|
-
|
|
34584
|
-
|
|
34585
|
-
});
|
|
34586
|
-
const fetchDurationMs = Date.now() - t0;
|
|
34587
|
-
const existingEntitiesPath = join18(outDir, ".existing-entities.json");
|
|
34588
|
-
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;
|
|
34589
34852
|
updateStep(db, fetchStepId, "complete", {
|
|
34590
|
-
components: String(
|
|
34591
|
-
tokens: String(
|
|
34592
|
-
path:
|
|
34853
|
+
components: String(result.entities.components.length),
|
|
34854
|
+
tokens: String(result.entities.tokens.length),
|
|
34855
|
+
path: result.path
|
|
34593
34856
|
});
|
|
34594
34857
|
progressWriter(
|
|
34595
|
-
`${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)`
|
|
34596
34859
|
);
|
|
34597
34860
|
steps.push({
|
|
34598
34861
|
step: "fetch existing entities",
|
|
34599
34862
|
status: "complete",
|
|
34600
|
-
durationMs:
|
|
34863
|
+
durationMs: result.durationMs,
|
|
34601
34864
|
detail: {
|
|
34602
|
-
components:
|
|
34603
|
-
tokens:
|
|
34865
|
+
components: result.entities.components.length,
|
|
34866
|
+
tokens: result.entities.tokens.length
|
|
34604
34867
|
}
|
|
34605
34868
|
});
|
|
34606
|
-
}
|
|
34607
|
-
|
|
34608
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
34609
|
-
updateStep(db, fetchStepId, "complete", {}, message);
|
|
34869
|
+
} else {
|
|
34870
|
+
updateStep(db, fetchStepId, "complete", {}, result.error);
|
|
34610
34871
|
progressWriter(
|
|
34611
|
-
`${fetchLabel}\u26A0 fetch failed, continuing without space context (${(
|
|
34872
|
+
`${fetchLabel}\u26A0 fetch failed, continuing without space context (${(result.durationMs / 1e3).toFixed(1)}s)`
|
|
34612
34873
|
);
|
|
34613
|
-
progressWriter(` ${
|
|
34874
|
+
progressWriter(` ${result.error.split("\n")[0]}`);
|
|
34614
34875
|
steps.push({
|
|
34615
34876
|
step: "fetch existing entities",
|
|
34616
34877
|
status: "skipped",
|
|
34617
|
-
durationMs:
|
|
34618
|
-
reason: `fetch failed: ${
|
|
34878
|
+
durationMs: result.durationMs,
|
|
34879
|
+
reason: `fetch failed: ${result.error.split("\n")[0]}`
|
|
34619
34880
|
});
|
|
34620
34881
|
}
|
|
34621
34882
|
}
|
|
@@ -34701,6 +34962,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
34701
34962
|
if (opts.excludeInvalid) editArgs.push("--exclude-invalid");
|
|
34702
34963
|
if (opts.noCache) editArgs.push("--no-cache");
|
|
34703
34964
|
if (opts.selectPromptPath) editArgs.push("--select-prompt-path", opts.selectPromptPath);
|
|
34965
|
+
if (existingEntitiesPath) editArgs.push("--existing-entities-path", existingEntitiesPath);
|
|
34704
34966
|
} else {
|
|
34705
34967
|
editArgs = ["analyze", "select", "--session", extractSessionId];
|
|
34706
34968
|
if (opts.select && opts.select.length > 0) {
|
|
@@ -34763,6 +35025,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
34763
35025
|
if (extractSessionId) generateArgs.push("--session", extractSessionId);
|
|
34764
35026
|
if (opts.dryRun) generateArgs.push("--dry-run");
|
|
34765
35027
|
if (opts.verbose) generateArgs.push("--verbose");
|
|
35028
|
+
if (existingEntitiesPath) generateArgs.push("--existing-entities-path", existingEntitiesPath);
|
|
34766
35029
|
const stepId = createStep(db, sessionId2, "generate components", {
|
|
34767
35030
|
extractSession: extractSessionId ?? ""
|
|
34768
35031
|
});
|
|
@@ -34817,6 +35080,7 @@ async function runPipeline(opts, progressWriter, cliPathOverride) {
|
|
|
34817
35080
|
if (opts.model) mapTokensArgs.push("--model", opts.model);
|
|
34818
35081
|
if (opts.noCache) mapTokensArgs.push("--no-cache");
|
|
34819
35082
|
if (opts.skipMapTokens) mapTokensArgs.push("--skip-agent");
|
|
35083
|
+
if (existingEntitiesPath) mapTokensArgs.push("--existing-entities-path", existingEntitiesPath);
|
|
34820
35084
|
const mapTokensStepId = createStep(db, sessionId2, "map tokens", {
|
|
34821
35085
|
extractSession: extractSessionId,
|
|
34822
35086
|
skipAgent: String(opts.skipMapTokens === true)
|
|
@@ -35178,7 +35442,7 @@ init_host_utils();
|
|
|
35178
35442
|
// packages/experience-design-system-cli/src/runs/replay-helpers.ts
|
|
35179
35443
|
init_resolve_run_target();
|
|
35180
35444
|
init_store();
|
|
35181
|
-
import { resolve as
|
|
35445
|
+
import { resolve as resolve25 } from "node:path";
|
|
35182
35446
|
|
|
35183
35447
|
// packages/experience-design-system-cli/src/runs/push-helpers.ts
|
|
35184
35448
|
init_cli_path();
|
|
@@ -35368,7 +35632,7 @@ async function modifyRun(opts) {
|
|
|
35368
35632
|
entryStep: "final-review",
|
|
35369
35633
|
saveMode,
|
|
35370
35634
|
...run.compositionMode ? { compositionMode: run.compositionMode } : {},
|
|
35371
|
-
...opts.outDir ? { outDirOverride:
|
|
35635
|
+
...opts.outDir ? { outDirOverride: resolve25(opts.outDir) } : {},
|
|
35372
35636
|
...mergedSpaceId ? { initialSpaceId: mergedSpaceId } : {},
|
|
35373
35637
|
...mergedEnvironmentId ? { initialEnvironmentId: mergedEnvironmentId } : {},
|
|
35374
35638
|
...mergedHost ? { initialHost: mergedHost } : {},
|
|
@@ -35445,7 +35709,7 @@ function resolvePromptFlags(flags) {
|
|
|
35445
35709
|
|
|
35446
35710
|
// packages/experience-design-system-cli/src/runs/run-picker-mount.ts
|
|
35447
35711
|
init_store();
|
|
35448
|
-
import { readFile as
|
|
35712
|
+
import { readFile as readFile27 } from "node:fs/promises";
|
|
35449
35713
|
function migrateRecord2(rec) {
|
|
35450
35714
|
return {
|
|
35451
35715
|
...rec,
|
|
@@ -35468,7 +35732,7 @@ async function shouldShowRunPicker(input) {
|
|
|
35468
35732
|
const path = input.runsJsonPath ?? runsFilePath();
|
|
35469
35733
|
let raw;
|
|
35470
35734
|
try {
|
|
35471
|
-
raw = await
|
|
35735
|
+
raw = await readFile27(path, "utf8");
|
|
35472
35736
|
} catch {
|
|
35473
35737
|
return { shouldShow: false, runs: [] };
|
|
35474
35738
|
}
|
|
@@ -35573,10 +35837,7 @@ function registerImportCommand(program) {
|
|
|
35573
35837
|
"Override a stage prompt (repeatable). value is a file path or literal text, e.g. --prompt composition=./p.md",
|
|
35574
35838
|
(v, acc) => [...acc, v],
|
|
35575
35839
|
[]
|
|
35576
|
-
).option("--auto-reject-cycles", "Automatically reject components involved in slot cycles and retry").option(
|
|
35577
|
-
"--with-space-context",
|
|
35578
|
-
"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."
|
|
35579
|
-
).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(
|
|
35580
35841
|
"--no-auto-filter",
|
|
35581
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)"
|
|
35582
35843
|
).option(
|
|
@@ -35844,7 +36105,7 @@ function registerImportCommand(program) {
|
|
|
35844
36105
|
livePreview: opts.livePreview !== false,
|
|
35845
36106
|
noPush: noPushRequested,
|
|
35846
36107
|
noSave: opts.save === false,
|
|
35847
|
-
...opts.outDir ? { outDirOverride:
|
|
36108
|
+
...opts.outDir ? { outDirOverride: resolve26(opts.outDir) } : {},
|
|
35848
36109
|
...opts.onConflict ? { onConflictMode: opts.onConflict } : {},
|
|
35849
36110
|
selectPromptPath: opts.selectPromptPath ?? creds.selectPromptPath,
|
|
35850
36111
|
generatePromptPath: opts.generatePromptPath ?? creds.generatePromptPath,
|
|
@@ -35885,7 +36146,7 @@ function registerImportCommand(program) {
|
|
|
35885
36146
|
return;
|
|
35886
36147
|
}
|
|
35887
36148
|
const projectRoot = normalizePath(opts.project);
|
|
35888
|
-
const outDir = opts.out ?
|
|
36149
|
+
const outDir = opts.out ? resolve26(opts.out) : join26(projectRoot, ".contentful");
|
|
35889
36150
|
const headlessCreds = await readExperiencesCredentials();
|
|
35890
36151
|
const headlessAgent = resolveAgent(opts.agent, headlessCreds.agent);
|
|
35891
36152
|
const headlessModel = resolveModel(opts.model, headlessCreds.agentModel);
|
|
@@ -35923,7 +36184,6 @@ function registerImportCommand(program) {
|
|
|
35923
36184
|
dryRun: dryRunForward,
|
|
35924
36185
|
selectPromptPath: opts.selectPromptPath,
|
|
35925
36186
|
autoRejectCycles: opts.autoRejectCycles ?? false,
|
|
35926
|
-
withSpaceContext: opts.withSpaceContext ?? false,
|
|
35927
36187
|
allowDeletions: opts.allowDeletions ?? false,
|
|
35928
36188
|
compositionMode: headlessCompositionMode,
|
|
35929
36189
|
...opts.compositionMap ? { compositionMap: opts.compositionMap } : {},
|
|
@@ -35948,8 +36208,8 @@ function registerImportCommand(program) {
|
|
|
35948
36208
|
// packages/experience-design-system-cli/src/setup/command.ts
|
|
35949
36209
|
init_credentials_store();
|
|
35950
36210
|
import { execFile as execFile5, spawn as spawn5 } from "node:child_process";
|
|
35951
|
-
import { appendFile as appendFile2, readFile as
|
|
35952
|
-
import { join as
|
|
36211
|
+
import { appendFile as appendFile2, readFile as readFile28, access as access10 } from "node:fs/promises";
|
|
36212
|
+
import { join as join27 } from "node:path";
|
|
35953
36213
|
import { homedir as homedir9 } from "node:os";
|
|
35954
36214
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
35955
36215
|
import { createInterface } from "node:readline";
|
|
@@ -36027,10 +36287,10 @@ function prompt(question) {
|
|
|
36027
36287
|
return Promise.resolve("");
|
|
36028
36288
|
}
|
|
36029
36289
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
36030
|
-
return new Promise((
|
|
36290
|
+
return new Promise((resolve28) => {
|
|
36031
36291
|
rl.question(question, (answer) => {
|
|
36032
36292
|
rl.close();
|
|
36033
|
-
|
|
36293
|
+
resolve28(answer.trim());
|
|
36034
36294
|
});
|
|
36035
36295
|
});
|
|
36036
36296
|
}
|
|
@@ -36038,7 +36298,7 @@ function promptSecret(question) {
|
|
|
36038
36298
|
if (!isInteractivePromptSession()) {
|
|
36039
36299
|
return Promise.resolve("");
|
|
36040
36300
|
}
|
|
36041
|
-
return new Promise((
|
|
36301
|
+
return new Promise((resolve28) => {
|
|
36042
36302
|
const rl = createInterface({
|
|
36043
36303
|
input: process.stdin,
|
|
36044
36304
|
output: process.stdout,
|
|
@@ -36065,7 +36325,7 @@ function promptSecret(question) {
|
|
|
36065
36325
|
}
|
|
36066
36326
|
if (!process.stdin.isTTY) process.stdout.write("\n");
|
|
36067
36327
|
process.stdin.resume();
|
|
36068
|
-
|
|
36328
|
+
resolve28(value);
|
|
36069
36329
|
});
|
|
36070
36330
|
});
|
|
36071
36331
|
}
|
|
@@ -36087,7 +36347,7 @@ async function binaryExists(name) {
|
|
|
36087
36347
|
}
|
|
36088
36348
|
}
|
|
36089
36349
|
function runSpawn(cmd, args, opts = {}) {
|
|
36090
|
-
return new Promise((
|
|
36350
|
+
return new Promise((resolve28) => {
|
|
36091
36351
|
const child = spawn5(cmd, args, {
|
|
36092
36352
|
cwd: opts.cwd,
|
|
36093
36353
|
env: opts.env ?? process.env,
|
|
@@ -36099,7 +36359,7 @@ function runSpawn(cmd, args, opts = {}) {
|
|
|
36099
36359
|
child.on("error", (err) => {
|
|
36100
36360
|
if (!settled) {
|
|
36101
36361
|
settled = true;
|
|
36102
|
-
|
|
36362
|
+
resolve28({ exitCode: 1, stdout: "", stderr: err.message });
|
|
36103
36363
|
}
|
|
36104
36364
|
});
|
|
36105
36365
|
child.stdout.on("data", (d) => {
|
|
@@ -36111,7 +36371,7 @@ function runSpawn(cmd, args, opts = {}) {
|
|
|
36111
36371
|
child.on("exit", (code) => {
|
|
36112
36372
|
if (!settled) {
|
|
36113
36373
|
settled = true;
|
|
36114
|
-
|
|
36374
|
+
resolve28({ exitCode: code ?? 1, stdout, stderr });
|
|
36115
36375
|
}
|
|
36116
36376
|
});
|
|
36117
36377
|
});
|
|
@@ -36120,21 +36380,21 @@ async function detectShellProfile() {
|
|
|
36120
36380
|
const shell = process.env["SHELL"] ?? "";
|
|
36121
36381
|
const home = homedir9();
|
|
36122
36382
|
if (shell.includes("zsh")) {
|
|
36123
|
-
return
|
|
36383
|
+
return join27(home, ".zshrc");
|
|
36124
36384
|
}
|
|
36125
36385
|
if (shell.includes("bash")) {
|
|
36126
|
-
const bashProfile =
|
|
36386
|
+
const bashProfile = join27(home, ".bash_profile");
|
|
36127
36387
|
const exists = await access10(bashProfile).then(() => true).catch(() => false);
|
|
36128
|
-
return exists ? bashProfile :
|
|
36388
|
+
return exists ? bashProfile : join27(home, ".bashrc");
|
|
36129
36389
|
}
|
|
36130
36390
|
if (shell.includes("fish")) {
|
|
36131
|
-
return
|
|
36391
|
+
return join27(home, ".config", "fish", "config.fish");
|
|
36132
36392
|
}
|
|
36133
|
-
return
|
|
36393
|
+
return join27(home, ".profile");
|
|
36134
36394
|
}
|
|
36135
36395
|
async function profileContains(profilePath, str) {
|
|
36136
36396
|
try {
|
|
36137
|
-
const content = await
|
|
36397
|
+
const content = await readFile28(profilePath, "utf8");
|
|
36138
36398
|
return content.includes(str);
|
|
36139
36399
|
} catch {
|
|
36140
36400
|
return false;
|
|
@@ -36155,7 +36415,7 @@ async function setupNode() {
|
|
|
36155
36415
|
}
|
|
36156
36416
|
fail(`Node.js v${current} \u2014 need v${REQUIRED_NODE_MAJOR}+`);
|
|
36157
36417
|
info("");
|
|
36158
|
-
const hasNvm = await binaryExists("nvm") || await access10(
|
|
36418
|
+
const hasNvm = await binaryExists("nvm") || await access10(join27(homedir9(), ".nvm", "nvm.sh")).then(() => true).catch(() => false);
|
|
36159
36419
|
const hasFnm = await binaryExists("fnm");
|
|
36160
36420
|
if (hasNvm) {
|
|
36161
36421
|
info(`nvm detected. Will run: nvm install ${REQUIRED_NODE_MAJOR} && nvm use ${REQUIRED_NODE_MAJOR}`);
|
|
@@ -36164,7 +36424,7 @@ async function setupNode() {
|
|
|
36164
36424
|
warn(`Skipped. Re-run experiences setup after switching to Node ${REQUIRED_NODE_MAJOR}.`);
|
|
36165
36425
|
return false;
|
|
36166
36426
|
}
|
|
36167
|
-
const nvmScript =
|
|
36427
|
+
const nvmScript = join27(homedir9(), ".nvm", "nvm.sh");
|
|
36168
36428
|
const result = await runSpawn("bash", [
|
|
36169
36429
|
"-c",
|
|
36170
36430
|
`source "${nvmScript}" && nvm install ${REQUIRED_NODE_MAJOR} && nvm alias default ${REQUIRED_NODE_MAJOR}`
|
|
@@ -36631,13 +36891,13 @@ async function checkPnpm(pkgRoot) {
|
|
|
36631
36891
|
}
|
|
36632
36892
|
async function checkDependencies(pkgRoot) {
|
|
36633
36893
|
section("Checking dependencies (pnpm install)");
|
|
36634
|
-
const nodeModulesExists = await access10(
|
|
36894
|
+
const nodeModulesExists = await access10(join27(pkgRoot, "node_modules")).then(() => true).catch(() => false);
|
|
36635
36895
|
if (!nodeModulesExists) {
|
|
36636
36896
|
info("node_modules not found \u2014 running pnpm install...");
|
|
36637
36897
|
} else {
|
|
36638
36898
|
info("Running pnpm install to ensure dependencies are up to date...");
|
|
36639
36899
|
}
|
|
36640
|
-
const repoRoot =
|
|
36900
|
+
const repoRoot = join27(pkgRoot, "..", "..");
|
|
36641
36901
|
const result = await runSpawn("pnpm", ["install", "--frozen-lockfile"], { cwd: repoRoot });
|
|
36642
36902
|
if (result.exitCode !== 0) {
|
|
36643
36903
|
fail("pnpm install failed");
|
|
@@ -36656,7 +36916,7 @@ async function checkDependencies(pkgRoot) {
|
|
|
36656
36916
|
async function checkBuild(pkgRoot) {
|
|
36657
36917
|
section("Building CLI");
|
|
36658
36918
|
info("Running pnpm build...");
|
|
36659
|
-
const repoRoot =
|
|
36919
|
+
const repoRoot = join27(pkgRoot, "..", "..");
|
|
36660
36920
|
const result = await runSpawn("pnpm", ["--filter", "@contentful/experience-design-system-cli", "run", "build"], {
|
|
36661
36921
|
cwd: repoRoot
|
|
36662
36922
|
});
|
|
@@ -36772,7 +37032,7 @@ function registerSetupCommand(program) {
|
|
|
36772
37032
|
process.stdout.write("\n\x1B[1mexperiences setup\x1B[0m \u2014 interactive setup wizard\n");
|
|
36773
37033
|
process.stdout.write("Sets up everything you need to run \x1B[1mexperiences import\x1B[0m.\n");
|
|
36774
37034
|
const pkgRoot = findPkgRoot();
|
|
36775
|
-
const repoRoot =
|
|
37035
|
+
const repoRoot = join27(pkgRoot, "..", "..");
|
|
36776
37036
|
const profilePath = await detectShellProfile();
|
|
36777
37037
|
const results = [];
|
|
36778
37038
|
const nodeOk = await setupNode();
|
|
@@ -37012,7 +37272,7 @@ async function beginCommand(command, opts) {
|
|
|
37012
37272
|
init_analytics();
|
|
37013
37273
|
init_credentials_store();
|
|
37014
37274
|
init_cli_path();
|
|
37015
|
-
var pkg3 = JSON.parse(readFileSync10(
|
|
37275
|
+
var pkg3 = JSON.parse(readFileSync10(join28(findPkgRoot(), "package.json"), "utf8"));
|
|
37016
37276
|
async function runBuild(opts) {
|
|
37017
37277
|
return new Promise((resolvePromise) => {
|
|
37018
37278
|
const child = opts.spawnFn();
|
|
@@ -37049,7 +37309,7 @@ function registerImportV2Command(program) {
|
|
|
37049
37309
|
}
|
|
37050
37310
|
function registerBuildCommand(program) {
|
|
37051
37311
|
program.command("build").description("Rebuild from source and re-link exo/experiences binaries to this build").action(async () => {
|
|
37052
|
-
const pkgRoot =
|
|
37312
|
+
const pkgRoot = resolve27(dirname14(fileURLToPath5(import.meta.url)), "..", "..");
|
|
37053
37313
|
process.stderr.write("\u2699 Building from source...\n");
|
|
37054
37314
|
const { exitCode } = await runBuild({
|
|
37055
37315
|
spawnFn: () => spawn6("pnpm", ["build"], { cwd: pkgRoot, stdio: "inherit" }),
|