@contentful/experience-design-system-cli 2.35.1-dev-build-459d7e23.0 → 2.35.1-dev-build-9e5b25da.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 -5
- package/dist/src/tui/home/home.d.ts +0 -1
- package/dist/src/tui/home/home.theme.d.ts +0 -11
- package/legacy/dist/src/analyze/composition/candidate-files.d.ts +34 -0
- package/legacy/dist/src/analyze/composition/composition-cache-key.d.ts +18 -0
- package/legacy/dist/src/analyze/composition/interchange-schema.d.ts +1 -7
- package/legacy/dist/src/analyze/composition/parse-map-edges.d.ts +16 -0
- package/legacy/dist/src/analyze/composition/prompt-loader.d.ts +3 -0
- package/legacy/dist/src/analyze/composition/resolve-mapping-cli.d.ts +10 -0
- package/legacy/dist/src/analyze/composition/resolve-mapping.d.ts +34 -11
- package/legacy/dist/src/analyze/extract-command.d.ts +4 -0
- package/legacy/dist/src/import/tui/WizardApp.d.ts +7 -1
- package/legacy/dist/src/import/tui/run-selection-agent.d.ts +1 -0
- package/legacy/dist/src/import/tui/wizard-state-transitions.d.ts +3 -0
- package/legacy/dist/src/index.js +1669 -449
- package/legacy/dist/src/map-tokens/tui/MapTokensView.d.ts +1 -0
- package/legacy/dist/src/session/cache-keys.d.ts +22 -0
- package/legacy/dist/src/session/core/components/hash-component-shape.d.ts +5 -0
- package/legacy/dist/src/session/core/tokens/hash-token-content.d.ts +1 -0
- package/legacy/dist/src/session/db.d.ts +72 -2
- package/legacy/package.json +1 -5
- package/legacy/prompts/composition-edges.md +11 -0
- package/package.json +3 -7
- package/legacy/dist/src/analyze/composition/source-call-site-evidence.d.ts +0 -30
- package/legacy/skills/debate-select.md +0 -23
package/legacy/dist/src/index.js
CHANGED
|
@@ -164,11 +164,12 @@ var init_render_with_goodbye = __esm({
|
|
|
164
164
|
function isAgentName(value) {
|
|
165
165
|
return AGENT_NAMES.includes(value);
|
|
166
166
|
}
|
|
167
|
-
var AGENT_NAMES, AGENT_BINARIES;
|
|
167
|
+
var AGENT_NAMES, DEFAULT_AGENT_NAME, AGENT_BINARIES;
|
|
168
168
|
var init_agent_names = __esm({
|
|
169
169
|
"packages/experience-design-system-generation/dist/src/agent-names.js"() {
|
|
170
170
|
"use strict";
|
|
171
171
|
AGENT_NAMES = ["claude", "codex", "opencode", "cursor", "copilot"];
|
|
172
|
+
DEFAULT_AGENT_NAME = "claude";
|
|
172
173
|
AGENT_BINARIES = {
|
|
173
174
|
claude: "claude",
|
|
174
175
|
codex: "codex",
|
|
@@ -180,6 +181,23 @@ var init_agent_names = __esm({
|
|
|
180
181
|
});
|
|
181
182
|
|
|
182
183
|
// packages/experience-design-system-generation/dist/src/controller/helpers/validate-generation-request.js
|
|
184
|
+
function validateGenerationRequest(request2) {
|
|
185
|
+
if (request2 === null || typeof request2 !== "object") {
|
|
186
|
+
throw new TypeError("createGenerationEndpoint requires a request object");
|
|
187
|
+
}
|
|
188
|
+
if (!isAgentName(request2.agent)) {
|
|
189
|
+
throw new TypeError(`createGenerationEndpoint requires agent to be a valid agent name, got: ${String(request2.agent)}`);
|
|
190
|
+
}
|
|
191
|
+
if (typeof request2.timeoutMs !== "number" || request2.timeoutMs <= 0) {
|
|
192
|
+
throw new TypeError("createGenerationEndpoint requires timeoutMs to be a positive number");
|
|
193
|
+
}
|
|
194
|
+
if (request2.promptOptions === null || typeof request2.promptOptions !== "object") {
|
|
195
|
+
throw new TypeError("createGenerationEndpoint requires promptOptions to be an object");
|
|
196
|
+
}
|
|
197
|
+
if (request2.onOutput !== void 0 && typeof request2.onOutput !== "function") {
|
|
198
|
+
throw new TypeError("createGenerationEndpoint requires onOutput to be a function when provided");
|
|
199
|
+
}
|
|
200
|
+
}
|
|
183
201
|
var init_validate_generation_request = __esm({
|
|
184
202
|
"packages/experience-design-system-generation/dist/src/controller/helpers/validate-generation-request.js"() {
|
|
185
203
|
"use strict";
|
|
@@ -238,7 +256,6 @@ var init_resolve_skill_file = __esm({
|
|
|
238
256
|
components: "generate-components.md",
|
|
239
257
|
tokens: "generate-tokens.md",
|
|
240
258
|
select: "select-components.md",
|
|
241
|
-
"debate-select": "debate-select.md",
|
|
242
259
|
"map-tokens": "map-tokens.md"
|
|
243
260
|
};
|
|
244
261
|
}
|
|
@@ -500,31 +517,6 @@ Rules:
|
|
|
500
517
|
- Emit set_group calls before the set_token calls that fall under them.
|
|
501
518
|
- You may emit prose lines (not starting with {) anywhere \u2014 they are ignored by the parser and serve as your reasoning log.`;
|
|
502
519
|
}
|
|
503
|
-
function buildDebateSelectAutonomousPreamble(inputBlock, debateRole, disagreementInline) {
|
|
504
|
-
const role = debateRole ?? "for";
|
|
505
|
-
return [
|
|
506
|
-
"You are the " + role.toUpperCase() + " participant in an adversarial review of one component-selection disagreement. This is an automatic escalation stage; do not ask the developer for confirmation.",
|
|
507
|
-
"",
|
|
508
|
-
"Your role is to argue the " + role.toUpperCase() + " position on the exact disagreement below. Address the claim literally, cite the supplied component evidence, and do not substitute a nearby component or field. The opposing participant is evaluating the same evidence independently.",
|
|
509
|
-
"",
|
|
510
|
-
"Component and source data:" + inputBlock,
|
|
511
|
-
"",
|
|
512
|
-
"Disagreement under review (JSON):",
|
|
513
|
-
"~~~json",
|
|
514
|
-
disagreementInline ?? "{}",
|
|
515
|
-
"~~~",
|
|
516
|
-
"",
|
|
517
|
-
"## Output protocol",
|
|
518
|
-
"",
|
|
519
|
-
"Emit exactly one JSON object on one line and do not write files:",
|
|
520
|
-
"",
|
|
521
|
-
"~~~json",
|
|
522
|
-
'{"role":"' + role + '","disagreement_id":"<id>","argument":"<position and reasoning>","evidence":[{"source":"<path>","line":"<line-or-range>","quote":"<verbatim evidence>"}]}',
|
|
523
|
-
"~~~",
|
|
524
|
-
"",
|
|
525
|
-
"The role and disagreement_id must match the values in this prompt. Use an empty evidence array only when the supplied context contains no citable source evidence."
|
|
526
|
-
].join("\n");
|
|
527
|
-
}
|
|
528
520
|
var init_build_skill_preambles = __esm({
|
|
529
521
|
"packages/experience-design-system-generation/dist/src/services/prompts/helpers/build-skill-preambles.js"() {
|
|
530
522
|
"use strict";
|
|
@@ -533,7 +525,7 @@ var init_build_skill_preambles = __esm({
|
|
|
533
525
|
|
|
534
526
|
// packages/experience-design-system-generation/dist/src/services/prompts/helpers/build-preamble.js
|
|
535
527
|
function buildPreamble(options) {
|
|
536
|
-
const { skill, rawComponentsInline, propBucketsInline, rawTokensInline, rawTokensFilename, tokensInline, tokenMapInline, generatedCdf, tokenTree, componentSourceRefs, existingComponentsInline, existingTokensInline, componentAllowlistInline
|
|
528
|
+
const { skill, rawComponentsInline, propBucketsInline, rawTokensInline, rawTokensFilename, tokensInline, tokenMapInline, generatedCdf, tokenTree, componentSourceRefs, existingComponentsInline, existingTokensInline, componentAllowlistInline } = options;
|
|
537
529
|
const sections = [];
|
|
538
530
|
if (existingComponentsInline) {
|
|
539
531
|
sections.push(`Existing components in the target Contentful space (JSON) \u2014 use for alignment, not as a hard filter:
|
|
@@ -605,8 +597,6 @@ ${sections.join("\n\n")}` : "";
|
|
|
605
597
|
return buildComponentsAutonomousPreamble(inputBlock);
|
|
606
598
|
if (skill === "select")
|
|
607
599
|
return buildSelectAutonomousPreamble(inputBlock);
|
|
608
|
-
if (skill === "debate-select")
|
|
609
|
-
return buildDebateSelectAutonomousPreamble(inputBlock, debateRole, disagreementInline);
|
|
610
600
|
if (skill === "map-tokens")
|
|
611
601
|
return buildMapTokensAutonomousPreamble(inputBlock);
|
|
612
602
|
return buildTokensAutonomousPreamble(inputBlock);
|
|
@@ -640,6 +630,17 @@ var init_build_prompt = __esm({
|
|
|
640
630
|
});
|
|
641
631
|
|
|
642
632
|
// packages/experience-design-system-generation/dist/src/orchestrator/execute-generation-orchestrator.js
|
|
633
|
+
async function executeGenerationOrchestrator(request2) {
|
|
634
|
+
const prompt = await buildPrompt(request2.promptOptions);
|
|
635
|
+
return request2.invoker.invoke({
|
|
636
|
+
agent: request2.agent,
|
|
637
|
+
model: request2.model,
|
|
638
|
+
bedrock: request2.bedrock,
|
|
639
|
+
prompt,
|
|
640
|
+
timeoutMs: request2.timeoutMs,
|
|
641
|
+
onOutput: request2.onOutput
|
|
642
|
+
});
|
|
643
|
+
}
|
|
643
644
|
var init_execute_generation_orchestrator = __esm({
|
|
644
645
|
"packages/experience-design-system-generation/dist/src/orchestrator/execute-generation-orchestrator.js"() {
|
|
645
646
|
"use strict";
|
|
@@ -740,6 +741,22 @@ var init_describe_agent_failure = __esm({
|
|
|
740
741
|
});
|
|
741
742
|
|
|
742
743
|
// packages/experience-design-system-generation/dist/src/services/agent/helpers/extract-sentinel-output.js
|
|
744
|
+
function extractSentinelOutput(stdout) {
|
|
745
|
+
const START = "<<<EDS_OUTPUT_START>>>";
|
|
746
|
+
const END = "<<<EDS_OUTPUT_END>>>";
|
|
747
|
+
const startIdx = stdout.indexOf(START);
|
|
748
|
+
const endIdx = stdout.indexOf(END);
|
|
749
|
+
if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx)
|
|
750
|
+
return null;
|
|
751
|
+
const secondStart = stdout.indexOf(START, startIdx + START.length);
|
|
752
|
+
if (secondStart !== -1 && secondStart < endIdx)
|
|
753
|
+
return "multiple";
|
|
754
|
+
const afterStart = stdout.indexOf(END, startIdx);
|
|
755
|
+
const secondEnd = stdout.indexOf(END, afterStart + END.length);
|
|
756
|
+
if (secondEnd !== -1)
|
|
757
|
+
return "multiple";
|
|
758
|
+
return stdout.slice(startIdx + START.length, endIdx).trim();
|
|
759
|
+
}
|
|
743
760
|
var init_extract_sentinel_output = __esm({
|
|
744
761
|
"packages/experience-design-system-generation/dist/src/services/agent/helpers/extract-sentinel-output.js"() {
|
|
745
762
|
"use strict";
|
|
@@ -764,7 +781,7 @@ async function runAgent(options) {
|
|
|
764
781
|
promptLen: prompt.length,
|
|
765
782
|
promptHead: prompt.slice(0, 500)
|
|
766
783
|
});
|
|
767
|
-
return new Promise((
|
|
784
|
+
return new Promise((resolve22) => {
|
|
768
785
|
const bedrockEnv = bedrock ? BEDROCK_ENV_BY_AGENT[agent] : void 0;
|
|
769
786
|
const child = spawn(binary, args, {
|
|
770
787
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -813,7 +830,7 @@ async function runAgent(options) {
|
|
|
813
830
|
stderrLen: stderr.length,
|
|
814
831
|
stderrTail: stderr.slice(-1e3)
|
|
815
832
|
});
|
|
816
|
-
|
|
833
|
+
resolve22(result);
|
|
817
834
|
});
|
|
818
835
|
});
|
|
819
836
|
}
|
|
@@ -830,7 +847,7 @@ var init_run_agent = __esm({
|
|
|
830
847
|
// packages/experience-design-system-generation/dist/src/services/agent/helpers/check-claude-auth.js
|
|
831
848
|
import { spawn as spawn2 } from "node:child_process";
|
|
832
849
|
function checkClaudeAuth(binary) {
|
|
833
|
-
return new Promise((
|
|
850
|
+
return new Promise((resolve22) => {
|
|
834
851
|
const child = spawn2(binary, ["auth", "status", "--json"], {
|
|
835
852
|
stdio: ["ignore", "pipe", "pipe"]
|
|
836
853
|
});
|
|
@@ -840,7 +857,7 @@ function checkClaudeAuth(binary) {
|
|
|
840
857
|
if (!done) {
|
|
841
858
|
done = true;
|
|
842
859
|
child.kill("SIGTERM");
|
|
843
|
-
|
|
860
|
+
resolve22("unauthenticated");
|
|
844
861
|
}
|
|
845
862
|
}, 5e3);
|
|
846
863
|
child.stdout?.on("data", (chunk) => {
|
|
@@ -852,14 +869,14 @@ function checkClaudeAuth(binary) {
|
|
|
852
869
|
done = true;
|
|
853
870
|
clearTimeout(timer);
|
|
854
871
|
if (code !== 0) {
|
|
855
|
-
|
|
872
|
+
resolve22("unauthenticated");
|
|
856
873
|
return;
|
|
857
874
|
}
|
|
858
875
|
try {
|
|
859
876
|
const status = JSON.parse(stdout);
|
|
860
|
-
|
|
877
|
+
resolve22(status.loggedIn ? "ok" : "unauthenticated");
|
|
861
878
|
} catch {
|
|
862
|
-
|
|
879
|
+
resolve22("unauthenticated");
|
|
863
880
|
}
|
|
864
881
|
});
|
|
865
882
|
});
|
|
@@ -874,13 +891,13 @@ var init_check_claude_auth = __esm({
|
|
|
874
891
|
import { spawn as spawn3 } from "node:child_process";
|
|
875
892
|
async function checkAgentAuth(agent) {
|
|
876
893
|
const binary = resolveAgentBinary(agent);
|
|
877
|
-
const binaryExists2 = await new Promise((
|
|
894
|
+
const binaryExists2 = await new Promise((resolve22) => {
|
|
878
895
|
if (binary.startsWith("/")) {
|
|
879
|
-
import("node:fs/promises").then((fs2) => fs2.access(binary).then(() =>
|
|
896
|
+
import("node:fs/promises").then((fs2) => fs2.access(binary).then(() => resolve22(true), () => resolve22(false)));
|
|
880
897
|
return;
|
|
881
898
|
}
|
|
882
899
|
const child = spawn3(process.platform === "win32" ? "where" : "which", [binary], { stdio: "ignore" });
|
|
883
|
-
child.on("close", (code) =>
|
|
900
|
+
child.on("close", (code) => resolve22(code === 0));
|
|
884
901
|
});
|
|
885
902
|
if (!binaryExists2)
|
|
886
903
|
return "not-found";
|
|
@@ -917,6 +934,20 @@ var init_local_cli_agent_invoker = __esm({
|
|
|
917
934
|
});
|
|
918
935
|
|
|
919
936
|
// packages/experience-design-system-generation/dist/src/controller/create-generation-endpoint.js
|
|
937
|
+
function createGenerationEndpoint(options = {}) {
|
|
938
|
+
const invoker2 = createLocalCliAgentInvoker({
|
|
939
|
+
onDebugEvent: options.onDebugEvent
|
|
940
|
+
});
|
|
941
|
+
return {
|
|
942
|
+
async run(request2) {
|
|
943
|
+
validateGenerationRequest(request2);
|
|
944
|
+
return executeGenerationOrchestrator({ ...request2, invoker: invoker2 });
|
|
945
|
+
},
|
|
946
|
+
checkAuth(agent) {
|
|
947
|
+
return invoker2.checkAuth(agent);
|
|
948
|
+
}
|
|
949
|
+
};
|
|
950
|
+
}
|
|
920
951
|
var init_create_generation_endpoint = __esm({
|
|
921
952
|
"packages/experience-design-system-generation/dist/src/controller/create-generation-endpoint.js"() {
|
|
922
953
|
"use strict";
|
|
@@ -1301,6 +1332,32 @@ var init_progress = __esm({
|
|
|
1301
1332
|
});
|
|
1302
1333
|
|
|
1303
1334
|
// packages/experience-design-system-generation/dist/src/index.js
|
|
1335
|
+
var src_exports = {};
|
|
1336
|
+
__export(src_exports, {
|
|
1337
|
+
AGENT_BINARIES: () => AGENT_BINARIES,
|
|
1338
|
+
AGENT_NAMES: () => AGENT_NAMES,
|
|
1339
|
+
DEFAULT_AGENT_NAME: () => DEFAULT_AGENT_NAME,
|
|
1340
|
+
agentSupportsBedrock: () => agentSupportsBedrock,
|
|
1341
|
+
buildArgs: () => buildAgentArgs,
|
|
1342
|
+
buildPrompt: () => buildPrompt,
|
|
1343
|
+
checkAgentAuth: () => checkAgentAuth,
|
|
1344
|
+
createGenerationEndpoint: () => createGenerationEndpoint,
|
|
1345
|
+
createLocalCliAgentInvoker: () => createLocalCliAgentInvoker,
|
|
1346
|
+
describeAgentFailure: () => describeAgentFailure,
|
|
1347
|
+
executeGenerationOrchestrator: () => executeGenerationOrchestrator,
|
|
1348
|
+
extractSentinelOutput: () => extractSentinelOutput,
|
|
1349
|
+
formatCustomPromptBanner: () => formatCustomPromptBanner,
|
|
1350
|
+
formatGenerateProgressLine: () => formatGenerateProgressLine,
|
|
1351
|
+
isAgentName: () => isAgentName,
|
|
1352
|
+
parseMapTokenPropToolCallLines: () => parseMapTokenPropToolCallLines,
|
|
1353
|
+
parseSelectToolCallLines: () => parseSelectToolCallLines,
|
|
1354
|
+
parseTokenToolCallLines: () => parseTokenToolCallLines,
|
|
1355
|
+
parseToolCallLines: () => parsePropToolCallLines,
|
|
1356
|
+
resolveAgentModel: () => resolveAgentModel,
|
|
1357
|
+
resolveBinary: () => resolveAgentBinary,
|
|
1358
|
+
resolveSkillPath: () => resolveSkillPath,
|
|
1359
|
+
runAgent: () => runAgent
|
|
1360
|
+
});
|
|
1304
1361
|
var init_src = __esm({
|
|
1305
1362
|
"packages/experience-design-system-generation/dist/src/index.js"() {
|
|
1306
1363
|
"use strict";
|
|
@@ -10300,6 +10357,41 @@ var init_read3 = __esm({
|
|
|
10300
10357
|
}
|
|
10301
10358
|
});
|
|
10302
10359
|
|
|
10360
|
+
// packages/experience-design-system-cli-legacy/src/session/core/components/hash-component-shape.ts
|
|
10361
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
10362
|
+
function hashComponentShape(component) {
|
|
10363
|
+
const payload = {
|
|
10364
|
+
framework: component.framework,
|
|
10365
|
+
name: component.name,
|
|
10366
|
+
source: component.source,
|
|
10367
|
+
props: component.props.map((p) => ({
|
|
10368
|
+
name: p.name,
|
|
10369
|
+
type: p.type
|
|
10370
|
+
})),
|
|
10371
|
+
slots: component.slots.map((s) => ({
|
|
10372
|
+
name: s.name,
|
|
10373
|
+
isDefault: s.isDefault
|
|
10374
|
+
}))
|
|
10375
|
+
};
|
|
10376
|
+
return createHash2("sha256").update(JSON.stringify(payload)).digest("hex");
|
|
10377
|
+
}
|
|
10378
|
+
var init_hash_component_shape = __esm({
|
|
10379
|
+
"packages/experience-design-system-cli-legacy/src/session/core/components/hash-component-shape.ts"() {
|
|
10380
|
+
"use strict";
|
|
10381
|
+
}
|
|
10382
|
+
});
|
|
10383
|
+
|
|
10384
|
+
// packages/experience-design-system-cli-legacy/src/session/core/tokens/hash-token-content.ts
|
|
10385
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
10386
|
+
function hashTokenContent(rawTokenContent) {
|
|
10387
|
+
return createHash3("sha256").update(rawTokenContent.trim()).digest("hex");
|
|
10388
|
+
}
|
|
10389
|
+
var init_hash_token_content = __esm({
|
|
10390
|
+
"packages/experience-design-system-cli-legacy/src/session/core/tokens/hash-token-content.ts"() {
|
|
10391
|
+
"use strict";
|
|
10392
|
+
}
|
|
10393
|
+
});
|
|
10394
|
+
|
|
10303
10395
|
// packages/experience-design-system-cli-legacy/src/session/repositories/tokens/write.ts
|
|
10304
10396
|
function deleteRawTokensForSession(db, sessionId2) {
|
|
10305
10397
|
db.prepare("DELETE FROM raw_token_groups WHERE session_id = ?").run(sessionId2);
|
|
@@ -10463,17 +10555,47 @@ var init_replace_raw_prop_token_paths = __esm({
|
|
|
10463
10555
|
}
|
|
10464
10556
|
});
|
|
10465
10557
|
|
|
10558
|
+
// packages/experience-design-system-cli-legacy/src/session/cache-keys.ts
|
|
10559
|
+
var cache_keys_exports = {};
|
|
10560
|
+
__export(cache_keys_exports, {
|
|
10561
|
+
hashContent: () => hashContent,
|
|
10562
|
+
hashFile: () => hashFile,
|
|
10563
|
+
hashPromptForSkill: () => hashPromptForSkill
|
|
10564
|
+
});
|
|
10565
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
10566
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
10567
|
+
import { resolve as resolve8 } from "node:path";
|
|
10568
|
+
function hashContent(content) {
|
|
10569
|
+
return createHash4("sha256").update(content).digest("hex");
|
|
10570
|
+
}
|
|
10571
|
+
async function hashFile(filePath) {
|
|
10572
|
+
const content = await readFile7(filePath, "utf8");
|
|
10573
|
+
return hashContent(content);
|
|
10574
|
+
}
|
|
10575
|
+
async function hashPromptForSkill(skill, agent, model, skillPathOverride, extraInputs = [], skillContentOverride) {
|
|
10576
|
+
const promptHash = skillContentOverride ? hashContent(skillContentOverride) : skillPathOverride ? await hashFile(resolve8(skillPathOverride)) : await hashFile(resolveSkillPath(skill));
|
|
10577
|
+
const extraSegment = extraInputs.length > 0 ? `|${extraInputs.join("|")}` : "";
|
|
10578
|
+
return hashContent(`${promptHash}|${agent}|${model ?? ""}${extraSegment}`);
|
|
10579
|
+
}
|
|
10580
|
+
var init_cache_keys = __esm({
|
|
10581
|
+
"packages/experience-design-system-cli-legacy/src/session/cache-keys.ts"() {
|
|
10582
|
+
"use strict";
|
|
10583
|
+
init_src();
|
|
10584
|
+
}
|
|
10585
|
+
});
|
|
10586
|
+
|
|
10466
10587
|
// packages/experience-design-system-cli-legacy/src/session/db.ts
|
|
10467
10588
|
import { DatabaseSync } from "node:sqlite";
|
|
10468
10589
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync5 } from "node:fs";
|
|
10469
|
-
import { readFile as
|
|
10590
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
10591
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
10470
10592
|
import { homedir as homedir3 } from "node:os";
|
|
10471
|
-
import { dirname as dirname14, resolve as
|
|
10593
|
+
import { dirname as dirname14, resolve as resolve9 } from "node:path";
|
|
10472
10594
|
function getPipelineDbPath() {
|
|
10473
10595
|
if (process.env.EDS_PIPELINE_DB_PATH) {
|
|
10474
|
-
return
|
|
10596
|
+
return resolve9(process.env.EDS_PIPELINE_DB_PATH);
|
|
10475
10597
|
}
|
|
10476
|
-
return
|
|
10598
|
+
return resolve9(homedir3(), ".contentful", "experience-design-system-cli", "pipeline.db");
|
|
10477
10599
|
}
|
|
10478
10600
|
function openPipelineDb(dbPath) {
|
|
10479
10601
|
const path = dbPath ?? getPipelineDbPath();
|
|
@@ -10607,8 +10729,134 @@ function applyDbMigrations(db) {
|
|
|
10607
10729
|
if (!rawSlotColsForRationale.some((c2) => c2.name === "rationale")) {
|
|
10608
10730
|
db.exec("ALTER TABLE raw_slots ADD COLUMN rationale TEXT");
|
|
10609
10731
|
}
|
|
10610
|
-
|
|
10611
|
-
|
|
10732
|
+
const hasExtractCache = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='extract_cache'`).all();
|
|
10733
|
+
if (hasExtractCache.length === 0) {
|
|
10734
|
+
db.exec(`
|
|
10735
|
+
CREATE TABLE extract_cache (
|
|
10736
|
+
file_path TEXT NOT NULL,
|
|
10737
|
+
file_hash TEXT NOT NULL,
|
|
10738
|
+
cli_version TEXT NOT NULL,
|
|
10739
|
+
created_at TEXT NOT NULL,
|
|
10740
|
+
updated_at TEXT NOT NULL,
|
|
10741
|
+
components_json TEXT NOT NULL,
|
|
10742
|
+
PRIMARY KEY (file_hash, cli_version)
|
|
10743
|
+
);
|
|
10744
|
+
CREATE INDEX idx_extract_cache_file ON extract_cache(file_path);
|
|
10745
|
+
`);
|
|
10746
|
+
}
|
|
10747
|
+
const hasSelectCache = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='select_cache'`).all();
|
|
10748
|
+
if (hasSelectCache.length === 0) {
|
|
10749
|
+
db.exec(`
|
|
10750
|
+
CREATE TABLE select_cache (
|
|
10751
|
+
component_hash TEXT NOT NULL,
|
|
10752
|
+
prompt_hash TEXT NOT NULL,
|
|
10753
|
+
cli_version TEXT NOT NULL,
|
|
10754
|
+
decision TEXT NOT NULL CHECK (decision IN ('accepted','rejected')),
|
|
10755
|
+
reason TEXT,
|
|
10756
|
+
created_at TEXT NOT NULL,
|
|
10757
|
+
updated_at TEXT NOT NULL,
|
|
10758
|
+
PRIMARY KEY (component_hash, prompt_hash, cli_version)
|
|
10759
|
+
);
|
|
10760
|
+
`);
|
|
10761
|
+
}
|
|
10762
|
+
const tables = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='generation_cache'`).all();
|
|
10763
|
+
if (tables.length === 0) {
|
|
10764
|
+
db.exec(`
|
|
10765
|
+
CREATE TABLE generation_cache (
|
|
10766
|
+
input_hash TEXT NOT NULL,
|
|
10767
|
+
entity_type TEXT NOT NULL CHECK (entity_type IN ('component', 'token_set', 'token_mapping')),
|
|
10768
|
+
entity_id TEXT NOT NULL,
|
|
10769
|
+
source_session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
10770
|
+
human_edited INTEGER NOT NULL DEFAULT 0 CHECK (human_edited IN (0, 1)),
|
|
10771
|
+
created_at TEXT NOT NULL,
|
|
10772
|
+
updated_at TEXT NOT NULL,
|
|
10773
|
+
PRIMARY KEY (input_hash, entity_type, entity_id)
|
|
10774
|
+
);
|
|
10775
|
+
CREATE INDEX idx_generation_cache_entity ON generation_cache(entity_type, entity_id);
|
|
10776
|
+
CREATE INDEX idx_generation_cache_session ON generation_cache(source_session_id);
|
|
10777
|
+
`);
|
|
10778
|
+
}
|
|
10779
|
+
const genCacheCols = db.prepare(`PRAGMA table_info(generation_cache)`).all();
|
|
10780
|
+
const hasPromptHash = genCacheCols.some((c2) => c2.name === "prompt_hash");
|
|
10781
|
+
const oldPkCols = genCacheCols.filter((c2) => c2.pk > 0).map((c2) => c2.name);
|
|
10782
|
+
const promptHashInPk = oldPkCols.includes("prompt_hash");
|
|
10783
|
+
if (!hasPromptHash) {
|
|
10784
|
+
db.exec(`ALTER TABLE generation_cache ADD COLUMN prompt_hash TEXT NOT NULL DEFAULT ''`);
|
|
10785
|
+
}
|
|
10786
|
+
if (!promptHashInPk) {
|
|
10787
|
+
db.exec("BEGIN");
|
|
10788
|
+
try {
|
|
10789
|
+
db.exec(`
|
|
10790
|
+
CREATE TABLE generation_cache__new (
|
|
10791
|
+
input_hash TEXT NOT NULL,
|
|
10792
|
+
entity_type TEXT NOT NULL CHECK (entity_type IN ('component', 'token_set', 'token_mapping')),
|
|
10793
|
+
entity_id TEXT NOT NULL,
|
|
10794
|
+
source_session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
10795
|
+
human_edited INTEGER NOT NULL DEFAULT 0 CHECK (human_edited IN (0, 1)),
|
|
10796
|
+
created_at TEXT NOT NULL,
|
|
10797
|
+
updated_at TEXT NOT NULL,
|
|
10798
|
+
prompt_hash TEXT NOT NULL DEFAULT '',
|
|
10799
|
+
PRIMARY KEY (input_hash, prompt_hash, entity_type, entity_id)
|
|
10800
|
+
);
|
|
10801
|
+
INSERT INTO generation_cache__new
|
|
10802
|
+
(input_hash, entity_type, entity_id, source_session_id, human_edited, created_at, updated_at, prompt_hash)
|
|
10803
|
+
SELECT input_hash, entity_type, entity_id, source_session_id, human_edited, created_at, updated_at, prompt_hash
|
|
10804
|
+
FROM generation_cache;
|
|
10805
|
+
DROP TABLE generation_cache;
|
|
10806
|
+
ALTER TABLE generation_cache__new RENAME TO generation_cache;
|
|
10807
|
+
CREATE INDEX IF NOT EXISTS idx_generation_cache_entity ON generation_cache(entity_type, entity_id);
|
|
10808
|
+
CREATE INDEX IF NOT EXISTS idx_generation_cache_session ON generation_cache(source_session_id);
|
|
10809
|
+
`);
|
|
10810
|
+
db.exec("COMMIT");
|
|
10811
|
+
} catch (e) {
|
|
10812
|
+
db.exec("ROLLBACK");
|
|
10813
|
+
throw e;
|
|
10814
|
+
}
|
|
10815
|
+
}
|
|
10816
|
+
const genCacheTableSql = db.prepare(`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'generation_cache'`).get();
|
|
10817
|
+
const hasTokenMappingEntityType = genCacheTableSql?.sql.includes("'token_mapping'") ?? true;
|
|
10818
|
+
if (!hasTokenMappingEntityType) {
|
|
10819
|
+
db.exec("BEGIN");
|
|
10820
|
+
try {
|
|
10821
|
+
db.exec(`
|
|
10822
|
+
CREATE TABLE generation_cache__new2 (
|
|
10823
|
+
input_hash TEXT NOT NULL,
|
|
10824
|
+
entity_type TEXT NOT NULL CHECK (entity_type IN ('component', 'token_set', 'token_mapping')),
|
|
10825
|
+
entity_id TEXT NOT NULL,
|
|
10826
|
+
source_session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
10827
|
+
human_edited INTEGER NOT NULL DEFAULT 0 CHECK (human_edited IN (0, 1)),
|
|
10828
|
+
created_at TEXT NOT NULL,
|
|
10829
|
+
updated_at TEXT NOT NULL,
|
|
10830
|
+
prompt_hash TEXT NOT NULL DEFAULT '',
|
|
10831
|
+
PRIMARY KEY (input_hash, prompt_hash, entity_type, entity_id)
|
|
10832
|
+
);
|
|
10833
|
+
INSERT INTO generation_cache__new2
|
|
10834
|
+
(input_hash, entity_type, entity_id, source_session_id, human_edited, created_at, updated_at, prompt_hash)
|
|
10835
|
+
SELECT input_hash, entity_type, entity_id, source_session_id, human_edited, created_at, updated_at, prompt_hash
|
|
10836
|
+
FROM generation_cache;
|
|
10837
|
+
DROP TABLE generation_cache;
|
|
10838
|
+
ALTER TABLE generation_cache__new2 RENAME TO generation_cache;
|
|
10839
|
+
CREATE INDEX IF NOT EXISTS idx_generation_cache_entity ON generation_cache(entity_type, entity_id);
|
|
10840
|
+
CREATE INDEX IF NOT EXISTS idx_generation_cache_session ON generation_cache(source_session_id);
|
|
10841
|
+
`);
|
|
10842
|
+
db.exec("COMMIT");
|
|
10843
|
+
} catch (e) {
|
|
10844
|
+
db.exec("ROLLBACK");
|
|
10845
|
+
throw e;
|
|
10846
|
+
}
|
|
10847
|
+
}
|
|
10848
|
+
const hasCompositionCache = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='composition_cache'`).all();
|
|
10849
|
+
if (hasCompositionCache.length === 0) {
|
|
10850
|
+
db.exec(`
|
|
10851
|
+
CREATE TABLE composition_cache (
|
|
10852
|
+
input_hash TEXT NOT NULL,
|
|
10853
|
+
cli_version TEXT NOT NULL,
|
|
10854
|
+
agent_output TEXT NOT NULL,
|
|
10855
|
+
created_at TEXT NOT NULL,
|
|
10856
|
+
updated_at TEXT NOT NULL,
|
|
10857
|
+
PRIMARY KEY (input_hash, cli_version)
|
|
10858
|
+
);
|
|
10859
|
+
`);
|
|
10612
10860
|
}
|
|
10613
10861
|
}
|
|
10614
10862
|
function loadComponentReviewMetadata(db, sessionId2, componentName) {
|
|
@@ -11148,16 +11396,16 @@ function extractRelativeImportPaths(sourceText) {
|
|
|
11148
11396
|
return [...specifiers];
|
|
11149
11397
|
}
|
|
11150
11398
|
async function resolveRelativeImport(specifier, fromDir) {
|
|
11151
|
-
const basePath =
|
|
11399
|
+
const basePath = resolve9(fromDir, specifier);
|
|
11152
11400
|
const candidates = [
|
|
11153
11401
|
basePath,
|
|
11154
11402
|
...rewrittenSourcePaths(basePath),
|
|
11155
11403
|
...SIBLING_FILE_EXTENSIONS.map((ext) => `${basePath}${ext}`),
|
|
11156
|
-
...SIBLING_FILE_EXTENSIONS.map((ext) =>
|
|
11404
|
+
...SIBLING_FILE_EXTENSIONS.map((ext) => resolve9(basePath, `index${ext}`))
|
|
11157
11405
|
];
|
|
11158
11406
|
for (const candidate of candidates) {
|
|
11159
11407
|
try {
|
|
11160
|
-
await
|
|
11408
|
+
await readFile8(candidate, "utf8");
|
|
11161
11409
|
return candidate;
|
|
11162
11410
|
} catch {
|
|
11163
11411
|
}
|
|
@@ -11173,7 +11421,7 @@ async function resolveImportSpecifiers(sourceText, fromDir) {
|
|
|
11173
11421
|
return resolvedPaths;
|
|
11174
11422
|
}
|
|
11175
11423
|
async function loadSiblingFiles(sourceText, sourcePath, propNames, candidateTypeNames = []) {
|
|
11176
|
-
const visited = /* @__PURE__ */ new Set([
|
|
11424
|
+
const visited = /* @__PURE__ */ new Set([resolve9(sourcePath)]);
|
|
11177
11425
|
const discovered = [];
|
|
11178
11426
|
let frontier = [{ text: sourceText, dir: dirname14(sourcePath) }];
|
|
11179
11427
|
for (let hop = 0; hop < MAX_SIBLING_DEPTH && discovered.length < MAX_SIBLING_CANDIDATES_EXPLORED; hop++) {
|
|
@@ -11187,7 +11435,7 @@ async function loadSiblingFiles(sourceText, sourcePath, propNames, candidateType
|
|
|
11187
11435
|
if (discovered.length >= MAX_SIBLING_CANDIDATES_EXPLORED) break;
|
|
11188
11436
|
let content;
|
|
11189
11437
|
try {
|
|
11190
|
-
content = await
|
|
11438
|
+
content = await readFile8(resolvedPath, "utf8");
|
|
11191
11439
|
} catch {
|
|
11192
11440
|
continue;
|
|
11193
11441
|
}
|
|
@@ -11224,7 +11472,7 @@ async function loadComponentSourceRef(name, sourcePath, propNames = [], propType
|
|
|
11224
11472
|
let truncatedSiblingCount = 0;
|
|
11225
11473
|
const usesNotShown = /* @__PURE__ */ new Set();
|
|
11226
11474
|
try {
|
|
11227
|
-
const rawText = await
|
|
11475
|
+
const rawText = await readFile8(sourcePath, "utf8");
|
|
11228
11476
|
let siblingUsesNotShown;
|
|
11229
11477
|
let declaredTypeNames;
|
|
11230
11478
|
({
|
|
@@ -11660,6 +11908,108 @@ function backfillUnclassifiedProps(db, sessionId2) {
|
|
|
11660
11908
|
).run(sessionId2, sessionId2);
|
|
11661
11909
|
return Number(withCategory.changes) + Number(withoutCategory.changes);
|
|
11662
11910
|
}
|
|
11911
|
+
function computeMapTokensInputHash(db, sessionId2, componentSourceRefs = []) {
|
|
11912
|
+
const props = db.prepare(
|
|
11913
|
+
`SELECT rc.name AS component_name, rp.name AS prop_name, rp.cdf_token_kind, rp.default_value
|
|
11914
|
+
FROM raw_props rp
|
|
11915
|
+
JOIN raw_components rc ON rc.session_id = rp.session_id AND rc.component_id = rp.component_id
|
|
11916
|
+
WHERE rp.session_id = ? AND rp.cdf_type = 'token' AND rp.cdf_category = 'design'
|
|
11917
|
+
ORDER BY rc.name, rp.name`
|
|
11918
|
+
).all(sessionId2);
|
|
11919
|
+
const tokens = db.prepare(`SELECT path, type FROM raw_tokens WHERE session_id = ? ORDER BY path`).all(sessionId2);
|
|
11920
|
+
const defaultMappings = db.prepare("SELECT raw_name, path, source FROM raw_token_name_paths WHERE session_id = ? ORDER BY raw_name").all(sessionId2);
|
|
11921
|
+
const payload = {
|
|
11922
|
+
props: props.map((p) => ({
|
|
11923
|
+
component: p.component_name,
|
|
11924
|
+
prop: p.prop_name,
|
|
11925
|
+
tokenKind: p.cdf_token_kind,
|
|
11926
|
+
rawDefault: p.default_value
|
|
11927
|
+
})),
|
|
11928
|
+
tokens,
|
|
11929
|
+
defaultMappings,
|
|
11930
|
+
// The agent's evidence, not just its inputs: a comment or allowlist edit
|
|
11931
|
+
// in a source file (or a sibling it reads) changes the correct answer
|
|
11932
|
+
// without touching props or tokens, so it must invalidate the cache too.
|
|
11933
|
+
sourceRefs: [...componentSourceRefs].sort((a, b) => a.component.localeCompare(b.component)).map((ref) => ({
|
|
11934
|
+
component: ref.component,
|
|
11935
|
+
content: ref.content,
|
|
11936
|
+
siblingFiles: (ref.siblingFiles ?? []).map((s) => ({ path: s.path, content: s.content })).sort((a, b) => a.path.localeCompare(b.path)),
|
|
11937
|
+
usesNotShown: [...ref.usesNotShown ?? []].sort()
|
|
11938
|
+
}))
|
|
11939
|
+
};
|
|
11940
|
+
return createHash5("sha256").update(JSON.stringify(payload)).digest("hex");
|
|
11941
|
+
}
|
|
11942
|
+
function lookupCache(db, inputHash, entityType, entityId, promptHash = "") {
|
|
11943
|
+
const row = db.prepare(
|
|
11944
|
+
`SELECT input_hash, entity_type, entity_id, source_session_id, human_edited, created_at, updated_at, prompt_hash
|
|
11945
|
+
FROM generation_cache
|
|
11946
|
+
WHERE input_hash = ? AND entity_type = ? AND entity_id = ? AND prompt_hash = ?`
|
|
11947
|
+
).get(inputHash, entityType, entityId, promptHash);
|
|
11948
|
+
if (!row) return null;
|
|
11949
|
+
return {
|
|
11950
|
+
inputHash: row.input_hash,
|
|
11951
|
+
entityType: row.entity_type,
|
|
11952
|
+
entityId: row.entity_id,
|
|
11953
|
+
sourceSessionId: row.source_session_id,
|
|
11954
|
+
humanEdited: row.human_edited === 1,
|
|
11955
|
+
promptHash: row.prompt_hash,
|
|
11956
|
+
createdAt: row.created_at,
|
|
11957
|
+
updatedAt: row.updated_at
|
|
11958
|
+
};
|
|
11959
|
+
}
|
|
11960
|
+
function lookupCacheByEntity(db, entityType, entityId) {
|
|
11961
|
+
const row = db.prepare(
|
|
11962
|
+
`SELECT input_hash, entity_type, entity_id, source_session_id, human_edited, created_at, updated_at, prompt_hash
|
|
11963
|
+
FROM generation_cache
|
|
11964
|
+
WHERE entity_type = ? AND entity_id = ?
|
|
11965
|
+
ORDER BY updated_at DESC LIMIT 1`
|
|
11966
|
+
).get(entityType, entityId);
|
|
11967
|
+
if (!row) return null;
|
|
11968
|
+
return {
|
|
11969
|
+
inputHash: row.input_hash,
|
|
11970
|
+
entityType: row.entity_type,
|
|
11971
|
+
entityId: row.entity_id,
|
|
11972
|
+
sourceSessionId: row.source_session_id,
|
|
11973
|
+
humanEdited: row.human_edited === 1,
|
|
11974
|
+
promptHash: row.prompt_hash,
|
|
11975
|
+
createdAt: row.created_at,
|
|
11976
|
+
updatedAt: row.updated_at
|
|
11977
|
+
};
|
|
11978
|
+
}
|
|
11979
|
+
function storeCache(db, inputHash, entityType, entityId, sourceSessionId, humanEdited, promptHash = "") {
|
|
11980
|
+
storeCaches(db, [{ inputHash, entityType, entityId, sourceSessionId, humanEdited, promptHash }]);
|
|
11981
|
+
}
|
|
11982
|
+
function storeCaches(db, entries) {
|
|
11983
|
+
if (entries.length === 0) return;
|
|
11984
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
11985
|
+
const insert = db.prepare(
|
|
11986
|
+
`INSERT INTO generation_cache (input_hash, entity_type, entity_id, source_session_id, human_edited, created_at, updated_at, prompt_hash)
|
|
11987
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
11988
|
+
ON CONFLICT(input_hash, prompt_hash, entity_type, entity_id) DO UPDATE SET
|
|
11989
|
+
source_session_id = excluded.source_session_id,
|
|
11990
|
+
human_edited = CASE WHEN generation_cache.human_edited = 1 THEN 1 ELSE excluded.human_edited END,
|
|
11991
|
+
updated_at = excluded.updated_at`
|
|
11992
|
+
);
|
|
11993
|
+
db.exec("BEGIN");
|
|
11994
|
+
try {
|
|
11995
|
+
for (const entry of entries) {
|
|
11996
|
+
insert.run(
|
|
11997
|
+
entry.inputHash,
|
|
11998
|
+
entry.entityType,
|
|
11999
|
+
entry.entityId,
|
|
12000
|
+
entry.sourceSessionId,
|
|
12001
|
+
entry.humanEdited ? 1 : 0,
|
|
12002
|
+
now,
|
|
12003
|
+
now,
|
|
12004
|
+
entry.promptHash ?? ""
|
|
12005
|
+
);
|
|
12006
|
+
}
|
|
12007
|
+
db.exec("COMMIT");
|
|
12008
|
+
} catch (e) {
|
|
12009
|
+
db.exec("ROLLBACK");
|
|
12010
|
+
throw e;
|
|
12011
|
+
}
|
|
12012
|
+
}
|
|
11663
12013
|
function storeScannedFiles(db, sessionId2, filePaths) {
|
|
11664
12014
|
db.exec("BEGIN");
|
|
11665
12015
|
try {
|
|
@@ -11742,7 +12092,105 @@ function filterUnknownSlotAllowedComponents(db, sessionId2, allowedComponentName
|
|
|
11742
12092
|
}
|
|
11743
12093
|
return unknown;
|
|
11744
12094
|
}
|
|
11745
|
-
function
|
|
12095
|
+
function copyComponentFromCache(db, sourceSessionId, targetSessionId, componentId, manageTransaction = true, options = {}) {
|
|
12096
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12097
|
+
if (manageTransaction) db.exec("BEGIN");
|
|
12098
|
+
try {
|
|
12099
|
+
const srcComp = db.prepare(
|
|
12100
|
+
`SELECT description, status, component_description_rationale, props_rationale, slots_rationale
|
|
12101
|
+
FROM raw_components WHERE session_id = ? AND component_id = ?`
|
|
12102
|
+
).get(sourceSessionId, componentId);
|
|
12103
|
+
if (srcComp) {
|
|
12104
|
+
db.prepare(
|
|
12105
|
+
`UPDATE raw_components
|
|
12106
|
+
SET description = ?, status = ?, component_description_rationale = ?, props_rationale = ?, slots_rationale = ?, extracted_at = ?
|
|
12107
|
+
WHERE session_id = ? AND component_id = ?`
|
|
12108
|
+
).run(
|
|
12109
|
+
srcComp.description,
|
|
12110
|
+
srcComp.status,
|
|
12111
|
+
srcComp.component_description_rationale,
|
|
12112
|
+
srcComp.props_rationale,
|
|
12113
|
+
srcComp.slots_rationale,
|
|
12114
|
+
now,
|
|
12115
|
+
targetSessionId,
|
|
12116
|
+
componentId
|
|
12117
|
+
);
|
|
12118
|
+
}
|
|
12119
|
+
const srcProps = db.prepare(
|
|
12120
|
+
`SELECT name, cdf_type, cdf_category, cdf_token_kind, required, description, default_value, rationale
|
|
12121
|
+
FROM raw_props WHERE session_id = ? AND component_id = ?`
|
|
12122
|
+
).all(sourceSessionId, componentId);
|
|
12123
|
+
for (const p of srcProps) {
|
|
12124
|
+
db.prepare(
|
|
12125
|
+
`UPDATE raw_props SET cdf_type = ?, cdf_category = ?, cdf_token_kind = ?, required = ?, description = ?, default_value = ?, rationale = ?
|
|
12126
|
+
WHERE session_id = ? AND component_id = ? AND name = ?`
|
|
12127
|
+
).run(
|
|
12128
|
+
p.cdf_type,
|
|
12129
|
+
p.cdf_category,
|
|
12130
|
+
p.cdf_token_kind,
|
|
12131
|
+
p.required,
|
|
12132
|
+
p.description,
|
|
12133
|
+
p.default_value,
|
|
12134
|
+
p.rationale,
|
|
12135
|
+
targetSessionId,
|
|
12136
|
+
componentId,
|
|
12137
|
+
p.name
|
|
12138
|
+
);
|
|
12139
|
+
}
|
|
12140
|
+
db.prepare(`DELETE FROM raw_prop_allowed_values WHERE session_id = ? AND component_id = ?`).run(
|
|
12141
|
+
targetSessionId,
|
|
12142
|
+
componentId
|
|
12143
|
+
);
|
|
12144
|
+
const srcAV = db.prepare(
|
|
12145
|
+
`SELECT prop_name, position, value FROM raw_prop_allowed_values WHERE session_id = ? AND component_id = ?`
|
|
12146
|
+
).all(sourceSessionId, componentId);
|
|
12147
|
+
const insertAV = db.prepare(
|
|
12148
|
+
`INSERT INTO raw_prop_allowed_values (session_id, component_id, prop_name, position, value) VALUES (?, ?, ?, ?, ?)`
|
|
12149
|
+
);
|
|
12150
|
+
for (const av of srcAV) {
|
|
12151
|
+
insertAV.run(targetSessionId, componentId, av.prop_name, av.position, av.value);
|
|
12152
|
+
}
|
|
12153
|
+
const srcSlots = db.prepare(`SELECT name, required, description, rationale FROM raw_slots WHERE session_id = ? AND component_id = ?`).all(sourceSessionId, componentId);
|
|
12154
|
+
for (const s of srcSlots) {
|
|
12155
|
+
db.prepare(
|
|
12156
|
+
`UPDATE raw_slots SET required = ?, description = ?, rationale = ? WHERE session_id = ? AND component_id = ? AND name = ?`
|
|
12157
|
+
).run(s.required, s.description, s.rationale, targetSessionId, componentId, s.name);
|
|
12158
|
+
}
|
|
12159
|
+
db.prepare(`DELETE FROM raw_slot_allowed_components WHERE session_id = ? AND component_id = ?`).run(
|
|
12160
|
+
targetSessionId,
|
|
12161
|
+
componentId
|
|
12162
|
+
);
|
|
12163
|
+
const srcSAC = db.prepare(
|
|
12164
|
+
`SELECT slot_name, position, allowed_component FROM raw_slot_allowed_components WHERE session_id = ? AND component_id = ?`
|
|
12165
|
+
).all(sourceSessionId, componentId);
|
|
12166
|
+
const insertSAC = db.prepare(
|
|
12167
|
+
`INSERT INTO raw_slot_allowed_components (session_id, component_id, slot_name, allowed_component, position) VALUES (?, ?, ?, ?, ?)`
|
|
12168
|
+
);
|
|
12169
|
+
const allowedSAC = options.allowedComponentNames ? srcSAC.filter((sac) => options.allowedComponentNames.has(sac.allowed_component)) : srcSAC;
|
|
12170
|
+
for (const sac of allowedSAC) {
|
|
12171
|
+
insertSAC.run(targetSessionId, componentId, sac.slot_name, sac.allowed_component, sac.position);
|
|
12172
|
+
}
|
|
12173
|
+
db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(now, targetSessionId);
|
|
12174
|
+
if (manageTransaction) db.exec("COMMIT");
|
|
12175
|
+
} catch (e) {
|
|
12176
|
+
if (manageTransaction) db.exec("ROLLBACK");
|
|
12177
|
+
throw e;
|
|
12178
|
+
}
|
|
12179
|
+
}
|
|
12180
|
+
function copyComponentsFromCache(db, entries, options = {}) {
|
|
12181
|
+
if (entries.length === 0) return;
|
|
12182
|
+
db.exec("BEGIN");
|
|
12183
|
+
try {
|
|
12184
|
+
for (const entry of entries) {
|
|
12185
|
+
copyComponentFromCache(db, entry.sourceSessionId, entry.targetSessionId, entry.componentId, false, options);
|
|
12186
|
+
}
|
|
12187
|
+
db.exec("COMMIT");
|
|
12188
|
+
} catch (e) {
|
|
12189
|
+
db.exec("ROLLBACK");
|
|
12190
|
+
throw e;
|
|
12191
|
+
}
|
|
12192
|
+
}
|
|
12193
|
+
function copyTokensFromCache(db, sourceSessionId, targetSessionId) {
|
|
11746
12194
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
11747
12195
|
db.exec("BEGIN");
|
|
11748
12196
|
try {
|
|
@@ -11763,7 +12211,153 @@ function copyTokensBetweenSessions(db, sourceSessionId, targetSessionId) {
|
|
|
11763
12211
|
throw e;
|
|
11764
12212
|
}
|
|
11765
12213
|
}
|
|
11766
|
-
|
|
12214
|
+
function copyMapTokensFromCache(db, sourceSessionId, targetSessionId) {
|
|
12215
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12216
|
+
let copiedCount = 0;
|
|
12217
|
+
db.exec("BEGIN");
|
|
12218
|
+
try {
|
|
12219
|
+
const sourceRows = db.prepare(
|
|
12220
|
+
`SELECT rc.name AS component_name, rptp.prop_name, rptp.source, rptp.position, rptp.path
|
|
12221
|
+
FROM raw_prop_token_paths rptp
|
|
12222
|
+
JOIN raw_components rc ON rc.session_id = rptp.session_id AND rc.component_id = rptp.component_id
|
|
12223
|
+
WHERE rptp.session_id = ?
|
|
12224
|
+
ORDER BY rc.name, rptp.prop_name, rptp.position`
|
|
12225
|
+
).all(sourceSessionId);
|
|
12226
|
+
const targetComponents = db.prepare(`SELECT component_id, name FROM raw_components WHERE session_id = ?`).all(targetSessionId);
|
|
12227
|
+
const targetIdByName = new Map(targetComponents.map((c2) => [c2.name, c2.component_id]));
|
|
12228
|
+
const targetProps = new Set(
|
|
12229
|
+
db.prepare(`SELECT component_id, name FROM raw_props WHERE session_id = ?`).all(targetSessionId).map((p) => `${p.component_id}::${p.name}`)
|
|
12230
|
+
);
|
|
12231
|
+
const insertPath = db.prepare(
|
|
12232
|
+
`INSERT INTO raw_prop_token_paths (session_id, component_id, prop_name, source, position, path)
|
|
12233
|
+
VALUES (?, ?, ?, ?, ?, ?)`
|
|
12234
|
+
);
|
|
12235
|
+
const clearedProps = /* @__PURE__ */ new Set();
|
|
12236
|
+
const copiedProps = /* @__PURE__ */ new Set();
|
|
12237
|
+
for (const row of sourceRows) {
|
|
12238
|
+
const targetComponentId = targetIdByName.get(row.component_name);
|
|
12239
|
+
if (!targetComponentId) continue;
|
|
12240
|
+
if (!targetProps.has(`${targetComponentId}::${row.prop_name}`)) continue;
|
|
12241
|
+
const propKey = `${targetComponentId}::${row.prop_name}`;
|
|
12242
|
+
if (!clearedProps.has(propKey)) {
|
|
12243
|
+
clearedProps.add(propKey);
|
|
12244
|
+
db.prepare(`DELETE FROM raw_prop_token_paths WHERE session_id = ? AND component_id = ? AND prop_name = ?`).run(
|
|
12245
|
+
targetSessionId,
|
|
12246
|
+
targetComponentId,
|
|
12247
|
+
row.prop_name
|
|
12248
|
+
);
|
|
12249
|
+
}
|
|
12250
|
+
insertPath.run(targetSessionId, targetComponentId, row.prop_name, row.source, row.position, row.path);
|
|
12251
|
+
copiedProps.add(propKey);
|
|
12252
|
+
}
|
|
12253
|
+
copiedCount = copiedProps.size;
|
|
12254
|
+
db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(now, targetSessionId);
|
|
12255
|
+
db.exec("COMMIT");
|
|
12256
|
+
} catch (e) {
|
|
12257
|
+
db.exec("ROLLBACK");
|
|
12258
|
+
throw e;
|
|
12259
|
+
}
|
|
12260
|
+
return copiedCount;
|
|
12261
|
+
}
|
|
12262
|
+
async function getCliCacheVersion() {
|
|
12263
|
+
if (_cliCacheVersionCache) return _cliCacheVersionCache;
|
|
12264
|
+
try {
|
|
12265
|
+
const { hashContent: hashContent2 } = await Promise.resolve().then(() => (init_cache_keys(), cache_keys_exports));
|
|
12266
|
+
const { resolveSkillPath: resolveSkillPath2 } = await Promise.resolve().then(() => (init_src(), src_exports));
|
|
12267
|
+
const skills = ["components", "tokens", "select"];
|
|
12268
|
+
const parts = [];
|
|
12269
|
+
for (const s of skills) {
|
|
12270
|
+
try {
|
|
12271
|
+
const p = resolveSkillPath2(s);
|
|
12272
|
+
parts.push(readFileSync5(p, "utf8"));
|
|
12273
|
+
} catch {
|
|
12274
|
+
parts.push(`<missing:${s}>`);
|
|
12275
|
+
}
|
|
12276
|
+
}
|
|
12277
|
+
_cliCacheVersionCache = hashContent2(parts.join("\n---\n"));
|
|
12278
|
+
return _cliCacheVersionCache;
|
|
12279
|
+
} catch {
|
|
12280
|
+
_cliCacheVersionCache = "fallback";
|
|
12281
|
+
return _cliCacheVersionCache;
|
|
12282
|
+
}
|
|
12283
|
+
}
|
|
12284
|
+
function storeExtractCache(db, filePath, fileHash, cliVersion2, components) {
|
|
12285
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12286
|
+
const componentsJson = JSON.stringify(components);
|
|
12287
|
+
db.prepare(
|
|
12288
|
+
`INSERT INTO extract_cache (file_path, file_hash, cli_version, created_at, updated_at, components_json)
|
|
12289
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
12290
|
+
ON CONFLICT(file_hash, cli_version) DO UPDATE SET
|
|
12291
|
+
file_path = excluded.file_path,
|
|
12292
|
+
updated_at = excluded.updated_at,
|
|
12293
|
+
components_json = excluded.components_json`
|
|
12294
|
+
).run(filePath, fileHash, cliVersion2, now, now, componentsJson);
|
|
12295
|
+
}
|
|
12296
|
+
function lookupExtractCache(db, fileHash, cliVersion2) {
|
|
12297
|
+
const row = db.prepare(
|
|
12298
|
+
`SELECT file_path, file_hash, cli_version, created_at, updated_at, components_json
|
|
12299
|
+
FROM extract_cache
|
|
12300
|
+
WHERE file_hash = ? AND cli_version = ?`
|
|
12301
|
+
).get(fileHash, cliVersion2);
|
|
12302
|
+
if (!row) return null;
|
|
12303
|
+
let components = [];
|
|
12304
|
+
try {
|
|
12305
|
+
components = JSON.parse(row.components_json);
|
|
12306
|
+
} catch {
|
|
12307
|
+
return null;
|
|
12308
|
+
}
|
|
12309
|
+
return {
|
|
12310
|
+
filePath: row.file_path,
|
|
12311
|
+
fileHash: row.file_hash,
|
|
12312
|
+
cliVersion: row.cli_version,
|
|
12313
|
+
createdAt: row.created_at,
|
|
12314
|
+
updatedAt: row.updated_at,
|
|
12315
|
+
components
|
|
12316
|
+
};
|
|
12317
|
+
}
|
|
12318
|
+
function storeCompositionCache(db, inputHash, cliVersion2, agentOutput) {
|
|
12319
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12320
|
+
db.prepare(
|
|
12321
|
+
`INSERT INTO composition_cache (input_hash, cli_version, agent_output, created_at, updated_at)
|
|
12322
|
+
VALUES (?, ?, ?, ?, ?)
|
|
12323
|
+
ON CONFLICT(input_hash, cli_version) DO UPDATE SET
|
|
12324
|
+
agent_output = excluded.agent_output,
|
|
12325
|
+
updated_at = excluded.updated_at`
|
|
12326
|
+
).run(inputHash, cliVersion2, agentOutput, now, now);
|
|
12327
|
+
}
|
|
12328
|
+
function lookupCompositionCache(db, inputHash, cliVersion2) {
|
|
12329
|
+
const row = db.prepare(`SELECT agent_output FROM composition_cache WHERE input_hash = ? AND cli_version = ?`).get(inputHash, cliVersion2);
|
|
12330
|
+
return row ? row.agent_output : null;
|
|
12331
|
+
}
|
|
12332
|
+
function storeSelectCache(db, componentHash, promptHash, cliVersion2, decision, reason) {
|
|
12333
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12334
|
+
db.prepare(
|
|
12335
|
+
`INSERT INTO select_cache (component_hash, prompt_hash, cli_version, decision, reason, created_at, updated_at)
|
|
12336
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
12337
|
+
ON CONFLICT(component_hash, prompt_hash, cli_version) DO UPDATE SET
|
|
12338
|
+
decision = excluded.decision,
|
|
12339
|
+
reason = excluded.reason,
|
|
12340
|
+
updated_at = excluded.updated_at`
|
|
12341
|
+
).run(componentHash, promptHash, cliVersion2, decision, reason, now, now);
|
|
12342
|
+
}
|
|
12343
|
+
function lookupSelectCache(db, componentHash, promptHash, cliVersion2) {
|
|
12344
|
+
const row = db.prepare(
|
|
12345
|
+
`SELECT component_hash, prompt_hash, cli_version, decision, reason, created_at, updated_at
|
|
12346
|
+
FROM select_cache
|
|
12347
|
+
WHERE component_hash = ? AND prompt_hash = ? AND cli_version = ?`
|
|
12348
|
+
).get(componentHash, promptHash, cliVersion2);
|
|
12349
|
+
if (!row) return null;
|
|
12350
|
+
return {
|
|
12351
|
+
componentHash: row.component_hash,
|
|
12352
|
+
promptHash: row.prompt_hash,
|
|
12353
|
+
cliVersion: row.cli_version,
|
|
12354
|
+
decision: row.decision,
|
|
12355
|
+
reason: row.reason,
|
|
12356
|
+
createdAt: row.created_at,
|
|
12357
|
+
updatedAt: row.updated_at
|
|
12358
|
+
};
|
|
12359
|
+
}
|
|
12360
|
+
var SCHEMA, MAX_COMPONENT_SOURCE_CHARS, MAX_SIBLING_FILES, MAX_SIBLING_SNIPPET_CHARS, MAX_TYPE_DECLARING_SIBLING_CHARS, MAX_ENLARGED_SIBLINGS, MAX_SIBLING_DEPTH, MAX_SIBLING_CANDIDATES_EXPLORED, RELATIVE_IMPORT_PATTERN, SIBLING_FILE_EXTENSIONS, TS_ESM_EXTENSION_REWRITES, IDENTIFIER_PATTERN, _cliCacheVersionCache;
|
|
11767
12361
|
var init_db = __esm({
|
|
11768
12362
|
"packages/experience-design-system-cli-legacy/src/session/db.ts"() {
|
|
11769
12363
|
"use strict";
|
|
@@ -11777,6 +12371,8 @@ var init_db = __esm({
|
|
|
11777
12371
|
init_write2();
|
|
11778
12372
|
init_session_resolver();
|
|
11779
12373
|
init_read3();
|
|
12374
|
+
init_hash_component_shape();
|
|
12375
|
+
init_hash_token_content();
|
|
11780
12376
|
init_read3();
|
|
11781
12377
|
init_store_dtcg_tokens();
|
|
11782
12378
|
init_apply_tool_calls();
|
|
@@ -11900,6 +12496,17 @@ CREATE TABLE IF NOT EXISTS raw_tokens (
|
|
|
11900
12496
|
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
11901
12497
|
);
|
|
11902
12498
|
|
|
12499
|
+
CREATE TABLE IF NOT EXISTS generation_cache (
|
|
12500
|
+
input_hash TEXT NOT NULL,
|
|
12501
|
+
entity_type TEXT NOT NULL CHECK (entity_type IN ('component', 'token_set', 'token_mapping')),
|
|
12502
|
+
entity_id TEXT NOT NULL,
|
|
12503
|
+
source_session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
12504
|
+
human_edited INTEGER NOT NULL DEFAULT 0 CHECK (human_edited IN (0, 1)),
|
|
12505
|
+
created_at TEXT NOT NULL,
|
|
12506
|
+
updated_at TEXT NOT NULL,
|
|
12507
|
+
PRIMARY KEY (input_hash, entity_type, entity_id)
|
|
12508
|
+
);
|
|
12509
|
+
|
|
11903
12510
|
CREATE TABLE IF NOT EXISTS scanned_files (
|
|
11904
12511
|
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
11905
12512
|
path TEXT NOT NULL,
|
|
@@ -11945,9 +12552,10 @@ CREATE INDEX IF NOT EXISTS idx_raw_props_session ON raw_props(session_id,
|
|
|
11945
12552
|
CREATE INDEX IF NOT EXISTS idx_raw_slots_session ON raw_slots(session_id, component_id);
|
|
11946
12553
|
CREATE INDEX IF NOT EXISTS idx_raw_tokens_session ON raw_tokens(session_id);
|
|
11947
12554
|
CREATE INDEX IF NOT EXISTS idx_raw_token_groups_session ON raw_token_groups(session_id);
|
|
12555
|
+
CREATE INDEX IF NOT EXISTS idx_generation_cache_entity ON generation_cache(entity_type, entity_id);
|
|
12556
|
+
CREATE INDEX IF NOT EXISTS idx_generation_cache_session ON generation_cache(source_session_id);
|
|
11948
12557
|
CREATE INDEX IF NOT EXISTS idx_scanned_files_session ON scanned_files(session_id);
|
|
11949
12558
|
`;
|
|
11950
|
-
REMOVED_CACHE_TABLES = ["generation_cache", "extract_cache", "composition_cache", "select_cache"];
|
|
11951
12559
|
MAX_COMPONENT_SOURCE_CHARS = 8e3;
|
|
11952
12560
|
MAX_SIBLING_FILES = 5;
|
|
11953
12561
|
MAX_SIBLING_SNIPPET_CHARS = 1200;
|
|
@@ -11964,15 +12572,16 @@ CREATE INDEX IF NOT EXISTS idx_scanned_files_session ON scanned_files(session
|
|
|
11964
12572
|
[".cjs", [".cts", ".cjs"]]
|
|
11965
12573
|
];
|
|
11966
12574
|
IDENTIFIER_PATTERN = /[A-Za-z_$][A-Za-z0-9_$]*/g;
|
|
12575
|
+
_cliCacheVersionCache = null;
|
|
11967
12576
|
}
|
|
11968
12577
|
});
|
|
11969
12578
|
|
|
11970
12579
|
// packages/experience-design-system-cli-legacy/src/helpers/read-existing-contentful-entities-from-session.ts
|
|
11971
|
-
import { readFile as
|
|
12580
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
11972
12581
|
async function readExistingContentfulEntitiesFromSession(path) {
|
|
11973
12582
|
if (!path) return void 0;
|
|
11974
12583
|
try {
|
|
11975
|
-
const raw = await
|
|
12584
|
+
const raw = await readFile9(path, "utf8");
|
|
11976
12585
|
const parsed = JSON.parse(raw);
|
|
11977
12586
|
if (!Array.isArray(parsed.components) || !Array.isArray(parsed.tokens)) return void 0;
|
|
11978
12587
|
return parsed;
|
|
@@ -12096,21 +12705,21 @@ var init_resolve_session_id = __esm({
|
|
|
12096
12705
|
});
|
|
12097
12706
|
|
|
12098
12707
|
// packages/experience-design-system-cli-legacy/src/analyze/select/persistence.ts
|
|
12099
|
-
import { access, appendFile, mkdir as mkdir2, readFile as
|
|
12708
|
+
import { access, appendFile, mkdir as mkdir2, readFile as readFile10, writeFile as writeFile2 } from "node:fs/promises";
|
|
12100
12709
|
import { homedir as homedir4 } from "node:os";
|
|
12101
|
-
import { resolve as
|
|
12710
|
+
import { resolve as resolve10 } from "node:path";
|
|
12102
12711
|
function getRefineArtifactsRoot() {
|
|
12103
12712
|
if (process.env.EDS_REVIEW_ARTIFACTS_DIR) {
|
|
12104
|
-
return
|
|
12713
|
+
return resolve10(process.env.EDS_REVIEW_ARTIFACTS_DIR);
|
|
12105
12714
|
}
|
|
12106
|
-
return
|
|
12715
|
+
return resolve10(homedir4(), ".contentful", "experience-design-system-cli", "reviews");
|
|
12107
12716
|
}
|
|
12108
12717
|
async function getRefineSessionPaths(sessionId2, artifactsRoot) {
|
|
12109
|
-
const sessionDir =
|
|
12718
|
+
const sessionDir = resolve10(artifactsRoot, sessionId2);
|
|
12110
12719
|
return {
|
|
12111
12720
|
sessionDir,
|
|
12112
|
-
eventsPath:
|
|
12113
|
-
statePath:
|
|
12721
|
+
eventsPath: resolve10(sessionDir, "events.jsonl"),
|
|
12722
|
+
statePath: resolve10(sessionDir, "current-review-state.json")
|
|
12114
12723
|
};
|
|
12115
12724
|
}
|
|
12116
12725
|
async function saveReviewState(statePath, session) {
|
|
@@ -12121,7 +12730,7 @@ async function ensureRefineSession(sessionId2, artifactsRoot, initialSnapshot) {
|
|
|
12121
12730
|
await mkdir2(paths.sessionDir, { recursive: true });
|
|
12122
12731
|
try {
|
|
12123
12732
|
await access(paths.statePath);
|
|
12124
|
-
const savedState = await
|
|
12733
|
+
const savedState = await readFile10(paths.statePath, "utf8");
|
|
12125
12734
|
return JSON.parse(savedState);
|
|
12126
12735
|
} catch {
|
|
12127
12736
|
await writeFile2(paths.statePath, JSON.stringify(initialSnapshot, null, 2), "utf8");
|
|
@@ -12606,8 +13215,8 @@ var init_path_exists = __esm({
|
|
|
12606
13215
|
});
|
|
12607
13216
|
|
|
12608
13217
|
// packages/experience-design-system-cli-legacy/src/lib/prompt-overrides.ts
|
|
12609
|
-
import { readFile as
|
|
12610
|
-
import { resolve as
|
|
13218
|
+
import { readFile as readFile11 } from "node:fs/promises";
|
|
13219
|
+
import { resolve as resolve11 } from "node:path";
|
|
12611
13220
|
function looksLikePath(value) {
|
|
12612
13221
|
if (value.includes("/") || value.includes("\\")) return true;
|
|
12613
13222
|
if (value.startsWith("~")) return true;
|
|
@@ -12639,9 +13248,9 @@ function parsePromptOverrides(inputs) {
|
|
|
12639
13248
|
}
|
|
12640
13249
|
async function resolvePromptOverride(override) {
|
|
12641
13250
|
if (override.kind === "text") return override.value;
|
|
12642
|
-
const abs =
|
|
13251
|
+
const abs = resolve11(override.value);
|
|
12643
13252
|
try {
|
|
12644
|
-
return await
|
|
13253
|
+
return await readFile11(abs, "utf8");
|
|
12645
13254
|
} catch {
|
|
12646
13255
|
throw new Error(`--prompt: could not read prompt file: ${abs}`);
|
|
12647
13256
|
}
|
|
@@ -12656,21 +13265,21 @@ var init_prompt_overrides = __esm({
|
|
|
12656
13265
|
|
|
12657
13266
|
// packages/experience-design-system-cli-legacy/src/generate/command.ts
|
|
12658
13267
|
import { createElement } from "react";
|
|
12659
|
-
import { readFile as
|
|
12660
|
-
import { join as join14, resolve as
|
|
13268
|
+
import { readFile as readFile12, readdir, stat } from "node:fs/promises";
|
|
13269
|
+
import { join as join14, resolve as resolve12 } from "node:path";
|
|
12661
13270
|
async function assertFileExists(flag, p) {
|
|
12662
13271
|
if (!await pathExists(p)) die(`Error: file not found: ${p} (from ${flag})`);
|
|
12663
13272
|
}
|
|
12664
13273
|
async function readFileInline(path) {
|
|
12665
13274
|
if (!path) return void 0;
|
|
12666
|
-
const resolved =
|
|
13275
|
+
const resolved = resolve12(path);
|
|
12667
13276
|
let s;
|
|
12668
13277
|
try {
|
|
12669
13278
|
s = await stat(resolved);
|
|
12670
13279
|
} catch {
|
|
12671
13280
|
return void 0;
|
|
12672
13281
|
}
|
|
12673
|
-
if (!s.isDirectory()) return
|
|
13282
|
+
if (!s.isDirectory()) return readFile12(resolved, "utf8");
|
|
12674
13283
|
const files = [];
|
|
12675
13284
|
async function walk(dir) {
|
|
12676
13285
|
let entries;
|
|
@@ -12696,7 +13305,7 @@ async function readFileInline(path) {
|
|
|
12696
13305
|
}
|
|
12697
13306
|
await walk(resolved);
|
|
12698
13307
|
if (files.length === 0) return void 0;
|
|
12699
|
-
const parts = await Promise.all(files.map((f) =>
|
|
13308
|
+
const parts = await Promise.all(files.map((f) => readFile12(f, "utf8").catch(() => "")));
|
|
12700
13309
|
return parts.filter(Boolean).join("\n\n");
|
|
12701
13310
|
}
|
|
12702
13311
|
function printFallbackInstructions(options) {
|
|
@@ -12718,6 +13327,23 @@ function printFallbackInstructions(options) {
|
|
|
12718
13327
|
lines.push(` Re-run the generate command with the agent available, or use --dry-run to inspect the prompt.`);
|
|
12719
13328
|
process.stderr.write(lines.join("\n") + "\n");
|
|
12720
13329
|
}
|
|
13330
|
+
function createCachedComponentResult(componentName, warnings = []) {
|
|
13331
|
+
return {
|
|
13332
|
+
componentName,
|
|
13333
|
+
classified: 0,
|
|
13334
|
+
excluded: 0,
|
|
13335
|
+
slots: 0,
|
|
13336
|
+
warnings,
|
|
13337
|
+
failed: false,
|
|
13338
|
+
cached: true,
|
|
13339
|
+
renamedSlotsCount: 0
|
|
13340
|
+
};
|
|
13341
|
+
}
|
|
13342
|
+
function writeCachedComponentStatus(position, componentName, pinned) {
|
|
13343
|
+
const status = pinned ? c.cyan("pinned (human-edited)") : c.green("cached");
|
|
13344
|
+
process.stderr.write(` ${position} ${c.bold(componentName)} ${status}
|
|
13345
|
+
`);
|
|
13346
|
+
}
|
|
12721
13347
|
async function showGenerateView(result) {
|
|
12722
13348
|
if (process.stdout.isTTY) {
|
|
12723
13349
|
const { waitUntilExit } = renderWithGoodbye(
|
|
@@ -12738,6 +13364,29 @@ session=${result.sessionId}
|
|
|
12738
13364
|
);
|
|
12739
13365
|
await exitWithAnalytics(0);
|
|
12740
13366
|
}
|
|
13367
|
+
function normalizeComponentForCache(component) {
|
|
13368
|
+
const slots = component.slots.map((slot, index, allSlots) => ({
|
|
13369
|
+
...slot,
|
|
13370
|
+
name: slot.name.trim() || (allSlots.length === 1 ? "children" : `slot_${index}`)
|
|
13371
|
+
}));
|
|
13372
|
+
return { ...component, slots };
|
|
13373
|
+
}
|
|
13374
|
+
function lookupComponentCache(db, component, promptHash) {
|
|
13375
|
+
const normalized = normalizeComponentForCache(component);
|
|
13376
|
+
const inputHash = hashComponentShape(normalized);
|
|
13377
|
+
const cached = lookupCache(db, inputHash, "component", component.component_id, promptHash);
|
|
13378
|
+
if (cached) return cached;
|
|
13379
|
+
const legacyInputHash = hashComponentShape(component);
|
|
13380
|
+
return legacyInputHash === inputHash ? null : lookupCache(db, legacyInputHash, "component", component.component_id, promptHash);
|
|
13381
|
+
}
|
|
13382
|
+
function resolveComponentCache(db, component, promptHash, allowedComponentNames2) {
|
|
13383
|
+
const cached = lookupComponentCache(db, component, promptHash);
|
|
13384
|
+
if (cached && findUnknownSlotAllowedComponents(db, cached.sourceSessionId, allowedComponentNames2, component.component_id).length === 0) {
|
|
13385
|
+
return { entry: cached, humanEdited: cached.humanEdited };
|
|
13386
|
+
}
|
|
13387
|
+
const pinned = lookupCacheByEntity(db, "component", component.component_id);
|
|
13388
|
+
return pinned?.humanEdited && findUnknownSlotAllowedComponents(db, pinned.sourceSessionId, allowedComponentNames2, component.component_id).length === 0 ? { entry: pinned, humanEdited: true } : null;
|
|
13389
|
+
}
|
|
12741
13390
|
async function runOneComponent(options, component, index, total) {
|
|
12742
13391
|
const {
|
|
12743
13392
|
agent,
|
|
@@ -12747,10 +13396,13 @@ async function runOneComponent(options, component, index, total) {
|
|
|
12747
13396
|
tokensInline,
|
|
12748
13397
|
tokenMapInline,
|
|
12749
13398
|
verbose,
|
|
13399
|
+
noCache,
|
|
12750
13400
|
skillPathOverride,
|
|
12751
13401
|
skillContentOverride,
|
|
13402
|
+
promptHash,
|
|
12752
13403
|
existingContentfulEntities,
|
|
12753
13404
|
existingTokensInline,
|
|
13405
|
+
precomputedCachedNames,
|
|
12754
13406
|
allowedComponentNames: allowedComponentNames2
|
|
12755
13407
|
} = options;
|
|
12756
13408
|
const pos = c.dim(`[${index + 1}/${total}]`);
|
|
@@ -12775,6 +13427,40 @@ async function runOneComponent(options, component, index, total) {
|
|
|
12775
13427
|
allowedComponents: slot.allowedComponents.filter((name) => allowedComponentNames2.has(name))
|
|
12776
13428
|
};
|
|
12777
13429
|
});
|
|
13430
|
+
const cacheComponent = normalizeComponentForCache(component);
|
|
13431
|
+
if (!noCache && precomputedCachedNames.has(component.name)) {
|
|
13432
|
+
writeCachedComponentStatus(pos, component.name, false);
|
|
13433
|
+
return createCachedComponentResult(component.name);
|
|
13434
|
+
}
|
|
13435
|
+
if (!noCache) {
|
|
13436
|
+
const inputHash = hashComponentShape(cacheComponent);
|
|
13437
|
+
const resolution = resolveComponentCache(db, component, promptHash, allowedComponentNames2);
|
|
13438
|
+
if (resolution && !resolution.humanEdited) {
|
|
13439
|
+
copyComponentFromCache(db, resolution.entry.sourceSessionId, sessionId2, component.component_id, true, {
|
|
13440
|
+
allowedComponentNames: allowedComponentNames2
|
|
13441
|
+
});
|
|
13442
|
+
storeCache(
|
|
13443
|
+
db,
|
|
13444
|
+
inputHash,
|
|
13445
|
+
"component",
|
|
13446
|
+
component.component_id,
|
|
13447
|
+
resolution.entry.sourceSessionId,
|
|
13448
|
+
resolution.entry.humanEdited,
|
|
13449
|
+
promptHash
|
|
13450
|
+
);
|
|
13451
|
+
writeCachedComponentStatus(pos, component.name, false);
|
|
13452
|
+
return createCachedComponentResult(component.name);
|
|
13453
|
+
}
|
|
13454
|
+
if (resolution?.humanEdited) {
|
|
13455
|
+
copyComponentFromCache(db, resolution.entry.sourceSessionId, sessionId2, component.component_id, true, {
|
|
13456
|
+
allowedComponentNames: allowedComponentNames2
|
|
13457
|
+
});
|
|
13458
|
+
writeCachedComponentStatus(pos, component.name, true);
|
|
13459
|
+
return createCachedComponentResult(`${component.name}`, [
|
|
13460
|
+
`${component.name}: source changed but human edits preserved`
|
|
13461
|
+
]);
|
|
13462
|
+
}
|
|
13463
|
+
}
|
|
12778
13464
|
const componentBuckets = bucketComponentProps(component);
|
|
12779
13465
|
getDebugLogger().event("analyze", "prop-buckets.generate", { ...componentBuckets });
|
|
12780
13466
|
const rawComponentsInline = JSON.stringify(
|
|
@@ -12849,6 +13535,10 @@ ${outputBuf}`);
|
|
|
12849
13535
|
const applied = applyToolCalls(db, sessionId2, component.component_id, component.name, calls, warnings, {
|
|
12850
13536
|
allowedComponentNames: allowedComponentNames2
|
|
12851
13537
|
});
|
|
13538
|
+
if (!noCache) {
|
|
13539
|
+
const inputHash = hashComponentShape(cacheComponent);
|
|
13540
|
+
storeCache(db, inputHash, "component", component.component_id, sessionId2, false, promptHash);
|
|
13541
|
+
}
|
|
12852
13542
|
return {
|
|
12853
13543
|
componentName: component.name,
|
|
12854
13544
|
classified: applied.classified,
|
|
@@ -12900,7 +13590,7 @@ async function loadAcceptedNames(sessionId2) {
|
|
|
12900
13590
|
try {
|
|
12901
13591
|
const artifactsRoot = getRefineArtifactsRoot();
|
|
12902
13592
|
const paths = await getRefineSessionPaths(sessionId2, artifactsRoot);
|
|
12903
|
-
const raw = await
|
|
13593
|
+
const raw = await readFile12(paths.statePath, "utf8");
|
|
12904
13594
|
const snapshot = JSON.parse(raw);
|
|
12905
13595
|
const accepted = snapshot.components.filter((c2) => c2.status === "accepted").map((c2) => c2.name);
|
|
12906
13596
|
if (accepted.length === 0) return null;
|
|
@@ -12909,6 +13599,15 @@ async function loadAcceptedNames(sessionId2) {
|
|
|
12909
13599
|
return null;
|
|
12910
13600
|
}
|
|
12911
13601
|
}
|
|
13602
|
+
function parsePrecomputedCachedNames(value) {
|
|
13603
|
+
if (!value) return /* @__PURE__ */ new Set();
|
|
13604
|
+
try {
|
|
13605
|
+
const parsed = JSON.parse(value);
|
|
13606
|
+
return new Set(Array.isArray(parsed) ? parsed.filter((name) => typeof name === "string") : []);
|
|
13607
|
+
} catch {
|
|
13608
|
+
return /* @__PURE__ */ new Set();
|
|
13609
|
+
}
|
|
13610
|
+
}
|
|
12912
13611
|
async function runGenerateSkill(skill, opts, verbose = false) {
|
|
12913
13612
|
const savedCreds = await readExperiencesCredentials();
|
|
12914
13613
|
const agentName = opts.agent ?? savedCreds.agent;
|
|
@@ -12937,8 +13636,8 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
12937
13636
|
}
|
|
12938
13637
|
const generatePromptPath = generatePrompt === void 0 ? configuredGeneratePromptPath : void 0;
|
|
12939
13638
|
if (generatePromptPath) {
|
|
12940
|
-
if (!await pathExists(
|
|
12941
|
-
die(`Error: custom prompt path not found: ${
|
|
13639
|
+
if (!await pathExists(resolve12(generatePromptPath))) {
|
|
13640
|
+
die(`Error: custom prompt path not found: ${resolve12(generatePromptPath)}`);
|
|
12942
13641
|
}
|
|
12943
13642
|
if (!generatePromptPath.toLowerCase().endsWith(".md")) {
|
|
12944
13643
|
process.stderr.write(
|
|
@@ -12946,7 +13645,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
12946
13645
|
`
|
|
12947
13646
|
);
|
|
12948
13647
|
}
|
|
12949
|
-
process.stderr.write(formatCustomPromptBanner("components",
|
|
13648
|
+
process.stderr.write(formatCustomPromptBanner("components", resolve12(generatePromptPath)));
|
|
12950
13649
|
}
|
|
12951
13650
|
if (skill === "tokens" && !opts.rawTokens) {
|
|
12952
13651
|
die("Error: --raw-tokens is required when using generate tokens");
|
|
@@ -12962,7 +13661,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
12962
13661
|
let existingContentfulEntities;
|
|
12963
13662
|
let existingTokensInline;
|
|
12964
13663
|
if (opts.existingEntitiesPath) {
|
|
12965
|
-
existingContentfulEntities = await readExistingContentfulEntitiesFromSession(
|
|
13664
|
+
existingContentfulEntities = await readExistingContentfulEntitiesFromSession(resolve12(opts.existingEntitiesPath));
|
|
12966
13665
|
if (existingContentfulEntities) {
|
|
12967
13666
|
existingTokensInline = JSON.stringify(summarizeForMapTokens(existingContentfulEntities));
|
|
12968
13667
|
} else {
|
|
@@ -13063,7 +13762,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
13063
13762
|
rawComponentsInline: sampleInline ?? rawTokensInline,
|
|
13064
13763
|
propBucketsInline: sampleBuckets ? JSON.stringify(sampleBuckets) : void 0,
|
|
13065
13764
|
rawTokensInline: skill === "tokens" ? rawTokensInline : void 0,
|
|
13066
|
-
rawTokensFilename: opts.rawTokens ?
|
|
13765
|
+
rawTokensFilename: opts.rawTokens ? resolve12(opts.rawTokens).split("/").pop() : void 0,
|
|
13067
13766
|
tokensInline,
|
|
13068
13767
|
tokenMapInline,
|
|
13069
13768
|
outDir: process.cwd(),
|
|
@@ -13089,7 +13788,64 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
13089
13788
|
if (skill === "components" && allComponents && sessionId2) {
|
|
13090
13789
|
const db = openPipelineDb();
|
|
13091
13790
|
let componentResults;
|
|
13791
|
+
const precomputedCachedNames = parsePrecomputedCachedNames(opts.cachedComponents);
|
|
13092
13792
|
try {
|
|
13793
|
+
const existingContentfulEntitiesHashInputs = [];
|
|
13794
|
+
if (existingTokensInline) existingContentfulEntitiesHashInputs.push(hashContent(existingTokensInline));
|
|
13795
|
+
const promptHash = await hashPromptForSkill(
|
|
13796
|
+
"components",
|
|
13797
|
+
agent,
|
|
13798
|
+
model,
|
|
13799
|
+
generatePromptPath,
|
|
13800
|
+
existingContentfulEntitiesHashInputs,
|
|
13801
|
+
generatePrompt
|
|
13802
|
+
);
|
|
13803
|
+
if (opts.cacheStatus) {
|
|
13804
|
+
const cacheEnabled = opts.cache !== false && process.env.EDS_NO_CACHE !== "1";
|
|
13805
|
+
const cachedComponents = cacheEnabled ? allComponents.flatMap((component) => {
|
|
13806
|
+
const resolution = resolveComponentCache(db, component, promptHash, allowedComponentNames2);
|
|
13807
|
+
return resolution ? [{ component, resolution }] : [];
|
|
13808
|
+
}) : [];
|
|
13809
|
+
if (cacheEnabled && opts.restoreCache) {
|
|
13810
|
+
const restorations = [];
|
|
13811
|
+
const rekeyed = [];
|
|
13812
|
+
const componentStatus = db.prepare(
|
|
13813
|
+
"SELECT status FROM raw_components WHERE session_id = ? AND component_id = ?"
|
|
13814
|
+
);
|
|
13815
|
+
for (const { component, resolution } of cachedComponents) {
|
|
13816
|
+
const current = componentStatus.get(sessionId2, component.component_id);
|
|
13817
|
+
if (current?.status === "generated") continue;
|
|
13818
|
+
renameEmptySlots(db, sessionId2, component.component_id, component.name, component.slots.length);
|
|
13819
|
+
restorations.push({
|
|
13820
|
+
sourceSessionId: resolution.entry.sourceSessionId,
|
|
13821
|
+
targetSessionId: sessionId2,
|
|
13822
|
+
componentId: component.component_id
|
|
13823
|
+
});
|
|
13824
|
+
rekeyed.push({ component, cached: resolution.entry });
|
|
13825
|
+
}
|
|
13826
|
+
copyComponentsFromCache(db, restorations, { allowedComponentNames: allowedComponentNames2 });
|
|
13827
|
+
storeCaches(
|
|
13828
|
+
db,
|
|
13829
|
+
rekeyed.map(({ component, cached }) => ({
|
|
13830
|
+
inputHash: hashComponentShape(normalizeComponentForCache(component)),
|
|
13831
|
+
entityType: "component",
|
|
13832
|
+
entityId: component.component_id,
|
|
13833
|
+
sourceSessionId: cached.sourceSessionId,
|
|
13834
|
+
humanEdited: cached.humanEdited,
|
|
13835
|
+
promptHash
|
|
13836
|
+
}))
|
|
13837
|
+
);
|
|
13838
|
+
}
|
|
13839
|
+
const fullyCached = cacheEnabled && cachedComponents.length === allComponents.length;
|
|
13840
|
+
process.stdout.write(`cache-status=${fullyCached ? "hit" : "miss"}
|
|
13841
|
+
`);
|
|
13842
|
+
process.stdout.write(
|
|
13843
|
+
`cache-components=${JSON.stringify(cachedComponents.map(({ component }) => component.name))}
|
|
13844
|
+
`
|
|
13845
|
+
);
|
|
13846
|
+
await exitWithAnalytics(0);
|
|
13847
|
+
return;
|
|
13848
|
+
}
|
|
13093
13849
|
componentResults = await runAllComponents(
|
|
13094
13850
|
{
|
|
13095
13851
|
agent,
|
|
@@ -13099,10 +13855,13 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
13099
13855
|
tokensInline,
|
|
13100
13856
|
tokenMapInline,
|
|
13101
13857
|
verbose,
|
|
13858
|
+
noCache: opts.cache === false || process.env.EDS_NO_CACHE === "1",
|
|
13102
13859
|
skillPathOverride: generatePromptPath,
|
|
13103
13860
|
skillContentOverride: generatePrompt,
|
|
13861
|
+
promptHash,
|
|
13104
13862
|
existingContentfulEntities,
|
|
13105
13863
|
existingTokensInline,
|
|
13864
|
+
precomputedCachedNames,
|
|
13106
13865
|
allowedComponentNames: allowedComponentNames2
|
|
13107
13866
|
},
|
|
13108
13867
|
allComponents
|
|
@@ -13111,7 +13870,8 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
13111
13870
|
db.close();
|
|
13112
13871
|
}
|
|
13113
13872
|
const failed = componentResults.filter((r) => r.failed);
|
|
13114
|
-
const
|
|
13873
|
+
const cachedResults = componentResults.filter((r) => r.cached);
|
|
13874
|
+
const generated = componentResults.filter((r) => !r.failed && !r.cached);
|
|
13115
13875
|
const allWarnings = componentResults.flatMap((r) => r.warnings.map((w) => ` ${r.componentName}: ${w}`));
|
|
13116
13876
|
if (allWarnings.length > 0) {
|
|
13117
13877
|
process.stderr.write(c.yellow("Warnings:") + "\n" + allWarnings.join("\n") + "\n");
|
|
@@ -13127,17 +13887,21 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
13127
13887
|
const totalExcluded = generated.reduce((s, r) => s + r.excluded, 0);
|
|
13128
13888
|
const totalRenamedSlots = componentResults.reduce((s, r) => s + r.renamedSlotsCount, 0);
|
|
13129
13889
|
const allOk = failed.length === 0;
|
|
13890
|
+
const cachedNote = cachedResults.length > 0 ? c.dim(` (${cachedResults.length} cached)`) : "";
|
|
13130
13891
|
process.stderr.write(
|
|
13131
|
-
(allOk ? c.green("\u2713") : c.yellow("\u26A0")) + ` ${generated.length}/${componentResults.length} components` + c.dim(` ${totalClassified} classified, ${totalExcluded} unattached`) + "\n"
|
|
13892
|
+
(allOk ? c.green("\u2713") : c.yellow("\u26A0")) + ` ${generated.length + cachedResults.length}/${componentResults.length} components` + cachedNote + c.dim(` ${totalClassified} classified, ${totalExcluded} unattached`) + "\n"
|
|
13132
13893
|
);
|
|
13133
13894
|
process.stdout.write(`renamed-slots: ${totalRenamedSlots}
|
|
13134
13895
|
`);
|
|
13135
|
-
if (generated.length === 0) {
|
|
13896
|
+
if (generated.length === 0 && cachedResults.length === 0) {
|
|
13136
13897
|
die(
|
|
13137
13898
|
`Error: all ${componentResults.length} component(s) failed to generate \u2014 see the per-component errors above.`
|
|
13138
13899
|
);
|
|
13139
13900
|
}
|
|
13140
13901
|
} else if (skill === "tokens") {
|
|
13902
|
+
const noCache = opts.cache === false || process.env.EDS_NO_CACHE === "1";
|
|
13903
|
+
const tokenInputContent = rawTokensInline ?? "";
|
|
13904
|
+
const tokenInputHash = hashTokenContent(tokenInputContent);
|
|
13141
13905
|
const db = openPipelineDb();
|
|
13142
13906
|
try {
|
|
13143
13907
|
let resolvedSessionId = opts.session;
|
|
@@ -13164,11 +13928,26 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
13164
13928
|
}
|
|
13165
13929
|
sessionId2 = resolvedSessionId;
|
|
13166
13930
|
await bindAnalyticsSessionId(resolvedSessionId);
|
|
13931
|
+
const tokenPromptHash = await hashPromptForSkill("tokens", agent, model);
|
|
13932
|
+
if (!noCache) {
|
|
13933
|
+
const tokenCached = lookupCache(db, tokenInputHash, "token_set", "__tokens__", tokenPromptHash);
|
|
13934
|
+
if (tokenCached) {
|
|
13935
|
+
copyTokensFromCache(db, tokenCached.sourceSessionId, resolvedSessionId);
|
|
13936
|
+
sessionId2 = resolvedSessionId;
|
|
13937
|
+
process.stderr.write(
|
|
13938
|
+
`Done: tokens reused from cache ${c.dim(`(source: ${tokenCached.sourceSessionId.slice(0, 12)})`)}
|
|
13939
|
+
`
|
|
13940
|
+
);
|
|
13941
|
+
db.close();
|
|
13942
|
+
await showGenerateView({ skill, agent, sessionId: sessionId2 ?? "" });
|
|
13943
|
+
return;
|
|
13944
|
+
}
|
|
13945
|
+
}
|
|
13167
13946
|
const prompt = await buildPrompt({
|
|
13168
13947
|
skill,
|
|
13169
13948
|
mode: "autonomous",
|
|
13170
13949
|
rawTokensInline,
|
|
13171
|
-
rawTokensFilename: opts.rawTokens ?
|
|
13950
|
+
rawTokensFilename: opts.rawTokens ? resolve12(opts.rawTokens).split("/").pop() : void 0,
|
|
13172
13951
|
tokensInline,
|
|
13173
13952
|
tokenMapInline,
|
|
13174
13953
|
outDir: process.cwd()
|
|
@@ -13205,6 +13984,9 @@ ${tokenWarnings.map((w) => ` ${w}`).join("\n")}
|
|
|
13205
13984
|
`);
|
|
13206
13985
|
}
|
|
13207
13986
|
applyTokenToolCalls(db, resolvedSessionId, tokenCalls, []);
|
|
13987
|
+
if (!noCache) {
|
|
13988
|
+
storeCache(db, tokenInputHash, "token_set", "__tokens__", resolvedSessionId, false, tokenPromptHash);
|
|
13989
|
+
}
|
|
13208
13990
|
sessionId2 = resolvedSessionId;
|
|
13209
13991
|
const groupCount = tokenCalls.filter((tc) => tc.tool === "set_group").length;
|
|
13210
13992
|
process.stderr.write(`Done: ${tokenCount} tokens, ${groupCount} groups stored
|
|
@@ -13216,7 +13998,10 @@ ${tokenWarnings.map((w) => ` ${w}`).join("\n")}
|
|
|
13216
13998
|
await showGenerateView({ skill, agent, sessionId: sessionId2 ?? "" });
|
|
13217
13999
|
}
|
|
13218
14000
|
function addAgentFlags(cmd) {
|
|
13219
|
-
return addAgentModelOptions(cmd).option("--verbose", "Show full agent output including reasoning text").option("--dry-run", "Print the prompt without invoking the agent")
|
|
14001
|
+
return addAgentModelOptions(cmd).option("--verbose", "Show full agent output including reasoning text").option("--dry-run", "Print the prompt without invoking the agent").option(
|
|
14002
|
+
"--no-cache",
|
|
14003
|
+
"Bypass ALL fine-grained caches (extract, select, generate) and force AI re-run. Cache keys now factor in prompt content \u2014 changing the prompt file via --generate-prompt-path or --select-prompt-path will already bust the corresponding stage. Use --no-cache to force a full re-run."
|
|
14004
|
+
);
|
|
13220
14005
|
}
|
|
13221
14006
|
function registerInternalGenerateCommand(program) {
|
|
13222
14007
|
const generate = program.command("__generate", { hidden: true }).description("Internal import pipeline generation command");
|
|
@@ -13232,6 +14017,12 @@ function registerInternalGenerateCommand(program) {
|
|
|
13232
14017
|
"--existing-entities-path <path>",
|
|
13233
14018
|
"Path to the .existing-entities.json file written after 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."
|
|
13234
14019
|
);
|
|
14020
|
+
componentsCmd.option("--cache-status", "Check whether all selected component definitions are cached");
|
|
14021
|
+
componentsCmd.option("--restore-cache", "Restore cached component definitions into the current session");
|
|
14022
|
+
componentsCmd.option(
|
|
14023
|
+
"--cached-components <json>",
|
|
14024
|
+
"Component names already restored by a prior cache-status lookup; skip per-component cache lookup"
|
|
14025
|
+
);
|
|
13235
14026
|
addAgentFlags(componentsCmd).action(async (opts) => {
|
|
13236
14027
|
await runGenerateSkill("components", opts, opts.verbose ?? false);
|
|
13237
14028
|
});
|
|
@@ -13257,6 +14048,7 @@ var init_command = __esm({
|
|
|
13257
14048
|
init_agent_output();
|
|
13258
14049
|
init_GenerateView();
|
|
13259
14050
|
init_db();
|
|
14051
|
+
init_cache_keys();
|
|
13260
14052
|
init_read_existing_contentful_entities_from_session();
|
|
13261
14053
|
init_summarize_existing_contentful_entities();
|
|
13262
14054
|
init_resolve_session_id();
|
|
@@ -13972,7 +14764,7 @@ var init_user_agent = __esm({
|
|
|
13972
14764
|
// packages/experience-design-system-cli-legacy/src/apply/api-client.ts
|
|
13973
14765
|
import { parseCDFComponents } from "@contentful/experience-design-system-types";
|
|
13974
14766
|
function defaultSleep(delayMs) {
|
|
13975
|
-
return new Promise((
|
|
14767
|
+
return new Promise((resolve22) => setTimeout(resolve22, delayMs));
|
|
13976
14768
|
}
|
|
13977
14769
|
function isTransientStatus(status) {
|
|
13978
14770
|
return status >= 500 && status <= 599;
|
|
@@ -14362,7 +15154,7 @@ ${trimmed}`;
|
|
|
14362
15154
|
const progress = maxAttempts > 1 ? attempt / (maxAttempts - 1) : 0;
|
|
14363
15155
|
const baseDelay = intervalMs + (maxIntervalMs - intervalMs) * progress;
|
|
14364
15156
|
const jitter = Math.random() * baseDelay * 0.15;
|
|
14365
|
-
await new Promise((
|
|
15157
|
+
await new Promise((resolve22) => setTimeout(resolve22, baseDelay + jitter));
|
|
14366
15158
|
}
|
|
14367
15159
|
}
|
|
14368
15160
|
throw new Error(`Operation ${operationId} timed out after ${maxAttempts} attempts`);
|
|
@@ -15172,7 +15964,7 @@ var init_terminal_capabilities = __esm({
|
|
|
15172
15964
|
|
|
15173
15965
|
// packages/experience-design-system-cli-legacy/src/apply/command.ts
|
|
15174
15966
|
import { createElement as createElement2 } from "react";
|
|
15175
|
-
import { readFile as
|
|
15967
|
+
import { readFile as readFile13, readdir as readdir2, stat as stat2 } from "node:fs/promises";
|
|
15176
15968
|
import { join as join16 } from "node:path";
|
|
15177
15969
|
import {
|
|
15178
15970
|
validateCDF,
|
|
@@ -15193,7 +15985,7 @@ function dieWithApiError(error) {
|
|
|
15193
15985
|
async function readJsonFile(flag, p) {
|
|
15194
15986
|
let text;
|
|
15195
15987
|
try {
|
|
15196
|
-
text = await
|
|
15988
|
+
text = await readFile13(p, "utf8");
|
|
15197
15989
|
} catch {
|
|
15198
15990
|
return await die2(`Error: file not found: ${p} (from ${flag})`);
|
|
15199
15991
|
}
|
|
@@ -15247,7 +16039,7 @@ async function readTokensFromPath(flag, p) {
|
|
|
15247
16039
|
for (const file of files.sort()) {
|
|
15248
16040
|
let text;
|
|
15249
16041
|
try {
|
|
15250
|
-
text = await
|
|
16042
|
+
text = await readFile13(file, "utf8");
|
|
15251
16043
|
} catch {
|
|
15252
16044
|
continue;
|
|
15253
16045
|
}
|
|
@@ -15616,11 +16408,11 @@ var init_command2 = __esm({
|
|
|
15616
16408
|
});
|
|
15617
16409
|
|
|
15618
16410
|
// packages/experience-design-system-cli-legacy/src/print/validate/validators/read-json-file.ts
|
|
15619
|
-
import { readFile as
|
|
16411
|
+
import { readFile as readFile14 } from "node:fs/promises";
|
|
15620
16412
|
async function readJsonFile2(filePath) {
|
|
15621
16413
|
let content;
|
|
15622
16414
|
try {
|
|
15623
|
-
content = await
|
|
16415
|
+
content = await readFile14(filePath, "utf-8");
|
|
15624
16416
|
} catch (err) {
|
|
15625
16417
|
return {
|
|
15626
16418
|
ok: false,
|
|
@@ -16031,7 +16823,7 @@ var init_ValidateView = __esm({
|
|
|
16031
16823
|
// packages/experience-design-system-cli-legacy/src/print/command.ts
|
|
16032
16824
|
import { createElement as createElement3 } from "react";
|
|
16033
16825
|
import { access as access3, mkdir as mkdir3, stat as stat3, writeFile as writeFile3 } from "node:fs/promises";
|
|
16034
|
-
import { basename as basename5, resolve as
|
|
16826
|
+
import { basename as basename5, resolve as resolve13 } from "node:path";
|
|
16035
16827
|
import { CDF_SCHEMA_URL } from "@contentful/experience-design-system-types";
|
|
16036
16828
|
async function die3(message) {
|
|
16037
16829
|
process.stderr.write(`${message}
|
|
@@ -16098,7 +16890,7 @@ function registerPrintCommand(program) {
|
|
|
16098
16890
|
"--allow-empty",
|
|
16099
16891
|
"Write an empty-but-present CDF file when no components are accepted (a subsequent push then removes ALL components from the target space). Without this, an empty accepted set is an error."
|
|
16100
16892
|
).action(async (opts) => {
|
|
16101
|
-
const outPath =
|
|
16893
|
+
const outPath = resolve13(opts.out);
|
|
16102
16894
|
await assertOutIsNotDirectory(outPath);
|
|
16103
16895
|
const sessionId2 = await resolveSession(opts.session, "generate components");
|
|
16104
16896
|
await bindAnalyticsSessionId(sessionId2);
|
|
@@ -16146,7 +16938,7 @@ function registerPrintCommand(program) {
|
|
|
16146
16938
|
`
|
|
16147
16939
|
);
|
|
16148
16940
|
}
|
|
16149
|
-
await mkdir3(
|
|
16941
|
+
await mkdir3(resolve13(outPath, ".."), { recursive: true });
|
|
16150
16942
|
await writeFile3(outPath, `${JSON.stringify(cdfObj, null, 2)}
|
|
16151
16943
|
`);
|
|
16152
16944
|
process.stdout.write(
|
|
@@ -16155,7 +16947,7 @@ function registerPrintCommand(program) {
|
|
|
16155
16947
|
);
|
|
16156
16948
|
});
|
|
16157
16949
|
print.command("tokens").description("Write generated tokens to a DTCG JSON file").option("--session <id>", "Session ID to print from (default: most recent generate tokens session)").option("--out <path>", "Output file path", "tokens.json").action(async (opts) => {
|
|
16158
|
-
const outPath =
|
|
16950
|
+
const outPath = resolve13(opts.out);
|
|
16159
16951
|
await assertOutIsNotDirectory(outPath);
|
|
16160
16952
|
const sessionId2 = await resolveSession(opts.session, "generate tokens");
|
|
16161
16953
|
await bindAnalyticsSessionId(sessionId2);
|
|
@@ -16170,7 +16962,7 @@ function registerPrintCommand(program) {
|
|
|
16170
16962
|
await die3(`Error: no generated tokens in session '${sessionId2}'. Run generate tokens first.`);
|
|
16171
16963
|
}
|
|
16172
16964
|
const tree = rebuildDTCGTree(result.groups, result.tokens);
|
|
16173
|
-
await mkdir3(
|
|
16965
|
+
await mkdir3(resolve13(outPath, ".."), { recursive: true });
|
|
16174
16966
|
await writeFile3(outPath, `${JSON.stringify(tree, null, 2)}
|
|
16175
16967
|
`);
|
|
16176
16968
|
process.stdout.write(
|
|
@@ -16319,7 +17111,7 @@ function MapTokensView({ result, onExit }) {
|
|
|
16319
17111
|
const timer = setTimeout(onExit, 100);
|
|
16320
17112
|
return () => clearTimeout(timer);
|
|
16321
17113
|
}, [onExit]);
|
|
16322
|
-
const summary = `${result.applied} mapping${result.applied === 1 ? "" : "s"} applied`;
|
|
17114
|
+
const summary = result.cached ? "reused from cache" : `${result.applied} mapping${result.applied === 1 ? "" : "s"} applied`;
|
|
16323
17115
|
return /* @__PURE__ */ jsx8(
|
|
16324
17116
|
CommandCompletionView,
|
|
16325
17117
|
{
|
|
@@ -16453,8 +17245,8 @@ var init_resolve_defaults = __esm({
|
|
|
16453
17245
|
|
|
16454
17246
|
// packages/experience-design-system-cli-legacy/src/map-tokens/command.ts
|
|
16455
17247
|
import { createElement as createElement4 } from "react";
|
|
16456
|
-
import { readFile as
|
|
16457
|
-
import { resolve as
|
|
17248
|
+
import { readFile as readFile15 } from "node:fs/promises";
|
|
17249
|
+
import { resolve as resolve14 } from "node:path";
|
|
16458
17250
|
async function renderResult(result) {
|
|
16459
17251
|
if (process.stdout.isTTY) {
|
|
16460
17252
|
const { waitUntilExit } = renderWithGoodbye(
|
|
@@ -16462,13 +17254,12 @@ async function renderResult(result) {
|
|
|
16462
17254
|
);
|
|
16463
17255
|
await waitUntilExit();
|
|
16464
17256
|
} else {
|
|
16465
|
-
|
|
16466
|
-
|
|
17257
|
+
const summary = result.cached ? "cached" : `${result.applied} mapping(s) applied`;
|
|
17258
|
+
process.stdout.write(`map tokens complete
|
|
16467
17259
|
agent: ${result.agent}
|
|
16468
17260
|
session=${result.sessionId}
|
|
16469
|
-
${
|
|
16470
|
-
`
|
|
16471
|
-
);
|
|
17261
|
+
${summary}
|
|
17262
|
+
`);
|
|
16472
17263
|
await exitWithAnalytics(0);
|
|
16473
17264
|
}
|
|
16474
17265
|
}
|
|
@@ -16490,7 +17281,7 @@ async function runMapTokens(opts) {
|
|
|
16490
17281
|
let mapPromptPath;
|
|
16491
17282
|
if (mapPromptOverride?.kind === "text") mapPromptText = mapPromptOverride.value;
|
|
16492
17283
|
if (mapPromptOverride?.kind === "path") {
|
|
16493
|
-
mapPromptPath =
|
|
17284
|
+
mapPromptPath = resolve14(mapPromptOverride.value);
|
|
16494
17285
|
try {
|
|
16495
17286
|
await resolvePromptOverride(mapPromptOverride);
|
|
16496
17287
|
} catch (error) {
|
|
@@ -16510,7 +17301,7 @@ async function runMapTokens(opts) {
|
|
|
16510
17301
|
const knownTokenPaths = new Set(tokenLeaves.map((t) => t.path));
|
|
16511
17302
|
const tokenMapDiagnostics = [];
|
|
16512
17303
|
if (opts.tokenMap) {
|
|
16513
|
-
const fileMappings = JSON.parse(await
|
|
17304
|
+
const fileMappings = JSON.parse(await readFile15(opts.tokenMap, "utf8"));
|
|
16514
17305
|
const validMappings = {};
|
|
16515
17306
|
for (const [rawName, path] of Object.entries(fileMappings)) {
|
|
16516
17307
|
if (knownTokenPaths.has(path)) {
|
|
@@ -16588,7 +17379,7 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
|
|
|
16588
17379
|
let existingTokensInline;
|
|
16589
17380
|
if (opts.existingEntitiesPath) {
|
|
16590
17381
|
const existingContentfulEntities = await readExistingContentfulEntitiesFromSession(
|
|
16591
|
-
|
|
17382
|
+
resolve14(opts.existingEntitiesPath)
|
|
16592
17383
|
);
|
|
16593
17384
|
if (existingContentfulEntities) {
|
|
16594
17385
|
existingTokensInline = JSON.stringify(summarizeForMapTokens(existingContentfulEntities));
|
|
@@ -16623,10 +17414,30 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
|
|
|
16623
17414
|
skipAgent: "true"
|
|
16624
17415
|
});
|
|
16625
17416
|
updateStep(db, stepId2, "complete", { applied: "0", skipAgent: "true" });
|
|
16626
|
-
await renderResult({ agent: resultAgent, sessionId: sessionId2, applied: 0 });
|
|
17417
|
+
await renderResult({ agent: resultAgent, sessionId: sessionId2, applied: 0, cached: false });
|
|
16627
17418
|
return;
|
|
16628
17419
|
}
|
|
16629
17420
|
const agent = configuredAgent;
|
|
17421
|
+
const noCache = opts.cache === false || process.env.EDS_NO_CACHE === "1";
|
|
17422
|
+
const promptHash = await hashPromptForSkill(
|
|
17423
|
+
"map-tokens",
|
|
17424
|
+
agent,
|
|
17425
|
+
model,
|
|
17426
|
+
void 0,
|
|
17427
|
+
existingTokensInline ? [hashContent(existingTokensInline)] : [],
|
|
17428
|
+
mapPromptText
|
|
17429
|
+
);
|
|
17430
|
+
const inputHash = computeMapTokensInputHash(db, sessionId2, componentSourceRefs);
|
|
17431
|
+
if (!noCache) {
|
|
17432
|
+
const cached = lookupCache(db, inputHash, "token_mapping", "__map_tokens__", promptHash);
|
|
17433
|
+
if (cached) {
|
|
17434
|
+
const appliedFromCache = copyMapTokensFromCache(db, cached.sourceSessionId, sessionId2);
|
|
17435
|
+
const stepId2 = createStep(db, sessionId2, "map tokens", { agent, model: model ?? "" });
|
|
17436
|
+
updateStep(db, stepId2, "complete", { cached: "true", applied: String(appliedFromCache) });
|
|
17437
|
+
await renderResult({ agent, sessionId: sessionId2, applied: appliedFromCache, cached: true });
|
|
17438
|
+
return;
|
|
17439
|
+
}
|
|
17440
|
+
}
|
|
16630
17441
|
const binary = resolveAgentBinary(agent);
|
|
16631
17442
|
if (!await assertBinaryInPath(binary)) {
|
|
16632
17443
|
die(
|
|
@@ -16646,20 +17457,23 @@ Install it, choose another agent with --agent, or use --print-prompt to run the
|
|
|
16646
17457
|
}
|
|
16647
17458
|
const { calls, warnings: parseWarnings } = parseMapTokenPropToolCallLines(result.stdout);
|
|
16648
17459
|
const { applied, warnings } = applyMapTokenPropCalls(db, sessionId2, calls, parseWarnings);
|
|
17460
|
+
if (!noCache) {
|
|
17461
|
+
storeCache(db, inputHash, "token_mapping", "__map_tokens__", sessionId2, false, promptHash);
|
|
17462
|
+
}
|
|
16649
17463
|
updateStep(db, stepId, "complete", { applied: String(applied), warnings: String(warnings.length) });
|
|
16650
17464
|
if (warnings.length > 0) {
|
|
16651
17465
|
process.stderr.write(`Warnings:
|
|
16652
17466
|
${warnings.map((w) => ` ${w}`).join("\n")}
|
|
16653
17467
|
`);
|
|
16654
17468
|
}
|
|
16655
|
-
await renderResult({ agent, sessionId: sessionId2, applied });
|
|
17469
|
+
await renderResult({ agent, sessionId: sessionId2, applied, cached: false });
|
|
16656
17470
|
} finally {
|
|
16657
17471
|
db.close();
|
|
16658
17472
|
}
|
|
16659
17473
|
}
|
|
16660
17474
|
function registerMapTokensCommand(program) {
|
|
16661
17475
|
const map = program.command("map", { hidden: true }).description("Suggest token restrictions for generated design-token props");
|
|
16662
|
-
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(
|
|
17476
|
+
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(
|
|
16663
17477
|
"--prompt <stage=value>",
|
|
16664
17478
|
"Override a stage prompt (repeatable). Used here for the map-tokens stage.",
|
|
16665
17479
|
(v, acc) => [...acc, v],
|
|
@@ -16679,6 +17493,7 @@ var init_command4 = __esm({
|
|
|
16679
17493
|
init_render_with_goodbye();
|
|
16680
17494
|
init_src();
|
|
16681
17495
|
init_db();
|
|
17496
|
+
init_cache_keys();
|
|
16682
17497
|
init_read_existing_contentful_entities_from_session();
|
|
16683
17498
|
init_summarize_existing_contentful_entities();
|
|
16684
17499
|
init_command3();
|
|
@@ -16695,7 +17510,7 @@ var init_command4 = __esm({
|
|
|
16695
17510
|
});
|
|
16696
17511
|
|
|
16697
17512
|
// packages/experience-design-system-cli-legacy/src/import/path-utils.ts
|
|
16698
|
-
import { resolve as
|
|
17513
|
+
import { resolve as resolve15 } from "node:path";
|
|
16699
17514
|
import { homedir as homedir5 } from "node:os";
|
|
16700
17515
|
function expandTilde(input) {
|
|
16701
17516
|
if (input === "~" || input.startsWith("~/") || input.startsWith("~\\")) {
|
|
@@ -16709,7 +17524,7 @@ function normalizePath(input) {
|
|
|
16709
17524
|
p = p.slice(1, -1);
|
|
16710
17525
|
}
|
|
16711
17526
|
p = expandTilde(p);
|
|
16712
|
-
return
|
|
17527
|
+
return resolve15(p);
|
|
16713
17528
|
}
|
|
16714
17529
|
var init_path_utils = __esm({
|
|
16715
17530
|
"packages/experience-design-system-cli-legacy/src/import/path-utils.ts"() {
|
|
@@ -16934,7 +17749,7 @@ var init_save_path_resolver = __esm({
|
|
|
16934
17749
|
});
|
|
16935
17750
|
|
|
16936
17751
|
// packages/experience-design-system-cli-legacy/src/runs/store.ts
|
|
16937
|
-
import { readFile as
|
|
17752
|
+
import { readFile as readFile16, writeFile as writeFile4, mkdir as mkdir4, rename } from "node:fs/promises";
|
|
16938
17753
|
import { join as join20 } from "node:path";
|
|
16939
17754
|
import { homedir as homedir6 } from "node:os";
|
|
16940
17755
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
@@ -16974,7 +17789,7 @@ function migrateRecord(rec) {
|
|
|
16974
17789
|
}
|
|
16975
17790
|
async function readFileMaybe() {
|
|
16976
17791
|
try {
|
|
16977
|
-
const raw = await
|
|
17792
|
+
const raw = await readFile16(RUNS_PATH, "utf8");
|
|
16978
17793
|
const parsed = JSON.parse(raw);
|
|
16979
17794
|
if (!READABLE_VERSIONS.has(parsed.version)) {
|
|
16980
17795
|
throw new Error(
|
|
@@ -17038,15 +17853,15 @@ var init_store = __esm({
|
|
|
17038
17853
|
});
|
|
17039
17854
|
|
|
17040
17855
|
// packages/experience-design-system-cli-legacy/src/runs/fingerprint.ts
|
|
17041
|
-
import { createHash as
|
|
17042
|
-
import { readFile as
|
|
17043
|
-
import { resolve as
|
|
17856
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
17857
|
+
import { readFile as readFile17, stat as stat4 } from "node:fs/promises";
|
|
17858
|
+
import { resolve as resolve16 } from "node:path";
|
|
17044
17859
|
function rowField(row, key) {
|
|
17045
17860
|
const v = row[key];
|
|
17046
17861
|
return typeof v === "string" ? v : null;
|
|
17047
17862
|
}
|
|
17048
17863
|
function sha256Hex(buf) {
|
|
17049
|
-
return
|
|
17864
|
+
return createHash6("sha256").update(buf).digest("hex");
|
|
17050
17865
|
}
|
|
17051
17866
|
async function buildSourceFingerprint(opts) {
|
|
17052
17867
|
const rows = opts.db.prepare("SELECT name, source_path FROM raw_components WHERE session_id = ?").all(opts.extractSessionId);
|
|
@@ -17056,7 +17871,7 @@ async function buildSourceFingerprint(opts) {
|
|
|
17056
17871
|
const sourcePath = rowField(row, "source_path");
|
|
17057
17872
|
const name = rowField(row, "name");
|
|
17058
17873
|
if (!sourcePath) continue;
|
|
17059
|
-
const abs =
|
|
17874
|
+
const abs = resolve16(sourcePath);
|
|
17060
17875
|
if (seen.has(abs)) continue;
|
|
17061
17876
|
seen.add(abs);
|
|
17062
17877
|
try {
|
|
@@ -17071,10 +17886,10 @@ async function buildSourceFingerprint(opts) {
|
|
|
17071
17886
|
let rawTokensMtime = null;
|
|
17072
17887
|
let rawTokensContentHash = null;
|
|
17073
17888
|
if (opts.rawTokensPath) {
|
|
17074
|
-
const abs =
|
|
17889
|
+
const abs = resolve16(opts.rawTokensPath);
|
|
17075
17890
|
rawTokensPath = abs;
|
|
17076
17891
|
try {
|
|
17077
|
-
const [st, buf] = await Promise.all([stat4(abs),
|
|
17892
|
+
const [st, buf] = await Promise.all([stat4(abs), readFile17(abs)]);
|
|
17078
17893
|
rawTokensMtime = st.mtime.toISOString();
|
|
17079
17894
|
rawTokensContentHash = sha256Hex(buf);
|
|
17080
17895
|
} catch {
|
|
@@ -18829,11 +19644,11 @@ var init_slot_graph = __esm({
|
|
|
18829
19644
|
});
|
|
18830
19645
|
|
|
18831
19646
|
// packages/experience-design-system-cli-legacy/src/analyze/select/parser.ts
|
|
18832
|
-
import { createHash as
|
|
19647
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
18833
19648
|
import { access as access5 } from "node:fs/promises";
|
|
18834
|
-
import { isAbsolute, relative, resolve as
|
|
19649
|
+
import { isAbsolute, relative, resolve as resolve17 } from "node:path";
|
|
18835
19650
|
function createComponentId(name, resolvedSourcePath) {
|
|
18836
|
-
const sourceHash =
|
|
19651
|
+
const sourceHash = createHash7("sha256").update(`${name}:${resolvedSourcePath}`).digest("hex").slice(0, 12);
|
|
18837
19652
|
return `${name}-${sourceHash}`;
|
|
18838
19653
|
}
|
|
18839
19654
|
async function resolveComponentSourcePath(source, reviewRoot) {
|
|
@@ -18845,7 +19660,7 @@ async function resolveComponentSourcePath(source, reviewRoot) {
|
|
|
18845
19660
|
throw new Error(`Unable to access component source at ${source}`);
|
|
18846
19661
|
}
|
|
18847
19662
|
}
|
|
18848
|
-
const candidate =
|
|
19663
|
+
const candidate = resolve17(reviewRoot, source);
|
|
18849
19664
|
const relativeToRoot = relative(reviewRoot, candidate);
|
|
18850
19665
|
if (relativeToRoot.startsWith("..") || relativeToRoot === ".." || isAbsolute(relativeToRoot)) {
|
|
18851
19666
|
throw new Error(
|
|
@@ -18860,7 +19675,7 @@ async function resolveComponentSourcePath(source, reviewRoot) {
|
|
|
18860
19675
|
}
|
|
18861
19676
|
}
|
|
18862
19677
|
async function loadReviewInput(components, options = {}) {
|
|
18863
|
-
const reviewRoot =
|
|
19678
|
+
const reviewRoot = resolve17(options.reviewRoot ?? process.cwd());
|
|
18864
19679
|
const records = await Promise.all(
|
|
18865
19680
|
components.map(async (component) => {
|
|
18866
19681
|
let resolvedSourcePath;
|
|
@@ -18891,7 +19706,7 @@ var init_parser = __esm({
|
|
|
18891
19706
|
});
|
|
18892
19707
|
|
|
18893
19708
|
// packages/experience-design-system-cli-legacy/src/analyze/select/command.ts
|
|
18894
|
-
import { access as access6, readFile as
|
|
19709
|
+
import { access as access6, readFile as readFile18 } from "node:fs/promises";
|
|
18895
19710
|
async function loadAndValidateForReview(sessionId2, projectRoot) {
|
|
18896
19711
|
const db = openPipelineDb();
|
|
18897
19712
|
let rawComponents;
|
|
@@ -18909,7 +19724,7 @@ async function patchReviewStateWithValidationErrors(sessionId2, errors, opts = {
|
|
|
18909
19724
|
let snapshot;
|
|
18910
19725
|
try {
|
|
18911
19726
|
await access6(paths.statePath);
|
|
18912
|
-
snapshot = JSON.parse(await
|
|
19727
|
+
snapshot = JSON.parse(await readFile18(paths.statePath, "utf8"));
|
|
18913
19728
|
} catch {
|
|
18914
19729
|
snapshot = await loadAndValidateForReview(sessionId2, void 0);
|
|
18915
19730
|
snapshot = await ensureRefineSession(sessionId2, artifactsRoot, snapshot);
|
|
@@ -18960,7 +19775,7 @@ async function rejectComponentsByName(sessionId2, names, opts = {}) {
|
|
|
18960
19775
|
const nameSet = new Set(names);
|
|
18961
19776
|
let snapshot;
|
|
18962
19777
|
try {
|
|
18963
|
-
snapshot = JSON.parse(await
|
|
19778
|
+
snapshot = JSON.parse(await readFile18(paths.statePath, "utf8"));
|
|
18964
19779
|
} catch {
|
|
18965
19780
|
return;
|
|
18966
19781
|
}
|
|
@@ -19059,9 +19874,9 @@ function spawnGenerateChild(opts) {
|
|
|
19059
19874
|
stderr += chunk;
|
|
19060
19875
|
opts.onStderr?.(chunk);
|
|
19061
19876
|
});
|
|
19062
|
-
const donePromise = new Promise((
|
|
19877
|
+
const donePromise = new Promise((resolve22) => {
|
|
19063
19878
|
child.on("close", (code, signal) => {
|
|
19064
|
-
|
|
19879
|
+
resolve22({
|
|
19065
19880
|
exitCode: code ?? 0,
|
|
19066
19881
|
signal: signal ?? null,
|
|
19067
19882
|
stdout,
|
|
@@ -19069,7 +19884,7 @@ function spawnGenerateChild(opts) {
|
|
|
19069
19884
|
});
|
|
19070
19885
|
});
|
|
19071
19886
|
child.on("error", (err) => {
|
|
19072
|
-
|
|
19887
|
+
resolve22({
|
|
19073
19888
|
exitCode: 1,
|
|
19074
19889
|
signal: null,
|
|
19075
19890
|
stdout,
|
|
@@ -27207,6 +28022,9 @@ function shouldGenerateAfterCredentialsValidated(opts) {
|
|
|
27207
28022
|
function shouldSkipFinalReviewAfterCredentials(state) {
|
|
27208
28023
|
return state.finalReviewPassed && state.generateSessionId != null;
|
|
27209
28024
|
}
|
|
28025
|
+
function resolveNoCacheForGenerate(opts) {
|
|
28026
|
+
return opts.cliNoCache;
|
|
28027
|
+
}
|
|
27210
28028
|
function shouldBypassPreview(state) {
|
|
27211
28029
|
return state.credentialsSkipped === true;
|
|
27212
28030
|
}
|
|
@@ -27233,43 +28051,70 @@ var init_wizard_state_transitions = __esm({
|
|
|
27233
28051
|
async function runSelectionAgent(options) {
|
|
27234
28052
|
const db = openPipelineDb();
|
|
27235
28053
|
let components;
|
|
28054
|
+
const cachedDecisions = /* @__PURE__ */ new Map();
|
|
28055
|
+
const cliVersion2 = await getCliCacheVersion();
|
|
28056
|
+
const promptHash = await hashPromptForSkill(
|
|
28057
|
+
"select",
|
|
28058
|
+
options.agent,
|
|
28059
|
+
options.model,
|
|
28060
|
+
options.promptPath,
|
|
28061
|
+
[SELECT_PAYLOAD_FORMAT],
|
|
28062
|
+
options.promptText
|
|
28063
|
+
);
|
|
27236
28064
|
try {
|
|
27237
28065
|
components = loadRawComponents(db, options.sessionId);
|
|
28066
|
+
if (!options.noCache) {
|
|
28067
|
+
for (const component of components) {
|
|
28068
|
+
const componentHash = hashComponentShape(component);
|
|
28069
|
+
const cached = lookupSelectCache(db, componentHash, promptHash, cliVersion2);
|
|
28070
|
+
if (cached) {
|
|
28071
|
+
cachedDecisions.set(component.name, {
|
|
28072
|
+
decision: cached.decision,
|
|
28073
|
+
reason: cached.reason
|
|
28074
|
+
});
|
|
28075
|
+
}
|
|
28076
|
+
}
|
|
28077
|
+
}
|
|
27238
28078
|
} finally {
|
|
27239
28079
|
db.close();
|
|
27240
28080
|
}
|
|
27241
28081
|
if (components.length === 0) return;
|
|
27242
|
-
const
|
|
27243
|
-
|
|
27244
|
-
|
|
27245
|
-
|
|
27246
|
-
|
|
27247
|
-
|
|
27248
|
-
|
|
27249
|
-
|
|
27250
|
-
|
|
27251
|
-
|
|
27252
|
-
|
|
27253
|
-
|
|
27254
|
-
|
|
27255
|
-
|
|
27256
|
-
|
|
27257
|
-
|
|
27258
|
-
|
|
27259
|
-
|
|
27260
|
-
|
|
27261
|
-
|
|
27262
|
-
|
|
27263
|
-
|
|
27264
|
-
|
|
27265
|
-
|
|
27266
|
-
|
|
27267
|
-
|
|
27268
|
-
|
|
27269
|
-
|
|
27270
|
-
|
|
28082
|
+
const componentsToRun = components.filter((component) => !cachedDecisions.has(component.name));
|
|
28083
|
+
let calls = [];
|
|
28084
|
+
if (componentsToRun.length > 0) {
|
|
28085
|
+
const invoker2 = createLocalCliAgentInvoker({
|
|
28086
|
+
onDebugEvent: (name, payload) => getDebugLogger().event("agent", name, payload)
|
|
28087
|
+
});
|
|
28088
|
+
const selectBuckets = bucketComponentsProps(componentsToRun);
|
|
28089
|
+
for (const assignment of selectBuckets) {
|
|
28090
|
+
getDebugLogger().event("analyze", "prop-buckets.select", { ...assignment });
|
|
28091
|
+
}
|
|
28092
|
+
const prompt = await buildPrompt({
|
|
28093
|
+
skill: "select",
|
|
28094
|
+
mode: "autonomous",
|
|
28095
|
+
rawComponentsInline: JSON.stringify(
|
|
28096
|
+
componentsToRun.map((component) => ({ ...component, props: component.props.map(stripPropProvenance) })),
|
|
28097
|
+
null,
|
|
28098
|
+
2
|
|
28099
|
+
),
|
|
28100
|
+
propBucketsInline: JSON.stringify(selectBuckets),
|
|
28101
|
+
outDir: process.cwd(),
|
|
28102
|
+
...options.promptText !== void 0 ? { skillContentOverride: options.promptText } : {},
|
|
28103
|
+
...options.promptText === void 0 && options.promptPath ? { skillPathOverride: options.promptPath } : {}
|
|
28104
|
+
});
|
|
28105
|
+
const { result } = await invokeAgentWithOutput(
|
|
28106
|
+
invoker2,
|
|
28107
|
+
{ agent: options.agent, model: options.model, prompt, timeoutMs: DEFAULT_TIMEOUT_MS4 },
|
|
28108
|
+
false
|
|
28109
|
+
);
|
|
28110
|
+
if (result.timedOut) throw new Error("selection agent timed out");
|
|
28111
|
+
if (result.exitCode !== 0) throw new Error(`selection agent exited with code ${result.exitCode}`);
|
|
28112
|
+
const parsed = parseSelectToolCallLines(result.stdout);
|
|
28113
|
+
for (const warning of parsed.warnings) process.stderr.write(`Warning: selection agent: ${warning}
|
|
27271
28114
|
`);
|
|
27272
|
-
|
|
28115
|
+
calls = parsed.calls;
|
|
28116
|
+
}
|
|
28117
|
+
const byName = new Map(calls.map((call) => [call.name, call]));
|
|
27273
28118
|
const writeDb = openPipelineDb();
|
|
27274
28119
|
try {
|
|
27275
28120
|
writeDb.exec("BEGIN");
|
|
@@ -27277,15 +28122,27 @@ async function runSelectionAgent(options) {
|
|
|
27277
28122
|
`UPDATE raw_components SET status = ?, reject_reason = ? WHERE session_id = ? AND component_id = ?`
|
|
27278
28123
|
);
|
|
27279
28124
|
for (const component of components) {
|
|
28125
|
+
const cached = cachedDecisions.get(component.name);
|
|
27280
28126
|
const call = byName.get(component.name);
|
|
27281
|
-
if (!call) continue;
|
|
27282
|
-
const rejected = call.tool === "reject_component";
|
|
28127
|
+
if (!cached && !call) continue;
|
|
28128
|
+
const rejected = cached ? cached.decision === "rejected" : call.tool === "reject_component";
|
|
28129
|
+
const reason = cached ? cached.reason : call.reason ?? null;
|
|
27283
28130
|
update.run(
|
|
27284
28131
|
rejected ? "rejected" : "accepted",
|
|
27285
|
-
rejected ?
|
|
28132
|
+
rejected ? reason : null,
|
|
27286
28133
|
options.sessionId,
|
|
27287
28134
|
component.component_id
|
|
27288
28135
|
);
|
|
28136
|
+
if (!cached) {
|
|
28137
|
+
storeSelectCache(
|
|
28138
|
+
writeDb,
|
|
28139
|
+
hashComponentShape(component),
|
|
28140
|
+
promptHash,
|
|
28141
|
+
cliVersion2,
|
|
28142
|
+
rejected ? "rejected" : "accepted",
|
|
28143
|
+
rejected ? reason : null
|
|
28144
|
+
);
|
|
28145
|
+
}
|
|
27289
28146
|
}
|
|
27290
28147
|
writeDb.exec("COMMIT");
|
|
27291
28148
|
} catch (error) {
|
|
@@ -27295,7 +28152,7 @@ async function runSelectionAgent(options) {
|
|
|
27295
28152
|
writeDb.close();
|
|
27296
28153
|
}
|
|
27297
28154
|
}
|
|
27298
|
-
var DEFAULT_TIMEOUT_MS4;
|
|
28155
|
+
var SELECT_PAYLOAD_FORMAT, DEFAULT_TIMEOUT_MS4;
|
|
27299
28156
|
var init_run_selection_agent = __esm({
|
|
27300
28157
|
"packages/experience-design-system-cli-legacy/src/import/tui/run-selection-agent.ts"() {
|
|
27301
28158
|
"use strict";
|
|
@@ -27304,6 +28161,8 @@ var init_run_selection_agent = __esm({
|
|
|
27304
28161
|
init_debug_logger();
|
|
27305
28162
|
init_agent_output();
|
|
27306
28163
|
init_db();
|
|
28164
|
+
init_cache_keys();
|
|
28165
|
+
SELECT_PAYLOAD_FORMAT = "prop-buckets-v1";
|
|
27307
28166
|
DEFAULT_TIMEOUT_MS4 = Number(process.env.EDS_AGENT_TIMEOUT_MS ?? 5 * 60 * 1e3);
|
|
27308
28167
|
}
|
|
27309
28168
|
});
|
|
@@ -27322,7 +28181,7 @@ __export(WizardApp_exports, {
|
|
|
27322
28181
|
});
|
|
27323
28182
|
import { useEffect as useEffect15, useRef as useRef10, useState as useState23 } from "react";
|
|
27324
28183
|
import { Box as Box42, Text as Text46 } from "ink";
|
|
27325
|
-
import { join as join23, resolve as
|
|
28184
|
+
import { join as join23, resolve as resolve18 } from "node:path";
|
|
27326
28185
|
import { appendFileSync as appendFileSync2, writeFileSync } from "node:fs";
|
|
27327
28186
|
import { access as access7, stat as stat5, writeFile as writeFile6 } from "node:fs/promises";
|
|
27328
28187
|
import { tmpdir } from "node:os";
|
|
@@ -27335,21 +28194,28 @@ function buildGenerateComponentsArgs(opts) {
|
|
|
27335
28194
|
if (opts.tokensPath) args.push("--tokens", opts.tokensPath);
|
|
27336
28195
|
if (opts.model) args.push("--model", opts.model);
|
|
27337
28196
|
if (opts.bedrock) args.push("--bedrock");
|
|
28197
|
+
if (opts.noCache) args.push("--no-cache");
|
|
27338
28198
|
if (opts.generatePromptPath) args.push("--generate-prompt-path", opts.generatePromptPath);
|
|
27339
28199
|
for (const prompt of opts.promptOverrides ?? []) args.push("--prompt", prompt);
|
|
27340
28200
|
if (opts.existingEntitiesPath) args.push("--existing-entities-path", opts.existingEntitiesPath);
|
|
28201
|
+
if (opts.restoreCache) args.push("--restore-cache");
|
|
28202
|
+
if (opts.cachedComponents && opts.cachedComponents.length > 0) {
|
|
28203
|
+
args.push("--cached-components", JSON.stringify(opts.cachedComponents));
|
|
28204
|
+
}
|
|
27341
28205
|
return args;
|
|
27342
28206
|
}
|
|
27343
28207
|
function buildGenerateTokensArgs(opts) {
|
|
27344
28208
|
const args = [findCliPath(), "__generate", "tokens", "--agent", opts.agent, "--raw-tokens", opts.rawTokensPath];
|
|
27345
28209
|
if (opts.model) args.push("--model", opts.model);
|
|
27346
28210
|
if (opts.bedrock) args.push("--bedrock");
|
|
28211
|
+
if (opts.noCache) args.push("--no-cache");
|
|
27347
28212
|
for (const prompt of opts.promptOverrides ?? []) args.push("--prompt", prompt);
|
|
27348
28213
|
return args;
|
|
27349
28214
|
}
|
|
27350
28215
|
function buildMapTokensArgs(opts) {
|
|
27351
28216
|
const args = ["map", "tokens", "--session", opts.sessionId, "--agent", opts.agent];
|
|
27352
28217
|
if (opts.model) args.push("--model", opts.model);
|
|
28218
|
+
if (opts.noCache) args.push("--no-cache");
|
|
27353
28219
|
if (opts.skipAgent) args.push("--skip-agent");
|
|
27354
28220
|
for (const prompt of opts.promptOverrides ?? []) args.push("--prompt", prompt);
|
|
27355
28221
|
if (opts.existingEntitiesPath) args.push("--existing-entities-path", opts.existingEntitiesPath);
|
|
@@ -27441,6 +28307,7 @@ function WizardApp({
|
|
|
27441
28307
|
initialProjectPath,
|
|
27442
28308
|
host,
|
|
27443
28309
|
promptOverrides,
|
|
28310
|
+
noCache = false,
|
|
27444
28311
|
livePreview = true,
|
|
27445
28312
|
generatePromptPath,
|
|
27446
28313
|
skipMapTokens = false,
|
|
@@ -27465,6 +28332,7 @@ function WizardApp({
|
|
|
27465
28332
|
});
|
|
27466
28333
|
const allowEmptyDeleteAllRef = useRef10(false);
|
|
27467
28334
|
const generateChildRef = useRef10(null);
|
|
28335
|
+
const generationCachePreflightRef = useRef10(null);
|
|
27468
28336
|
const selectionToReviewStartedAtRef = useRef10(null);
|
|
27469
28337
|
const credentialsValidationIdRef = useRef10(0);
|
|
27470
28338
|
const pendingCredentialValidationRef = useRef10(null);
|
|
@@ -27479,8 +28347,9 @@ function WizardApp({
|
|
|
27479
28347
|
const existingEntitiesPromiseRef = useRef10(null);
|
|
27480
28348
|
const generatePromiseRef = useRef10(null);
|
|
27481
28349
|
const rawTokensEntryReady = !!initialRawTokensPath;
|
|
28350
|
+
const effectiveNoCache = resolveNoCacheForGenerate({ cliNoCache: noCache });
|
|
27482
28351
|
const initialStepResolved = rawTokensEntryReady ? initialProjectPath ? "path-validation" : "credentials" : initialProjectPath ? "token-input" : "welcome";
|
|
27483
|
-
const initialOutDir = initialProjectPath ? join23(
|
|
28352
|
+
const initialOutDir = initialProjectPath ? join23(resolve18(initialProjectPath), ".contentful") : "";
|
|
27484
28353
|
const [state, setState] = useState23({
|
|
27485
28354
|
step: initialStepResolved,
|
|
27486
28355
|
agent: initialAgent ?? "claude",
|
|
@@ -27656,13 +28525,14 @@ If you are using AWS Bedrock, run:
|
|
|
27656
28525
|
if (!deferStep) update({ step: nextStep });
|
|
27657
28526
|
return true;
|
|
27658
28527
|
};
|
|
27659
|
-
const runGenerateTokens = async (rawTokensPath, outDir) => {
|
|
28528
|
+
const runGenerateTokens = async (rawTokensPath, outDir, forceRegenerate = false) => {
|
|
27660
28529
|
update({ tokenGenerationStatus: "running" });
|
|
27661
28530
|
const tokenArgs = buildGenerateTokensArgs({
|
|
27662
28531
|
rawTokensPath,
|
|
27663
28532
|
agent: state.agent,
|
|
27664
28533
|
...state.agentModel ? { model: state.agentModel } : {},
|
|
27665
28534
|
...state.bedrock ? { bedrock: true } : {},
|
|
28535
|
+
noCache: effectiveNoCache || forceRegenerate,
|
|
27666
28536
|
promptOverrides
|
|
27667
28537
|
});
|
|
27668
28538
|
const result = await runSpawnedCli(tokenArgs);
|
|
@@ -27711,6 +28581,7 @@ If you are using AWS Bedrock, run:
|
|
|
27711
28581
|
const timer = startWizardTimer("token-mapping", {
|
|
27712
28582
|
sessionId: sessionId2,
|
|
27713
28583
|
silent,
|
|
28584
|
+
noCache: effectiveNoCache,
|
|
27714
28585
|
skipAgent: skipMapTokens
|
|
27715
28586
|
});
|
|
27716
28587
|
let mappablePropCount = 0;
|
|
@@ -27719,7 +28590,7 @@ If you are using AWS Bedrock, run:
|
|
|
27719
28590
|
const db = openPipelineDb();
|
|
27720
28591
|
try {
|
|
27721
28592
|
if (state.tokenSessionId && state.tokenSessionId !== sessionId2) {
|
|
27722
|
-
|
|
28593
|
+
copyTokensFromCache(db, state.tokenSessionId, sessionId2);
|
|
27723
28594
|
} else if (!state.tokenSessionId && state.tokensPath) {
|
|
27724
28595
|
const tokens = await readTokensFromPath("tokens", state.tokensPath);
|
|
27725
28596
|
storeDtcgTokens(db, sessionId2, [], tokens);
|
|
@@ -27759,6 +28630,7 @@ If you are using AWS Bedrock, run:
|
|
|
27759
28630
|
sessionId: sessionId2,
|
|
27760
28631
|
agent: state.agent,
|
|
27761
28632
|
...state.agentModel ? { model: state.agentModel } : {},
|
|
28633
|
+
noCache: effectiveNoCache,
|
|
27762
28634
|
skipAgent: skipMapTokens,
|
|
27763
28635
|
promptOverrides,
|
|
27764
28636
|
...state.existingEntitiesPath ? { existingEntitiesPath: state.existingEntitiesPath } : {}
|
|
@@ -27838,7 +28710,7 @@ If you are using AWS Bedrock, run:
|
|
|
27838
28710
|
return promise;
|
|
27839
28711
|
};
|
|
27840
28712
|
const runExtract = async (projectPath, showProgress = true) => {
|
|
27841
|
-
const outDir = join23(
|
|
28713
|
+
const outDir = join23(resolve18(projectPath), ".contentful");
|
|
27842
28714
|
const existingEntitiesExpected = !state.credentialsSkipped && Boolean(state.spaceId && state.environmentId && state.cmaToken && projectPath);
|
|
27843
28715
|
update({
|
|
27844
28716
|
...showProgress ? { step: "extracting" } : {},
|
|
@@ -27853,6 +28725,10 @@ If you are using AWS Bedrock, run:
|
|
|
27853
28725
|
});
|
|
27854
28726
|
const existingEntitiesPromise = startExistingEntitiesFetch(projectPath, outDir);
|
|
27855
28727
|
const extractArgs = [findCliPath(), "__extract", "--project", projectPath];
|
|
28728
|
+
if (effectiveNoCache) extractArgs.push("--composition-refresh", "--no-cache");
|
|
28729
|
+
for (const p of promptOverrides ?? []) extractArgs.push("--prompt", p);
|
|
28730
|
+
if (state.agent) extractArgs.push("--agent", state.agent);
|
|
28731
|
+
if (state.bedrock) extractArgs.push("--bedrock");
|
|
27856
28732
|
let selectionPromptText;
|
|
27857
28733
|
let selectionPromptPath;
|
|
27858
28734
|
try {
|
|
@@ -27861,7 +28737,7 @@ If you are using AWS Bedrock, run:
|
|
|
27861
28737
|
const selectOverride = overrides.get("select");
|
|
27862
28738
|
if (selectOverride?.kind === "text") selectionPromptText = selectOverride.value;
|
|
27863
28739
|
if (selectOverride?.kind === "path") {
|
|
27864
|
-
selectionPromptPath =
|
|
28740
|
+
selectionPromptPath = resolve18(selectOverride.value);
|
|
27865
28741
|
await resolvePromptOverride(selectOverride);
|
|
27866
28742
|
}
|
|
27867
28743
|
} catch (error) {
|
|
@@ -27885,7 +28761,8 @@ If you are using AWS Bedrock, run:
|
|
|
27885
28761
|
agent: state.agent,
|
|
27886
28762
|
...state.agentModel ? { model: state.agentModel } : {},
|
|
27887
28763
|
...selectionPromptText !== void 0 ? { promptText: selectionPromptText } : {},
|
|
27888
|
-
...selectionPromptPath ? { promptPath: selectionPromptPath } : {}
|
|
28764
|
+
...selectionPromptPath ? { promptPath: selectionPromptPath } : {},
|
|
28765
|
+
noCache: effectiveNoCache
|
|
27889
28766
|
});
|
|
27890
28767
|
})().catch((error) => {
|
|
27891
28768
|
selectionError = error;
|
|
@@ -28030,17 +28907,136 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
|
|
|
28030
28907
|
generateProgress: null
|
|
28031
28908
|
}));
|
|
28032
28909
|
};
|
|
28033
|
-
const buildGenerateOptions = (extractSessionId, tokensPath, generatePromptPath2) => ({
|
|
28910
|
+
const buildGenerateOptions = (extractSessionId, tokensPath, generatePromptPath2, cachedComponents) => ({
|
|
28034
28911
|
sessionId: extractSessionId,
|
|
28035
28912
|
tokensPath,
|
|
28036
28913
|
agent: state.agent,
|
|
28037
28914
|
...state.agentModel ? { model: state.agentModel } : {},
|
|
28038
28915
|
...state.bedrock ? { bedrock: true } : {},
|
|
28916
|
+
noCache: effectiveNoCache,
|
|
28039
28917
|
...state.existingEntitiesPath ? { existingEntitiesPath: state.existingEntitiesPath } : {},
|
|
28040
28918
|
...generatePromptPath2 ? { generatePromptPath: generatePromptPath2 } : {},
|
|
28041
|
-
promptOverrides
|
|
28919
|
+
promptOverrides,
|
|
28920
|
+
...cachedComponents && cachedComponents.length > 0 ? { cachedComponents } : {}
|
|
28042
28921
|
});
|
|
28043
|
-
const buildGenerateArgs = (extractSessionId, tokensPath, generatePromptPath2) => buildGenerateProcessArgs(buildGenerateOptions(extractSessionId, tokensPath, generatePromptPath2));
|
|
28922
|
+
const buildGenerateArgs = (extractSessionId, tokensPath, generatePromptPath2, cachedComponents) => buildGenerateProcessArgs(buildGenerateOptions(extractSessionId, tokensPath, generatePromptPath2, cachedComponents));
|
|
28923
|
+
const buildGenerateCliArgs = (extractSessionId, tokensPath, generatePromptPath2, cachedComponents) => buildGenerateComponentsArgs(
|
|
28924
|
+
buildGenerateOptions(extractSessionId, tokensPath, generatePromptPath2, cachedComponents)
|
|
28925
|
+
);
|
|
28926
|
+
const checkGenerateCache = async (extractSessionId, tokensPath) => {
|
|
28927
|
+
const timer = startWizardTimer("generation-cache-status", {
|
|
28928
|
+
sessionId: extractSessionId,
|
|
28929
|
+
noCache: effectiveNoCache
|
|
28930
|
+
});
|
|
28931
|
+
if (effectiveNoCache) {
|
|
28932
|
+
finishWizardTimer("generation-cache-status", timer, { status: "skipped" });
|
|
28933
|
+
return false;
|
|
28934
|
+
}
|
|
28935
|
+
const result = await runCli([...buildGenerateCliArgs(extractSessionId, tokensPath), "--cache-status"]);
|
|
28936
|
+
const hit = result.exitCode === 0 && /^cache-status=hit$/m.test(result.stdout);
|
|
28937
|
+
finishWizardTimer("generation-cache-status", timer, {
|
|
28938
|
+
status: hit ? "hit" : "miss",
|
|
28939
|
+
exitCode: result.exitCode,
|
|
28940
|
+
...result.exitCode !== 0 ? { stderrTail: result.stderr.trim().slice(-500) } : {}
|
|
28941
|
+
});
|
|
28942
|
+
return hit;
|
|
28943
|
+
};
|
|
28944
|
+
const checkGenerateCacheComponents = async (extractSessionId, tokensPath, restoreCache = false) => {
|
|
28945
|
+
const timer = startWizardTimer("generation-cache-components", {
|
|
28946
|
+
sessionId: extractSessionId,
|
|
28947
|
+
restoreCache,
|
|
28948
|
+
noCache: effectiveNoCache
|
|
28949
|
+
});
|
|
28950
|
+
if (effectiveNoCache) {
|
|
28951
|
+
finishWizardTimer("generation-cache-components", timer, { status: "skipped" });
|
|
28952
|
+
return /* @__PURE__ */ new Set();
|
|
28953
|
+
}
|
|
28954
|
+
const args = [...buildGenerateCliArgs(extractSessionId, tokensPath), "--cache-status"];
|
|
28955
|
+
if (restoreCache) args.push("--restore-cache");
|
|
28956
|
+
const result = await runCli(args);
|
|
28957
|
+
if (result.exitCode !== 0) {
|
|
28958
|
+
finishWizardTimer("generation-cache-components", timer, {
|
|
28959
|
+
status: "error",
|
|
28960
|
+
exitCode: result.exitCode,
|
|
28961
|
+
stderrTail: result.stderr.trim().slice(-500)
|
|
28962
|
+
});
|
|
28963
|
+
return /* @__PURE__ */ new Set();
|
|
28964
|
+
}
|
|
28965
|
+
const line = /^cache-components=(.+)$/m.exec(result.stdout)?.[1];
|
|
28966
|
+
if (!line) {
|
|
28967
|
+
finishWizardTimer("generation-cache-components", timer, {
|
|
28968
|
+
status: "missing-output",
|
|
28969
|
+
exitCode: result.exitCode,
|
|
28970
|
+
cachedCount: 0
|
|
28971
|
+
});
|
|
28972
|
+
return /* @__PURE__ */ new Set();
|
|
28973
|
+
}
|
|
28974
|
+
try {
|
|
28975
|
+
const names = JSON.parse(line);
|
|
28976
|
+
const cachedNames = new Set(
|
|
28977
|
+
Array.isArray(names) ? names.filter((name) => typeof name === "string") : []
|
|
28978
|
+
);
|
|
28979
|
+
finishWizardTimer("generation-cache-components", timer, {
|
|
28980
|
+
status: "complete",
|
|
28981
|
+
exitCode: result.exitCode,
|
|
28982
|
+
cachedCount: cachedNames.size
|
|
28983
|
+
});
|
|
28984
|
+
return cachedNames;
|
|
28985
|
+
} catch {
|
|
28986
|
+
finishWizardTimer("generation-cache-components", timer, {
|
|
28987
|
+
status: "invalid-output",
|
|
28988
|
+
exitCode: result.exitCode,
|
|
28989
|
+
cachedCount: 0
|
|
28990
|
+
});
|
|
28991
|
+
return /* @__PURE__ */ new Set();
|
|
28992
|
+
}
|
|
28993
|
+
};
|
|
28994
|
+
useEffect15(() => {
|
|
28995
|
+
if (state.step !== "extracting" && state.step !== "scope-gate" || !state.extractSessionId || state.existingEntitiesStatus === "running" || state.existingEntitiesStatus === "idle" || state.selectionAgentStatus !== "complete" || state.compositionPhase !== "done" && state.compositionPhase !== "cache-hit" || state.rawTokensPath && state.tokenGenerationStatus !== "complete" || effectiveNoCache) {
|
|
28996
|
+
return;
|
|
28997
|
+
}
|
|
28998
|
+
const sessionId2 = state.extractSessionId;
|
|
28999
|
+
if (generationCachePreflightRef.current?.sessionId === sessionId2) return;
|
|
29000
|
+
const timer = startWizardTimer("generation-cache-preflight", { sessionId: sessionId2 });
|
|
29001
|
+
const db = openPipelineDb();
|
|
29002
|
+
let generatedNames = null;
|
|
29003
|
+
try {
|
|
29004
|
+
const rows = db.prepare("SELECT name, status FROM raw_components WHERE session_id = ?").all(sessionId2);
|
|
29005
|
+
if (rows.length > 0 && rows.every((row) => row.status === "generated")) {
|
|
29006
|
+
generatedNames = new Set(rows.map((row) => row.name));
|
|
29007
|
+
}
|
|
29008
|
+
} finally {
|
|
29009
|
+
db.close();
|
|
29010
|
+
}
|
|
29011
|
+
if (generatedNames) {
|
|
29012
|
+
generationCachePreflightRef.current = { sessionId: sessionId2, promise: Promise.resolve(generatedNames) };
|
|
29013
|
+
finishWizardTimer("generation-cache-preflight", timer, {
|
|
29014
|
+
status: "complete",
|
|
29015
|
+
source: "session-db",
|
|
29016
|
+
cachedCount: generatedNames.size
|
|
29017
|
+
});
|
|
29018
|
+
return;
|
|
29019
|
+
}
|
|
29020
|
+
const promise = checkGenerateCacheComponents(sessionId2, state.tokensPath, true);
|
|
29021
|
+
generationCachePreflightRef.current = { sessionId: sessionId2, promise };
|
|
29022
|
+
void promise.then((cachedNames) => {
|
|
29023
|
+
finishWizardTimer("generation-cache-preflight", timer, {
|
|
29024
|
+
status: "complete",
|
|
29025
|
+
source: "cache-status",
|
|
29026
|
+
cachedCount: cachedNames.size
|
|
29027
|
+
});
|
|
29028
|
+
});
|
|
29029
|
+
}, [
|
|
29030
|
+
state.step,
|
|
29031
|
+
state.extractSessionId,
|
|
29032
|
+
state.tokensPath,
|
|
29033
|
+
state.rawTokensPath,
|
|
29034
|
+
state.tokenGenerationStatus,
|
|
29035
|
+
state.selectionAgentStatus,
|
|
29036
|
+
state.compositionPhase,
|
|
29037
|
+
state.existingEntitiesStatus,
|
|
29038
|
+
state.existingEntitiesPath
|
|
29039
|
+
]);
|
|
28044
29040
|
const startGeneratePrefetch = (extractSessionId, tokensPath) => {
|
|
28045
29041
|
const args = buildGenerateArgs(extractSessionId, tokensPath);
|
|
28046
29042
|
let progressCursor = null;
|
|
@@ -28095,13 +29091,14 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
|
|
|
28095
29091
|
});
|
|
28096
29092
|
return donePromise;
|
|
28097
29093
|
};
|
|
28098
|
-
const runGenerate = async (extractSessionId, tokensPath, acceptedCount, suppressScreen = false) => {
|
|
29094
|
+
const runGenerate = async (extractSessionId, tokensPath, acceptedCount, suppressScreen = false, cachedComponents = []) => {
|
|
28099
29095
|
const timer = startWizardTimer("component-generation", {
|
|
28100
29096
|
sessionId: extractSessionId,
|
|
28101
29097
|
acceptedCount,
|
|
28102
|
-
suppressScreen
|
|
29098
|
+
suppressScreen,
|
|
29099
|
+
noCache: effectiveNoCache
|
|
28103
29100
|
});
|
|
28104
|
-
const args = buildGenerateArgs(extractSessionId, tokensPath, generatePromptPath);
|
|
29101
|
+
const args = buildGenerateArgs(extractSessionId, tokensPath, generatePromptPath, cachedComponents);
|
|
28105
29102
|
let progressCursor = state.generateProgress;
|
|
28106
29103
|
const { donePromise } = spawnGenerateChild({
|
|
28107
29104
|
command: "node",
|
|
@@ -28171,6 +29168,25 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
|
|
|
28171
29168
|
finishSelectionToReviewTimer("error");
|
|
28172
29169
|
}
|
|
28173
29170
|
};
|
|
29171
|
+
const finishCachedGeneration = async (sessionId2, acceptedCount) => {
|
|
29172
|
+
if (await runMapTokens2(sessionId2, true)) {
|
|
29173
|
+
finishSelectionToReviewTimer("cached");
|
|
29174
|
+
update(
|
|
29175
|
+
{
|
|
29176
|
+
acceptedCount,
|
|
29177
|
+
autoRejectedCount: 0,
|
|
29178
|
+
generateSessionId: sessionId2,
|
|
29179
|
+
generatedCount: acceptedCount,
|
|
29180
|
+
generateProgress: null,
|
|
29181
|
+
mapTokensStatus: "complete",
|
|
29182
|
+
step: "final-review"
|
|
29183
|
+
},
|
|
29184
|
+
{ clearScreen: false }
|
|
29185
|
+
);
|
|
29186
|
+
} else {
|
|
29187
|
+
finishSelectionToReviewTimer("error");
|
|
29188
|
+
}
|
|
29189
|
+
};
|
|
28174
29190
|
const advanceToPushFlow = (generatedAcceptedCount) => {
|
|
28175
29191
|
update({ generatedAcceptedCount });
|
|
28176
29192
|
void runSaveAndPush();
|
|
@@ -28355,8 +29371,14 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
|
|
|
28355
29371
|
}
|
|
28356
29372
|
}
|
|
28357
29373
|
if (await runAgentAuthCheck("generating", true)) {
|
|
28358
|
-
|
|
28359
|
-
|
|
29374
|
+
const cacheHit = await checkGenerateCache(sid, state.tokensPath);
|
|
29375
|
+
if (cacheHit) {
|
|
29376
|
+
update({ step: "generating" });
|
|
29377
|
+
void finishCachedGeneration(sid, state.acceptedCount);
|
|
29378
|
+
} else {
|
|
29379
|
+
update({ step: "generating" });
|
|
29380
|
+
void runGenerate(sid, state.tokensPath, state.acceptedCount);
|
|
29381
|
+
}
|
|
28360
29382
|
}
|
|
28361
29383
|
return;
|
|
28362
29384
|
}
|
|
@@ -28720,7 +29742,7 @@ If using a custom host configuration, make sure the space exists on that host.`
|
|
|
28720
29742
|
});
|
|
28721
29743
|
return { ok: false };
|
|
28722
29744
|
}
|
|
28723
|
-
await new Promise((
|
|
29745
|
+
await new Promise((resolve22) => setTimeout(resolve22, SAVE_CONFIRMATION_DELAY_MS));
|
|
28724
29746
|
update(nextStateAfterPrint({ skipGate: opts.skipGate, componentsPath }));
|
|
28725
29747
|
return { ok: true };
|
|
28726
29748
|
};
|
|
@@ -28797,6 +29819,12 @@ If using a custom host configuration, make sure the space exists on that host.`
|
|
|
28797
29819
|
tokenReuseChecked.current = true;
|
|
28798
29820
|
const tokenNextStep = state.projectPath ? "path-validation" : "credentials";
|
|
28799
29821
|
const existingTokensPath = join23(state.outDir, "tokens.json");
|
|
29822
|
+
if (effectiveNoCache) {
|
|
29823
|
+
tokenGenerationPromiseRef.current = runAgentAuthCheck(tokenNextStep).then(
|
|
29824
|
+
(ok2) => ok2 ? runGenerateTokens(state.rawTokensPath, state.outDir) : false
|
|
29825
|
+
);
|
|
29826
|
+
return;
|
|
29827
|
+
}
|
|
28800
29828
|
(async () => {
|
|
28801
29829
|
try {
|
|
28802
29830
|
await access7(existingTokensPath);
|
|
@@ -28880,7 +29908,7 @@ If using a custom host configuration, make sure the space exists on that host.`
|
|
|
28880
29908
|
const tokenNextStep = state.projectPath ? "path-validation" : "credentials";
|
|
28881
29909
|
update({ step: tokenNextStep });
|
|
28882
29910
|
if (await runAgentAuthCheck(tokenNextStep)) {
|
|
28883
|
-
tokenGenerationPromiseRef.current = runGenerateTokens(state.rawTokensPath, state.outDir);
|
|
29911
|
+
tokenGenerationPromiseRef.current = runGenerateTokens(state.rawTokensPath, state.outDir, true);
|
|
28884
29912
|
}
|
|
28885
29913
|
},
|
|
28886
29914
|
onQuit: () => process.exit(0)
|
|
@@ -28914,7 +29942,7 @@ If using a custom host configuration, make sure the space exists on that host.`
|
|
|
28914
29942
|
);
|
|
28915
29943
|
case "extracting": {
|
|
28916
29944
|
const ep = state.extractProgress;
|
|
28917
|
-
const compositionComplete = state.compositionPhase === "done";
|
|
29945
|
+
const compositionComplete = state.compositionPhase === "done" || state.compositionPhase === "cache-hit";
|
|
28918
29946
|
const tokenGenerationComplete = !state.rawTokensPath || state.tokenGenerationStatus === "complete";
|
|
28919
29947
|
const extractionTasksComplete = ep !== null && ep.totalFiles > 0 && compositionComplete && state.selectionAgentStatus === "complete" && tokenGenerationComplete && state.existingEntitiesStatus !== "running";
|
|
28920
29948
|
if (extractionTasksComplete) return null;
|
|
@@ -28929,7 +29957,7 @@ If using a custom host configuration, make sure the space exists on that host.`
|
|
|
28929
29957
|
extractDetail = "Scanning files...";
|
|
28930
29958
|
}
|
|
28931
29959
|
const selectionDetail = state.selectionAgentStatus === "complete" ? "Selection agent complete" : `Filtering component selection via ${state.agent}...`;
|
|
28932
|
-
const compositionDetail = compositionComplete ? "Composition mapping complete" : "Mapping composition
|
|
29960
|
+
const compositionDetail = state.compositionPhase === "cache-hit" ? "Composition mapping (cached)" : compositionComplete ? "Composition mapping complete" : state.compositionPhase?.startsWith("agent:") ? `Mapping composition via ${state.compositionPhase.slice("agent:".length)}...` : `Mapping composition via ${state.agent}...`;
|
|
28933
29961
|
return /* @__PURE__ */ jsx50(
|
|
28934
29962
|
RunningStep,
|
|
28935
29963
|
{
|
|
@@ -28979,6 +30007,29 @@ If using a custom host configuration, make sure the space exists on that host.`
|
|
|
28979
30007
|
acceptedCount: decisions.accepted.length,
|
|
28980
30008
|
rejectedCount: decisions.rejected.length
|
|
28981
30009
|
}) : null;
|
|
30010
|
+
const preflight = generationCachePreflightRef.current;
|
|
30011
|
+
const cachePromise = preflight?.sessionId === sessionId2 ? preflight.promise : checkGenerateCacheComponents(sessionId2, state.tokensPath, true);
|
|
30012
|
+
if (!preflight || preflight.sessionId !== sessionId2) {
|
|
30013
|
+
generationCachePreflightRef.current = { sessionId: sessionId2, promise: cachePromise };
|
|
30014
|
+
}
|
|
30015
|
+
const cacheWaitStartedAt = startWizardTimer("selection-cache-restoration-wait", {
|
|
30016
|
+
sessionId: sessionId2,
|
|
30017
|
+
preflight: Boolean(preflight?.sessionId === sessionId2)
|
|
30018
|
+
});
|
|
30019
|
+
try {
|
|
30020
|
+
const cachedNames = await cachePromise;
|
|
30021
|
+
finishWizardTimer("selection-cache-restoration-wait", cacheWaitStartedAt, {
|
|
30022
|
+
status: "complete",
|
|
30023
|
+
cachedCount: cachedNames.size
|
|
30024
|
+
});
|
|
30025
|
+
} catch (error) {
|
|
30026
|
+
finishWizardTimer("selection-cache-restoration-wait", cacheWaitStartedAt, {
|
|
30027
|
+
status: "error",
|
|
30028
|
+
error: error instanceof Error ? error.message : String(error)
|
|
30029
|
+
});
|
|
30030
|
+
finishSelectionToReviewTimer("error");
|
|
30031
|
+
throw error;
|
|
30032
|
+
}
|
|
28982
30033
|
await runScopeGate({
|
|
28983
30034
|
sessionId: sessionId2,
|
|
28984
30035
|
decisions,
|
|
@@ -28987,12 +30038,35 @@ If using a custom host configuration, make sure the space exists on that host.`
|
|
|
28987
30038
|
if (shouldGenerateAfterScopeGate({ acceptedCount })) {
|
|
28988
30039
|
const authPromise = runAgentAuthCheck("generating", true);
|
|
28989
30040
|
if (await authPromise) {
|
|
28990
|
-
|
|
28991
|
-
|
|
28992
|
-
|
|
28993
|
-
|
|
30041
|
+
const comparisonStartedAt = startWizardTimer("generation-cache-set-comparison", {
|
|
30042
|
+
sessionId: sid,
|
|
30043
|
+
acceptedCount: decisions?.accepted.length ?? 0
|
|
30044
|
+
});
|
|
30045
|
+
let cachedNames = await cachePromise;
|
|
30046
|
+
const acceptedNames = decisions?.accepted ?? [];
|
|
30047
|
+
let cacheHit = !effectiveNoCache && acceptedNames.length > 0 && acceptedNames.every((name) => cachedNames.has(name));
|
|
30048
|
+
if (!cacheHit && !effectiveNoCache && acceptedNames.length > 0) {
|
|
30049
|
+
cachedNames = await checkGenerateCacheComponents(sid, state.tokensPath, true);
|
|
30050
|
+
cacheHit = acceptedNames.every((name) => cachedNames.has(name));
|
|
30051
|
+
}
|
|
30052
|
+
finishWizardTimer("generation-cache-set-comparison", comparisonStartedAt, {
|
|
30053
|
+
status: "complete",
|
|
30054
|
+
cacheHit,
|
|
30055
|
+
cachedCount: cachedNames.size,
|
|
30056
|
+
acceptedCount: acceptedNames.length
|
|
28994
30057
|
});
|
|
28995
|
-
|
|
30058
|
+
if (cacheHit) {
|
|
30059
|
+
void finishCachedGeneration(sid, acceptedCount);
|
|
30060
|
+
} else {
|
|
30061
|
+
const acceptedNameSet = new Set(acceptedNames);
|
|
30062
|
+
const restoredCachedNames = [...cachedNames].filter((name) => acceptedNameSet.has(name));
|
|
30063
|
+
update({
|
|
30064
|
+
step: "generating",
|
|
30065
|
+
generateProgress: null,
|
|
30066
|
+
acceptedCount
|
|
30067
|
+
});
|
|
30068
|
+
void runGenerate(sid, state.tokensPath, acceptedCount, false, restoredCachedNames);
|
|
30069
|
+
}
|
|
28996
30070
|
} else {
|
|
28997
30071
|
finishSelectionToReviewTimer("error");
|
|
28998
30072
|
}
|
|
@@ -29358,7 +30432,7 @@ function registerImportCommand(program) {
|
|
|
29358
30432
|
"Override a composition, selection, token, generation, or token-mapping prompt (repeatable). value is a file path or literal text, e.g. --prompt select=./p.md",
|
|
29359
30433
|
(v, acc) => [...acc, v],
|
|
29360
30434
|
[]
|
|
29361
|
-
).action(async (opts) => {
|
|
30435
|
+
).option("--no-cache", "Re-run all steps even if output already exists").action(async (opts) => {
|
|
29362
30436
|
const interactiveTerminalSupported = getInteractiveTerminalSupport().supported;
|
|
29363
30437
|
if (opts.tokens !== void 0) {
|
|
29364
30438
|
const { access: access9 } = await import("node:fs/promises");
|
|
@@ -29395,6 +30469,7 @@ function registerImportCommand(program) {
|
|
|
29395
30469
|
...resolvedModel ? { initialModel: resolvedModel } : {},
|
|
29396
30470
|
initialProjectPath: opts.project !== "." ? normalizePath(opts.project) : void 0,
|
|
29397
30471
|
...buildCompositionForwardingOptions(opts),
|
|
30472
|
+
noCache: opts.cache === false,
|
|
29398
30473
|
skipMapTokens: false,
|
|
29399
30474
|
livePreview: true,
|
|
29400
30475
|
generatePromptPath: creds.generatePromptPath,
|
|
@@ -29482,7 +30557,7 @@ async function pathExists3(path) {
|
|
|
29482
30557
|
return access8(path).then(() => true).catch(() => false);
|
|
29483
30558
|
}
|
|
29484
30559
|
function runSpawn(cmd, args, opts = {}) {
|
|
29485
|
-
return new Promise((
|
|
30560
|
+
return new Promise((resolve22) => {
|
|
29486
30561
|
const child = spawn6(cmd, args, {
|
|
29487
30562
|
cwd: opts.cwd,
|
|
29488
30563
|
env: opts.env ?? process.env,
|
|
@@ -29494,7 +30569,7 @@ function runSpawn(cmd, args, opts = {}) {
|
|
|
29494
30569
|
const settle = (result) => {
|
|
29495
30570
|
if (settled) return;
|
|
29496
30571
|
settled = true;
|
|
29497
|
-
|
|
30572
|
+
resolve22(result);
|
|
29498
30573
|
};
|
|
29499
30574
|
child.on("error", (err) => settle({ exitCode: 1, stdout: "", stderr: err.message }));
|
|
29500
30575
|
child.stdout.on("data", (d) => {
|
|
@@ -30695,13 +31770,13 @@ function PrerequisitesScreen({
|
|
|
30695
31770
|
const driver = {
|
|
30696
31771
|
...base,
|
|
30697
31772
|
emit: (event) => setEvents((current) => [...current, event]),
|
|
30698
|
-
confirm: (question, defaultYes = true) => new Promise((
|
|
31773
|
+
confirm: (question, defaultYes = true) => new Promise((resolve22) => {
|
|
30699
31774
|
setConfirm({
|
|
30700
31775
|
question,
|
|
30701
31776
|
defaultYes,
|
|
30702
31777
|
resolve: (answer) => {
|
|
30703
31778
|
setConfirm(null);
|
|
30704
|
-
|
|
31779
|
+
resolve22(answer);
|
|
30705
31780
|
}
|
|
30706
31781
|
});
|
|
30707
31782
|
})
|
|
@@ -30776,8 +31851,8 @@ function SetupScreen({
|
|
|
30776
31851
|
useEffect21(() => {
|
|
30777
31852
|
if (startedRef.current) return;
|
|
30778
31853
|
startedRef.current = true;
|
|
30779
|
-
const runScreen = (build) => new Promise((
|
|
30780
|
-
setScreen(build(
|
|
31854
|
+
const runScreen = (build) => new Promise((resolve22) => {
|
|
31855
|
+
setScreen(build(resolve22));
|
|
30781
31856
|
});
|
|
30782
31857
|
void (async () => {
|
|
30783
31858
|
const results = [];
|
|
@@ -30955,9 +32030,9 @@ var init_command8 = __esm({
|
|
|
30955
32030
|
function rank(p) {
|
|
30956
32031
|
if (p === "typed-slot") return 1;
|
|
30957
32032
|
if (p === "structural") return 2;
|
|
30958
|
-
if (p === "
|
|
30959
|
-
if (p === "
|
|
30960
|
-
if (p
|
|
32033
|
+
if (p === "manifest") return 3;
|
|
32034
|
+
if (p === "doc") return 4;
|
|
32035
|
+
if (p.startsWith("adapter:")) return 5;
|
|
30961
32036
|
return 6;
|
|
30962
32037
|
}
|
|
30963
32038
|
function mergeEdges(all) {
|
|
@@ -30993,6 +32068,65 @@ var init_merge_edges = __esm({
|
|
|
30993
32068
|
}
|
|
30994
32069
|
});
|
|
30995
32070
|
|
|
32071
|
+
// packages/experience-design-system-cli-legacy/src/analyze/composition/parse-map-edges.ts
|
|
32072
|
+
function parseMapEdges(raw, opts) {
|
|
32073
|
+
const edges = [];
|
|
32074
|
+
const warnings = [];
|
|
32075
|
+
const { componentNames } = opts;
|
|
32076
|
+
for (const line of raw.split("\n")) {
|
|
32077
|
+
const trimmed = line.trim();
|
|
32078
|
+
if (!trimmed.startsWith("{")) continue;
|
|
32079
|
+
let obj;
|
|
32080
|
+
try {
|
|
32081
|
+
obj = JSON.parse(trimmed);
|
|
32082
|
+
} catch {
|
|
32083
|
+
warnings.push(`unparseable line: ${trimmed.slice(0, 120)}`);
|
|
32084
|
+
continue;
|
|
32085
|
+
}
|
|
32086
|
+
if (typeof obj !== "object" || obj === null || !("tool" in obj)) continue;
|
|
32087
|
+
const rec = obj;
|
|
32088
|
+
if (!VALID_MAP_TOOL_NAMES.has(rec.tool)) {
|
|
32089
|
+
warnings.push(`unknown tool: ${String(rec.tool)}`);
|
|
32090
|
+
continue;
|
|
32091
|
+
}
|
|
32092
|
+
if (typeof rec.parent !== "string" || !rec.parent || typeof rec.child !== "string" || !rec.child) {
|
|
32093
|
+
warnings.push("map_edge missing parent/child \u2014 skipped");
|
|
32094
|
+
continue;
|
|
32095
|
+
}
|
|
32096
|
+
const { parent, child } = rec;
|
|
32097
|
+
if (!componentNames.has(parent)) {
|
|
32098
|
+
warnings.push(`map_edge names unknown component (parent): ${parent} \u2014 skipped`);
|
|
32099
|
+
continue;
|
|
32100
|
+
}
|
|
32101
|
+
if (!componentNames.has(child)) {
|
|
32102
|
+
warnings.push(`map_edge names unknown component (child): ${child} \u2014 skipped`);
|
|
32103
|
+
continue;
|
|
32104
|
+
}
|
|
32105
|
+
const edge = { parent, child, provenance: "agent" };
|
|
32106
|
+
if (typeof rec.slot === "string" && rec.slot) {
|
|
32107
|
+
edge.slot = rec.slot;
|
|
32108
|
+
}
|
|
32109
|
+
if (rec.confidence !== void 0) {
|
|
32110
|
+
if (typeof rec.confidence === "number" && rec.confidence >= 1 && rec.confidence <= 5) {
|
|
32111
|
+
edge.confidence = rec.confidence;
|
|
32112
|
+
} else {
|
|
32113
|
+
warnings.push(
|
|
32114
|
+
`map_edge (${parent}\u2192${child}): invalid confidence ${String(rec.confidence)} \u2014 edge kept without confidence`
|
|
32115
|
+
);
|
|
32116
|
+
}
|
|
32117
|
+
}
|
|
32118
|
+
edges.push(edge);
|
|
32119
|
+
}
|
|
32120
|
+
return { edges, warnings };
|
|
32121
|
+
}
|
|
32122
|
+
var VALID_MAP_TOOL_NAMES;
|
|
32123
|
+
var init_parse_map_edges = __esm({
|
|
32124
|
+
"packages/experience-design-system-cli-legacy/src/analyze/composition/parse-map-edges.ts"() {
|
|
32125
|
+
"use strict";
|
|
32126
|
+
VALID_MAP_TOOL_NAMES = /* @__PURE__ */ new Set(["map_edge"]);
|
|
32127
|
+
}
|
|
32128
|
+
});
|
|
32129
|
+
|
|
30996
32130
|
// packages/experience-design-system-cli-legacy/src/analyze/composition/apply-mapping.ts
|
|
30997
32131
|
function applyMapping(components, edges) {
|
|
30998
32132
|
const warnings = [];
|
|
@@ -31052,9 +32186,44 @@ var init_apply_mapping = __esm({
|
|
|
31052
32186
|
}
|
|
31053
32187
|
});
|
|
31054
32188
|
|
|
32189
|
+
// packages/experience-design-system-cli-legacy/src/analyze/composition/prompt-loader.ts
|
|
32190
|
+
import { existsSync as existsSync10, readFileSync as readFileSync10 } from "node:fs";
|
|
32191
|
+
import { dirname as dirname17, join as join27, resolve as resolve19 } from "node:path";
|
|
32192
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
32193
|
+
function resolvePromptPath(fileName) {
|
|
32194
|
+
const thisDir = dirname17(fileURLToPath3(import.meta.url));
|
|
32195
|
+
let dir = thisDir;
|
|
32196
|
+
for (; ; ) {
|
|
32197
|
+
const candidate = join27(dir, "prompts");
|
|
32198
|
+
if (existsSync10(candidate)) return join27(candidate, fileName);
|
|
32199
|
+
const parent = resolve19(dir, "..");
|
|
32200
|
+
if (parent === dir) {
|
|
32201
|
+
throw new Error(
|
|
32202
|
+
`prompt file missing from CLI installation (could not locate prompts/ directory from: ${thisDir})`
|
|
32203
|
+
);
|
|
32204
|
+
}
|
|
32205
|
+
dir = parent;
|
|
32206
|
+
}
|
|
32207
|
+
}
|
|
32208
|
+
function loadPrompt(fileName) {
|
|
32209
|
+
const path = resolvePromptPath(fileName);
|
|
32210
|
+
try {
|
|
32211
|
+
return readFileSync10(path, "utf8");
|
|
32212
|
+
} catch {
|
|
32213
|
+
throw new Error(`prompt file missing from CLI installation \u2014 try reinstalling the CLI (looked for: ${path})`);
|
|
32214
|
+
}
|
|
32215
|
+
}
|
|
32216
|
+
var init_prompt_loader = __esm({
|
|
32217
|
+
"packages/experience-design-system-cli-legacy/src/analyze/composition/prompt-loader.ts"() {
|
|
32218
|
+
"use strict";
|
|
32219
|
+
}
|
|
32220
|
+
});
|
|
32221
|
+
|
|
31055
32222
|
// packages/experience-design-system-cli-legacy/src/analyze/composition/resolve-mapping.ts
|
|
31056
|
-
function resolveMapping(input) {
|
|
32223
|
+
async function resolveMapping(input) {
|
|
32224
|
+
const componentNames = new Set(input.components.map((c2) => c2.name));
|
|
31057
32225
|
const collected = [];
|
|
32226
|
+
const agentWarnings = [];
|
|
31058
32227
|
for (const c2 of input.components) {
|
|
31059
32228
|
for (const slot of c2.slots) {
|
|
31060
32229
|
for (const child of slot.allowedComponents ?? []) {
|
|
@@ -31072,41 +32241,17 @@ function resolveMapping(input) {
|
|
|
31072
32241
|
if (input.extraEdges) {
|
|
31073
32242
|
collected.push(...input.extraEdges);
|
|
31074
32243
|
}
|
|
31075
|
-
for (const evidence of input.sourceCallSiteEvidence ?? []) {
|
|
31076
|
-
collected.push({
|
|
31077
|
-
parent: evidence.parent,
|
|
31078
|
-
child: evidence.child,
|
|
31079
|
-
...evidence.slot ? { slot: evidence.slot } : {},
|
|
31080
|
-
citation: { sourcePath: evidence.sourcePath, startLine: evidence.startLine, endLine: evidence.endLine },
|
|
31081
|
-
provenance: "call-site"
|
|
31082
|
-
});
|
|
31083
|
-
}
|
|
31084
32244
|
const coveredParents = new Set(collected.map((e) => e.parent));
|
|
31085
32245
|
const residueParents = input.components.map((c2) => c2.name).filter((n) => !coveredParents.has(n));
|
|
31086
|
-
const
|
|
31087
|
-
|
|
31088
|
-
const
|
|
31089
|
-
|
|
31090
|
-
|
|
31091
|
-
|
|
31092
|
-
|
|
31093
|
-
|
|
31094
|
-
coveredParents: [...coveredParents].sort(),
|
|
31095
|
-
residueParents,
|
|
31096
|
-
sourceCallSiteAccepted: input.sourceCallSiteEvidence?.length ?? 0,
|
|
31097
|
-
sourceCallSiteRejected: input.sourceCallSiteRejections?.length ?? 0
|
|
31098
|
-
});
|
|
32246
|
+
const shouldRunAgent = input.forceAgent || residueParents.length > 0 && input.files.length > 0;
|
|
32247
|
+
if (shouldRunAgent) {
|
|
32248
|
+
const prompt = input.buildPrompt ? input.buildPrompt(input.files, [...componentNames]) : defaultPrompt(input.files, [...componentNames], input.promptOverride);
|
|
32249
|
+
const raw = await input.runAgentFn({ prompt, files: input.files }) ?? "";
|
|
32250
|
+
const parsed = parseMapEdges(raw, { componentNames });
|
|
32251
|
+
collected.push(...parsed.edges);
|
|
32252
|
+
agentWarnings.push(...parsed.warnings);
|
|
32253
|
+
}
|
|
31099
32254
|
const merged = mergeEdges(collected);
|
|
31100
|
-
debug.event("analyze", "composition.merged", {
|
|
31101
|
-
edgeCountsByProvenance: countByProvenance(merged.edges),
|
|
31102
|
-
conflicts: merged.conflicts,
|
|
31103
|
-
edges: merged.edges.map((edge) => ({
|
|
31104
|
-
parent: edge.parent,
|
|
31105
|
-
child: edge.child,
|
|
31106
|
-
slot: edge.slot ?? null,
|
|
31107
|
-
provenance: edge.provenance
|
|
31108
|
-
}))
|
|
31109
|
-
});
|
|
31110
32255
|
const base = input.components.map((c2) => ({
|
|
31111
32256
|
...c2,
|
|
31112
32257
|
slots: c2.slots.map((s) => {
|
|
@@ -31115,32 +32260,127 @@ function resolveMapping(input) {
|
|
|
31115
32260
|
})
|
|
31116
32261
|
}));
|
|
31117
32262
|
const applied = applyMapping(base, merged.edges);
|
|
31118
|
-
debug.event("analyze", "composition.applied", {
|
|
31119
|
-
slots: applied.components.flatMap(
|
|
31120
|
-
(component) => component.slots.filter((slot) => (slot.allowedComponents?.length ?? 0) > 0).map((slot) => ({ component: component.name, slot: slot.name, allowedComponents: slot.allowedComponents }))
|
|
31121
|
-
),
|
|
31122
|
-
warnings: applied.warnings
|
|
31123
|
-
});
|
|
31124
32263
|
return {
|
|
31125
32264
|
components: applied.components,
|
|
31126
32265
|
edges: merged.edges,
|
|
31127
32266
|
conflicts: merged.conflicts,
|
|
31128
|
-
warnings: applied.warnings
|
|
31129
|
-
sourceCallSiteEvidence: [...input.sourceCallSiteEvidence ?? []],
|
|
31130
|
-
sourceCallSiteRejections: [...input.sourceCallSiteRejections ?? []]
|
|
32267
|
+
warnings: [...agentWarnings, ...applied.warnings]
|
|
31131
32268
|
};
|
|
31132
32269
|
}
|
|
32270
|
+
function defaultPrompt(files, componentNames, promptOverride) {
|
|
32271
|
+
const fileBlocks = files.map((f) => `--- ${f.path} ---
|
|
32272
|
+
${f.content}`).join("\n\n");
|
|
32273
|
+
const instruction = promptOverride?.trim() ? promptOverride.trim() : loadPrompt("composition-edges.md").trim();
|
|
32274
|
+
return [
|
|
32275
|
+
instruction,
|
|
32276
|
+
"",
|
|
32277
|
+
'Emit one JSON object per line, each: {"tool":"map_edge","parent":"<Name>","child":"<Name>","slot"?:"<slot>","confidence"?:1-5,"reason":"<cite the file + declaration>"}.',
|
|
32278
|
+
"Use ONLY these exact component names (an edge naming anything else is dropped):",
|
|
32279
|
+
componentNames.join(", "),
|
|
32280
|
+
"",
|
|
32281
|
+
"Candidate files:",
|
|
32282
|
+
fileBlocks
|
|
32283
|
+
].join("\n");
|
|
32284
|
+
}
|
|
31133
32285
|
var init_resolve_mapping = __esm({
|
|
31134
32286
|
"packages/experience-design-system-cli-legacy/src/analyze/composition/resolve-mapping.ts"() {
|
|
31135
32287
|
"use strict";
|
|
31136
32288
|
init_merge_edges();
|
|
32289
|
+
init_parse_map_edges();
|
|
31137
32290
|
init_apply_mapping();
|
|
31138
|
-
|
|
32291
|
+
init_prompt_loader();
|
|
32292
|
+
}
|
|
32293
|
+
});
|
|
32294
|
+
|
|
32295
|
+
// packages/experience-design-system-cli-legacy/src/analyze/composition/resolve-mapping-cli.ts
|
|
32296
|
+
function resolveCompositionSources(opts) {
|
|
32297
|
+
return {
|
|
32298
|
+
forceAgent: opts.compositionRefresh === true || opts.noCache === true
|
|
32299
|
+
};
|
|
32300
|
+
}
|
|
32301
|
+
var init_resolve_mapping_cli = __esm({
|
|
32302
|
+
"packages/experience-design-system-cli-legacy/src/analyze/composition/resolve-mapping-cli.ts"() {
|
|
32303
|
+
"use strict";
|
|
32304
|
+
}
|
|
32305
|
+
});
|
|
32306
|
+
|
|
32307
|
+
// packages/experience-design-system-cli-legacy/src/analyze/composition/candidate-files.ts
|
|
32308
|
+
function matchReason(file) {
|
|
32309
|
+
const segments = file.path.split("/").filter((s) => s !== "");
|
|
32310
|
+
for (const pattern of CANDIDATE_NAME_PATTERNS) {
|
|
32311
|
+
if (segments.some((seg) => pattern.test(seg))) {
|
|
32312
|
+
return `name:${pattern.source.toLowerCase()}`;
|
|
32313
|
+
}
|
|
32314
|
+
}
|
|
32315
|
+
for (const marker of CANDIDATE_CONTENT_MARKERS) {
|
|
32316
|
+
if (file.content.includes(marker)) return `content:${marker}`;
|
|
32317
|
+
}
|
|
32318
|
+
return void 0;
|
|
32319
|
+
}
|
|
32320
|
+
function selectCandidateFiles(files) {
|
|
32321
|
+
const selected = [];
|
|
32322
|
+
const seen = /* @__PURE__ */ new Set();
|
|
32323
|
+
for (const file of files) {
|
|
32324
|
+
if (seen.has(file.path)) continue;
|
|
32325
|
+
const reason = matchReason(file);
|
|
32326
|
+
if (reason === void 0) continue;
|
|
32327
|
+
seen.add(file.path);
|
|
32328
|
+
selected.push({ path: file.path, content: file.content, reason });
|
|
32329
|
+
}
|
|
32330
|
+
return selected;
|
|
32331
|
+
}
|
|
32332
|
+
function capCandidatesToPromptBudget(files, budget = PROMPT_CANDIDATE_TOKEN_BUDGET) {
|
|
32333
|
+
const ordered = [...files].sort((a, b) => a.content.length - b.content.length || a.path.localeCompare(b.path));
|
|
32334
|
+
const kept = [];
|
|
32335
|
+
const dropped = [];
|
|
32336
|
+
let spent = 0;
|
|
32337
|
+
for (const file of ordered) {
|
|
32338
|
+
const cost = tokenCost(file);
|
|
32339
|
+
if (spent + cost > budget) {
|
|
32340
|
+
dropped.push(file);
|
|
32341
|
+
continue;
|
|
32342
|
+
}
|
|
32343
|
+
kept.push(file);
|
|
32344
|
+
spent += cost;
|
|
32345
|
+
}
|
|
32346
|
+
return { kept, dropped };
|
|
32347
|
+
}
|
|
32348
|
+
function tokenCost(file) {
|
|
32349
|
+
return Math.ceil(file.content.length / CHARS_PER_TOKEN);
|
|
32350
|
+
}
|
|
32351
|
+
var CANDIDATE_NAME_PATTERNS, CANDIDATE_CONTENT_MARKERS, PROMPT_CANDIDATE_TOKEN_BUDGET, CHARS_PER_TOKEN;
|
|
32352
|
+
var init_candidate_files = __esm({
|
|
32353
|
+
"packages/experience-design-system-cli-legacy/src/analyze/composition/candidate-files.ts"() {
|
|
32354
|
+
"use strict";
|
|
32355
|
+
CANDIDATE_NAME_PATTERNS = [/mapping/i, /meta/i, /registry/i, /schema/i, /composition/i];
|
|
32356
|
+
CANDIDATE_CONTENT_MARKERS = [
|
|
32357
|
+
"requiredParent",
|
|
32358
|
+
"withParentType",
|
|
32359
|
+
"allowedTagNames",
|
|
32360
|
+
"createContext",
|
|
32361
|
+
"MappingContext",
|
|
32362
|
+
"allowedComponents"
|
|
32363
|
+
];
|
|
32364
|
+
PROMPT_CANDIDATE_TOKEN_BUDGET = 8e4;
|
|
32365
|
+
CHARS_PER_TOKEN = 4;
|
|
32366
|
+
}
|
|
32367
|
+
});
|
|
32368
|
+
|
|
32369
|
+
// packages/experience-design-system-cli-legacy/src/analyze/composition/composition-cache-key.ts
|
|
32370
|
+
function buildCompositionInputHash(input) {
|
|
32371
|
+
const fileDigest = input.files.map((f) => `${f.path} ${hashContent(f.content)}`).sort().join("");
|
|
32372
|
+
return hashContent(`agent:${input.agent}
|
|
32373
|
+
${fileDigest}`);
|
|
32374
|
+
}
|
|
32375
|
+
var init_composition_cache_key = __esm({
|
|
32376
|
+
"packages/experience-design-system-cli-legacy/src/analyze/composition/composition-cache-key.ts"() {
|
|
32377
|
+
"use strict";
|
|
32378
|
+
init_cache_keys();
|
|
31139
32379
|
}
|
|
31140
32380
|
});
|
|
31141
32381
|
|
|
31142
32382
|
// packages/experience-design-system-cli-legacy/src/analyze/composition/manifest-doc-evidence.ts
|
|
31143
|
-
import { dirname as
|
|
32383
|
+
import { dirname as dirname18 } from "node:path";
|
|
31144
32384
|
function kebabToPascal2(name) {
|
|
31145
32385
|
return name.split("-").filter(Boolean).map((seg) => seg.charAt(0).toUpperCase() + seg.slice(1)).join("");
|
|
31146
32386
|
}
|
|
@@ -31190,8 +32430,8 @@ function collectAgentsDocEdges(files, components, componentNames) {
|
|
|
31190
32430
|
const seen = /* @__PURE__ */ new Set();
|
|
31191
32431
|
for (const file of files) {
|
|
31192
32432
|
if (!file.path.endsWith("AGENTS.md")) continue;
|
|
31193
|
-
const docDir =
|
|
31194
|
-
const parent = components.find((c2) => c2.sourcePath &&
|
|
32433
|
+
const docDir = dirname18(file.path);
|
|
32434
|
+
const parent = components.find((c2) => c2.sourcePath && dirname18(c2.sourcePath) === docDir)?.name;
|
|
31195
32435
|
if (!parent || !componentNames.has(parent)) continue;
|
|
31196
32436
|
for (const line of file.content.split("\n")) {
|
|
31197
32437
|
const lower = line.toLowerCase();
|
|
@@ -31221,172 +32461,12 @@ var init_manifest_doc_evidence = __esm({
|
|
|
31221
32461
|
}
|
|
31222
32462
|
});
|
|
31223
32463
|
|
|
31224
|
-
// packages/experience-design-system-cli-legacy/src/analyze/composition/source-call-site-evidence.ts
|
|
31225
|
-
import { Node as Node49, Project as Project11, SyntaxKind as SyntaxKind15 } from "ts-morph";
|
|
31226
|
-
function collectSourceCallSiteEvidence(files, components) {
|
|
31227
|
-
const componentNames = new Set(components.map((component) => component.name));
|
|
31228
|
-
const componentsBySource = /* @__PURE__ */ new Map();
|
|
31229
|
-
for (const component of components) {
|
|
31230
|
-
const sourcePath = component.sourcePath ?? component.source;
|
|
31231
|
-
const siblings = componentsBySource.get(sourcePath) ?? [];
|
|
31232
|
-
siblings.push(component);
|
|
31233
|
-
componentsBySource.set(sourcePath, siblings);
|
|
31234
|
-
}
|
|
31235
|
-
const project = new Project11({
|
|
31236
|
-
compilerOptions: { jsx: 1, target: 99, module: 99, moduleResolution: 100, skipLibCheck: true, allowJs: true },
|
|
31237
|
-
skipAddingFilesFromTsConfig: true
|
|
31238
|
-
});
|
|
31239
|
-
const sourceFiles = new Map(
|
|
31240
|
-
files.map((file) => [file.path, project.createSourceFile(file.path, file.content, { overwrite: true })])
|
|
31241
|
-
);
|
|
31242
|
-
const accepted = [];
|
|
31243
|
-
const rejected = [];
|
|
31244
|
-
for (const [sourcePath, parents] of componentsBySource) {
|
|
31245
|
-
const sourceFile = sourceFiles.get(sourcePath);
|
|
31246
|
-
if (!sourceFile) continue;
|
|
31247
|
-
const boundNames = collectBoundNames(sourceFile);
|
|
31248
|
-
for (const parent of parents) {
|
|
31249
|
-
for (const jsxElement of [
|
|
31250
|
-
...sourceFile.getDescendantsOfKind(SyntaxKind15.JsxSelfClosingElement),
|
|
31251
|
-
...sourceFile.getDescendantsOfKind(SyntaxKind15.JsxElement)
|
|
31252
|
-
]) {
|
|
31253
|
-
const tagName = Node49.isJsxSelfClosingElement(jsxElement) ? jsxElement.getTagNameNode().getText() : jsxElement.getOpeningElement().getTagNameNode().getText();
|
|
31254
|
-
const candidate = tagName.split(".").at(-1) ?? tagName;
|
|
31255
|
-
if (candidate === parent.name || isIntrinsicTag(candidate)) continue;
|
|
31256
|
-
const lines = sourceExcerpt(sourceFile, jsxElement);
|
|
31257
|
-
if (!componentNames.has(candidate)) {
|
|
31258
|
-
rejected.push({ parent: parent.name, candidate, ...lines, reason: "unknown-component" });
|
|
31259
|
-
continue;
|
|
31260
|
-
}
|
|
31261
|
-
if (!boundNames.has(tagName) && !boundNames.has(candidate)) {
|
|
31262
|
-
rejected.push({ parent: parent.name, candidate, ...lines, reason: "unbound-component" });
|
|
31263
|
-
continue;
|
|
31264
|
-
}
|
|
31265
|
-
accepted.push({ parent: parent.name, child: candidate, ...lines, kind: "jsx-render" });
|
|
31266
|
-
}
|
|
31267
|
-
}
|
|
31268
|
-
}
|
|
31269
|
-
for (const sourceFile of sourceFiles.values()) {
|
|
31270
|
-
collectCallerSlotEvidence(sourceFile, componentNames, collectBoundNames(sourceFile), accepted, rejected);
|
|
31271
|
-
}
|
|
31272
|
-
const verifiedPairs = new Set(accepted.map((evidence) => `${evidence.parent}\0${evidence.child}`));
|
|
31273
|
-
for (const component of components) {
|
|
31274
|
-
const candidates = component.slots.flatMap((slot) => [
|
|
31275
|
-
...slot.allowedComponents ?? [],
|
|
31276
|
-
...slot.structuralAllowedComponents ?? []
|
|
31277
|
-
]);
|
|
31278
|
-
for (const candidate of candidates) {
|
|
31279
|
-
if (verifiedPairs.has(`${component.name}\0${candidate}`)) continue;
|
|
31280
|
-
rejected.push({
|
|
31281
|
-
parent: component.name,
|
|
31282
|
-
candidate,
|
|
31283
|
-
sourcePath: component.sourcePath ?? component.source,
|
|
31284
|
-
reason: "no-call-site"
|
|
31285
|
-
});
|
|
31286
|
-
}
|
|
31287
|
-
}
|
|
31288
|
-
return {
|
|
31289
|
-
accepted: dedupeEvidence(accepted),
|
|
31290
|
-
rejected: dedupeRejections(rejected)
|
|
31291
|
-
};
|
|
31292
|
-
}
|
|
31293
|
-
function collectCallerSlotEvidence(sourceFile, componentNames, boundNames, accepted, rejected) {
|
|
31294
|
-
for (const parentElement of sourceFile.getDescendantsOfKind(SyntaxKind15.JsxElement)) {
|
|
31295
|
-
const parentTag = parentElement.getOpeningElement().getTagNameNode().getText();
|
|
31296
|
-
const parent = parentTag.split(".").at(-1) ?? parentTag;
|
|
31297
|
-
if (!componentNames.has(parent) || !boundNames.has(parentTag)) continue;
|
|
31298
|
-
for (const childNode of parentElement.getJsxChildren()) {
|
|
31299
|
-
if (!Node49.isJsxElement(childNode) && !Node49.isJsxSelfClosingElement(childNode)) {
|
|
31300
|
-
if (Node49.isJsxText(childNode) && childNode.getText().trim()) {
|
|
31301
|
-
const lines2 = sourceExcerpt(sourceFile, childNode);
|
|
31302
|
-
rejected.push({ parent, candidate: "<text>", ...lines2, reason: "text-only-child" });
|
|
31303
|
-
}
|
|
31304
|
-
continue;
|
|
31305
|
-
}
|
|
31306
|
-
const childTag = Node49.isJsxElement(childNode) ? childNode.getOpeningElement().getTagNameNode().getText() : childNode.getTagNameNode().getText();
|
|
31307
|
-
const child = childTag.split(".").at(-1) ?? childTag;
|
|
31308
|
-
if (isIntrinsicTag(child)) continue;
|
|
31309
|
-
const lines = sourceExcerpt(sourceFile, childNode);
|
|
31310
|
-
if (!componentNames.has(child)) {
|
|
31311
|
-
rejected.push({ parent, candidate: child, ...lines, reason: "unknown-component" });
|
|
31312
|
-
continue;
|
|
31313
|
-
}
|
|
31314
|
-
if (!boundNames.has(childTag) && !boundNames.has(child)) {
|
|
31315
|
-
rejected.push({ parent, candidate: child, ...lines, reason: "unbound-component" });
|
|
31316
|
-
continue;
|
|
31317
|
-
}
|
|
31318
|
-
const slotAttribute = Node49.isJsxElement(childNode) ? childNode.getOpeningElement().getAttribute("slot") : childNode.getAttribute("slot");
|
|
31319
|
-
const slotValue = slotAttribute && Node49.isJsxAttribute(slotAttribute) ? slotAttribute.getInitializer() : void 0;
|
|
31320
|
-
const slot = slotValue && Node49.isStringLiteral(slotValue) ? slotValue.getLiteralValue() : void 0;
|
|
31321
|
-
accepted.push({ parent, child, ...slot ? { slot } : {}, ...lines, kind: "jsx-render" });
|
|
31322
|
-
}
|
|
31323
|
-
}
|
|
31324
|
-
}
|
|
31325
|
-
function collectBoundNames(sourceFile) {
|
|
31326
|
-
const names = /* @__PURE__ */ new Set();
|
|
31327
|
-
for (const declaration of sourceFile.getImportDeclarations()) {
|
|
31328
|
-
const defaultImport = declaration.getDefaultImport();
|
|
31329
|
-
if (defaultImport) names.add(defaultImport.getText());
|
|
31330
|
-
const namespaceImport = declaration.getNamespaceImport();
|
|
31331
|
-
if (namespaceImport) names.add(namespaceImport.getText());
|
|
31332
|
-
for (const namedImport of declaration.getNamedImports()) {
|
|
31333
|
-
names.add((namedImport.getAliasNode() ?? namedImport.getNameNode()).getText());
|
|
31334
|
-
}
|
|
31335
|
-
}
|
|
31336
|
-
for (const declaration of sourceFile.getVariableDeclarations()) names.add(declaration.getName());
|
|
31337
|
-
for (const declaration of sourceFile.getFunctions()) {
|
|
31338
|
-
if (declaration.getName()) names.add(declaration.getName());
|
|
31339
|
-
}
|
|
31340
|
-
for (const declaration of sourceFile.getClasses()) {
|
|
31341
|
-
if (declaration.getName()) names.add(declaration.getName());
|
|
31342
|
-
}
|
|
31343
|
-
return names;
|
|
31344
|
-
}
|
|
31345
|
-
function sourceExcerpt(sourceFile, node) {
|
|
31346
|
-
const startLine = node.getStartLineNumber();
|
|
31347
|
-
const endLine = node.getEndLineNumber();
|
|
31348
|
-
const lines = sourceFile.getFullText().split("\n");
|
|
31349
|
-
return {
|
|
31350
|
-
sourcePath: sourceFile.getFilePath(),
|
|
31351
|
-
startLine,
|
|
31352
|
-
endLine,
|
|
31353
|
-
excerpt: lines.slice(startLine - 1, endLine).join("\n").trim()
|
|
31354
|
-
};
|
|
31355
|
-
}
|
|
31356
|
-
function isIntrinsicTag(tagName) {
|
|
31357
|
-
return /^[a-z]/.test(tagName) || tagName.includes("-");
|
|
31358
|
-
}
|
|
31359
|
-
function dedupeEvidence(evidence) {
|
|
31360
|
-
const seen = /* @__PURE__ */ new Set();
|
|
31361
|
-
return evidence.filter((item) => {
|
|
31362
|
-
const key = `${item.parent}\0${item.child}\0${item.slot ?? ""}\0${item.sourcePath}\0${item.startLine}`;
|
|
31363
|
-
if (seen.has(key)) return false;
|
|
31364
|
-
seen.add(key);
|
|
31365
|
-
return true;
|
|
31366
|
-
}).sort(
|
|
31367
|
-
(left, right) => `${left.parent}\0${left.child}\0${left.sourcePath}\0${left.startLine}`.localeCompare(
|
|
31368
|
-
`${right.parent}\0${right.child}\0${right.sourcePath}\0${right.startLine}`
|
|
31369
|
-
)
|
|
31370
|
-
);
|
|
31371
|
-
}
|
|
31372
|
-
function dedupeRejections(rejections) {
|
|
31373
|
-
const seen = /* @__PURE__ */ new Set();
|
|
31374
|
-
return rejections.filter((item) => {
|
|
31375
|
-
const key = `${item.parent}\0${item.candidate}\0${item.sourcePath}\0${item.startLine}`;
|
|
31376
|
-
if (seen.has(key)) return false;
|
|
31377
|
-
seen.add(key);
|
|
31378
|
-
return true;
|
|
31379
|
-
});
|
|
31380
|
-
}
|
|
31381
|
-
var init_source_call_site_evidence = __esm({
|
|
31382
|
-
"packages/experience-design-system-cli-legacy/src/analyze/composition/source-call-site-evidence.ts"() {
|
|
31383
|
-
"use strict";
|
|
31384
|
-
}
|
|
31385
|
-
});
|
|
31386
|
-
|
|
31387
32464
|
// packages/experience-design-system-cli-legacy/src/analyze/extract-command.ts
|
|
31388
|
-
import { mkdir as mkdir6, readdir as readdir3, readFile as
|
|
31389
|
-
import { isAbsolute as isAbsolute2, join as
|
|
32465
|
+
import { mkdir as mkdir6, readdir as readdir3, readFile as readFile19, stat as stat6 } from "node:fs/promises";
|
|
32466
|
+
import { isAbsolute as isAbsolute2, join as join28, relative as relative2, resolve as resolve20 } from "node:path";
|
|
32467
|
+
function resolveExtractNoCache(opts) {
|
|
32468
|
+
return opts.noCache === true || opts.cache === false;
|
|
32469
|
+
}
|
|
31390
32470
|
function isDenylistedNoiseFile(name) {
|
|
31391
32471
|
return DENYLISTED_EXACT_FILE_NAMES.has(name) || DENYLISTED_FILE_NAME_PATTERNS.some((pattern) => pattern.test(name));
|
|
31392
32472
|
}
|
|
@@ -31400,12 +32480,12 @@ async function retryDatabaseWrite(operation, attempts = 8) {
|
|
|
31400
32480
|
} catch (error) {
|
|
31401
32481
|
const message = error instanceof Error ? error.message : String(error);
|
|
31402
32482
|
if (!/database is locked|database is busy/i.test(message) || attempt >= attempts) throw error;
|
|
31403
|
-
await new Promise((
|
|
32483
|
+
await new Promise((resolve22) => setTimeout(resolve22, Math.min(250 * attempt, 2e3)));
|
|
31404
32484
|
}
|
|
31405
32485
|
}
|
|
31406
32486
|
}
|
|
31407
32487
|
function resolveFromProjectRoot(projectRoot, inputPath) {
|
|
31408
|
-
return isAbsolute2(inputPath) ? inputPath :
|
|
32488
|
+
return isAbsolute2(inputPath) ? inputPath : resolve20(projectRoot, inputPath);
|
|
31409
32489
|
}
|
|
31410
32490
|
async function pathExists4(path) {
|
|
31411
32491
|
return Boolean(await stat6(path).catch(() => null));
|
|
@@ -31416,7 +32496,7 @@ async function collectSourceFiles(directory, onProgress) {
|
|
|
31416
32496
|
const entries = await readdir3(currentDirectory, { withFileTypes: true });
|
|
31417
32497
|
const subdirs = [];
|
|
31418
32498
|
for (const entry of entries) {
|
|
31419
|
-
const fullPath =
|
|
32499
|
+
const fullPath = join28(currentDirectory, entry.name);
|
|
31420
32500
|
if (entry.isDirectory()) {
|
|
31421
32501
|
if (!IGNORED_DIRECTORY_NAMES.has(entry.name)) {
|
|
31422
32502
|
subdirs.push(fullPath);
|
|
@@ -31443,6 +32523,12 @@ async function collectSourceFiles(directory, onProgress) {
|
|
|
31443
32523
|
await visit(directory);
|
|
31444
32524
|
return files.sort();
|
|
31445
32525
|
}
|
|
32526
|
+
function resolveCompositionAgentName(flagValue) {
|
|
32527
|
+
if (flagValue && isAgentName(flagValue)) return flagValue;
|
|
32528
|
+
const env = process.env["EDS_COMPOSITION_AGENT"];
|
|
32529
|
+
if (env && isAgentName(env)) return env;
|
|
32530
|
+
return DEFAULT_AGENT_NAME;
|
|
32531
|
+
}
|
|
31446
32532
|
async function readCandidateFiles(components, extraFiles = []) {
|
|
31447
32533
|
const paths = new Set(extraFiles);
|
|
31448
32534
|
for (const c2 of components) {
|
|
@@ -31452,7 +32538,7 @@ async function readCandidateFiles(components, extraFiles = []) {
|
|
|
31452
32538
|
await Promise.all(
|
|
31453
32539
|
[...paths].map(async (p) => {
|
|
31454
32540
|
try {
|
|
31455
|
-
const content = await
|
|
32541
|
+
const content = await readFile19(p, "utf8");
|
|
31456
32542
|
out.push({ path: p, content });
|
|
31457
32543
|
} catch {
|
|
31458
32544
|
}
|
|
@@ -31461,11 +32547,21 @@ async function readCandidateFiles(components, extraFiles = []) {
|
|
|
31461
32547
|
return out;
|
|
31462
32548
|
}
|
|
31463
32549
|
function registerInternalExtractCommand(program) {
|
|
31464
|
-
program.command("__extract", { hidden: true }).description("Extract component definitions from a project").requiredOption("--project <path>", "Path to the project root").option("--dir <path>", "Path to the component source directory relative to the project root").option(
|
|
32550
|
+
const extractCmd = program.command("__extract", { hidden: true }).description("Extract component definitions from a project").requiredOption("--project <path>", "Path to the project root").option("--dir <path>", "Path to the component source directory relative to the project root").option(
|
|
31465
32551
|
"--resolve-unreachable <mode>",
|
|
31466
32552
|
"Retry pass for unresolved Svelte Props types: 'auto' (default), 'always', or 'never'",
|
|
31467
32553
|
"auto"
|
|
31468
|
-
).
|
|
32554
|
+
).option("--composition-refresh", "Force the mapping agent to run even where deterministic sources answered").option("--no-cache", "Re-run extraction even when all source files are unchanged").option(
|
|
32555
|
+
"--prompt <stage=value>",
|
|
32556
|
+
"Override a stage prompt (repeatable). value is a file path or literal text, e.g. --prompt composition=./p.md",
|
|
32557
|
+
(v, acc) => [...acc, v],
|
|
32558
|
+
[]
|
|
32559
|
+
);
|
|
32560
|
+
addAgentModelOptions(extractCmd, {
|
|
32561
|
+
includeModel: false,
|
|
32562
|
+
agentDescription: "Coding agent for composition mapping resolution (claude|codex|opencode|cursor)"
|
|
32563
|
+
}).action(async (opts) => {
|
|
32564
|
+
const noCache = resolveExtractNoCache(opts);
|
|
31469
32565
|
const resolveUnreachable = (() => {
|
|
31470
32566
|
const v = opts.resolveUnreachable ?? "auto";
|
|
31471
32567
|
if (v !== "auto" && v !== "always" && v !== "never") {
|
|
@@ -31475,8 +32571,16 @@ function registerInternalExtractCommand(program) {
|
|
|
31475
32571
|
}
|
|
31476
32572
|
return v;
|
|
31477
32573
|
})();
|
|
31478
|
-
|
|
31479
|
-
|
|
32574
|
+
if (opts.bedrock) {
|
|
32575
|
+
const bedrockAgent = resolveCompositionAgentName(opts.agent);
|
|
32576
|
+
if (!agentSupportsBedrock(bedrockAgent)) {
|
|
32577
|
+
process.stderr.write(`Error: --bedrock is not supported for --agent ${bedrockAgent}
|
|
32578
|
+
`);
|
|
32579
|
+
process.exit(1);
|
|
32580
|
+
}
|
|
32581
|
+
}
|
|
32582
|
+
const projectRoot = resolve20(opts.project);
|
|
32583
|
+
const outDir = join28(projectRoot, ".contentful");
|
|
31480
32584
|
let sourceDirectory;
|
|
31481
32585
|
if (opts.dir !== void 0) {
|
|
31482
32586
|
sourceDirectory = resolveFromProjectRoot(projectRoot, opts.dir);
|
|
@@ -31499,16 +32603,50 @@ function registerInternalExtractCommand(program) {
|
|
|
31499
32603
|
process.stderr.write(`progress=scan-done:${sourceFiles.length}
|
|
31500
32604
|
`);
|
|
31501
32605
|
}
|
|
31502
|
-
const
|
|
31503
|
-
|
|
31504
|
-
|
|
32606
|
+
const extractionCacheDb = openPipelineDb();
|
|
32607
|
+
let extraction;
|
|
32608
|
+
let extractionCacheHits = 0;
|
|
32609
|
+
try {
|
|
32610
|
+
const cacheVersion = await getCliCacheVersion();
|
|
32611
|
+
const cachedByPath = /* @__PURE__ */ new Map();
|
|
32612
|
+
if (!noCache && sourceFiles.length > 0) {
|
|
32613
|
+
const hashes = await Promise.all(
|
|
32614
|
+
sourceFiles.map(async (filePath) => [filePath, await hashFile(filePath)])
|
|
32615
|
+
);
|
|
32616
|
+
for (const [filePath, fileHash] of hashes) {
|
|
32617
|
+
cachedByPath.set(filePath, lookupExtractCache(extractionCacheDb, fileHash, cacheVersion));
|
|
32618
|
+
}
|
|
32619
|
+
}
|
|
32620
|
+
const allFilesCached = !noCache && sourceFiles.length > 0 && sourceFiles.every((filePath) => cachedByPath.get(filePath) !== null);
|
|
32621
|
+
if (allFilesCached) {
|
|
32622
|
+
const cachedComponents = sourceFiles.flatMap((filePath) => cachedByPath.get(filePath).components);
|
|
32623
|
+
extractionCacheHits = sourceFiles.length;
|
|
32624
|
+
extraction = { components: cachedComponents, warnings: [], exclusions: [] };
|
|
31505
32625
|
if (!process.stdout.isTTY) {
|
|
31506
|
-
process.stderr.write(
|
|
31507
|
-
`
|
|
32626
|
+
process.stderr.write(
|
|
32627
|
+
`progress=extract:${sourceFiles.length}/${sourceFiles.length}:${cachedComponents.length}
|
|
32628
|
+
`
|
|
32629
|
+
);
|
|
31508
32630
|
}
|
|
31509
|
-
|
|
31510
|
-
|
|
31511
|
-
|
|
32631
|
+
getDebugLogger().event("analyze", "extract.cache-hit", {
|
|
32632
|
+
files: sourceFiles.length,
|
|
32633
|
+
components: cachedComponents.length
|
|
32634
|
+
});
|
|
32635
|
+
} else {
|
|
32636
|
+
extraction = await extractComponents(
|
|
32637
|
+
sourceFiles,
|
|
32638
|
+
({ filesProcessed, componentsFound }) => {
|
|
32639
|
+
if (!process.stdout.isTTY) {
|
|
32640
|
+
process.stderr.write(`progress=extract:${filesProcessed}/${sourceFiles.length}:${componentsFound}
|
|
32641
|
+
`);
|
|
32642
|
+
}
|
|
32643
|
+
},
|
|
32644
|
+
{ resolveUnreachable, projectRoot }
|
|
32645
|
+
);
|
|
32646
|
+
}
|
|
32647
|
+
} finally {
|
|
32648
|
+
extractionCacheDb.close();
|
|
32649
|
+
}
|
|
31512
32650
|
await mkdir6(outDir, { recursive: true });
|
|
31513
32651
|
const db = openPipelineDb();
|
|
31514
32652
|
const { sessionId: sessionId2 } = getOrCreateSession(db, void 0, void 0, {
|
|
@@ -31523,6 +32661,25 @@ function registerInternalExtractCommand(program) {
|
|
|
31523
32661
|
const stepId = createStep(db, sessionId2, "analyze extract", {
|
|
31524
32662
|
project: projectRoot
|
|
31525
32663
|
});
|
|
32664
|
+
if (extractionCacheHits === 0 && !noCache) {
|
|
32665
|
+
const cacheVersion = await getCliCacheVersion();
|
|
32666
|
+
const componentsBySourcePath = /* @__PURE__ */ new Map();
|
|
32667
|
+
for (const component of extraction.components) {
|
|
32668
|
+
if (!component.sourcePath) continue;
|
|
32669
|
+
const components = componentsBySourcePath.get(component.sourcePath) ?? [];
|
|
32670
|
+
components.push(component);
|
|
32671
|
+
componentsBySourcePath.set(component.sourcePath, components);
|
|
32672
|
+
}
|
|
32673
|
+
for (const filePath of sourceFiles) {
|
|
32674
|
+
storeExtractCache(
|
|
32675
|
+
db,
|
|
32676
|
+
filePath,
|
|
32677
|
+
await hashFile(filePath),
|
|
32678
|
+
cacheVersion,
|
|
32679
|
+
componentsBySourcePath.get(filePath) ?? []
|
|
32680
|
+
);
|
|
32681
|
+
}
|
|
32682
|
+
}
|
|
31526
32683
|
const classifiedComponents = extraction.components.map(preClassifyComponent);
|
|
31527
32684
|
for (const exclusion of extraction.exclusions ?? []) {
|
|
31528
32685
|
getDebugLogger().event("filter", "extract.excluded", { ...exclusion });
|
|
@@ -31546,9 +32703,28 @@ function registerInternalExtractCommand(program) {
|
|
|
31546
32703
|
storeRawComponents(db, sessionId2, validatedComponents);
|
|
31547
32704
|
process.stdout.write(`session=${sessionId2}
|
|
31548
32705
|
`);
|
|
31549
|
-
let sourceCallSiteEvidence = [];
|
|
31550
|
-
let sourceCallSiteRejections = [];
|
|
31551
32706
|
{
|
|
32707
|
+
const sources = resolveCompositionSources({
|
|
32708
|
+
...opts,
|
|
32709
|
+
noCache
|
|
32710
|
+
});
|
|
32711
|
+
const { overrides: promptOverrides, errors: promptErrors } = parsePromptOverrides(opts.prompt ?? []);
|
|
32712
|
+
for (const err of promptErrors) {
|
|
32713
|
+
process.stderr.write(`Error: ${err}
|
|
32714
|
+
`);
|
|
32715
|
+
process.exit(1);
|
|
32716
|
+
}
|
|
32717
|
+
let compositionPrompt;
|
|
32718
|
+
const compositionOverride = promptOverrides.get("composition");
|
|
32719
|
+
if (compositionOverride) {
|
|
32720
|
+
try {
|
|
32721
|
+
compositionPrompt = await resolvePromptOverride(compositionOverride);
|
|
32722
|
+
} catch (e) {
|
|
32723
|
+
process.stderr.write(`Error: ${e instanceof Error ? e.message : String(e)}
|
|
32724
|
+
`);
|
|
32725
|
+
process.exit(1);
|
|
32726
|
+
}
|
|
32727
|
+
}
|
|
31552
32728
|
{
|
|
31553
32729
|
const emitCompositionProgress = (phase) => {
|
|
31554
32730
|
if (!process.stdout.isTTY) process.stderr.write(`progress=composition:${phase}
|
|
@@ -31556,18 +32732,62 @@ function registerInternalExtractCommand(program) {
|
|
|
31556
32732
|
};
|
|
31557
32733
|
emitCompositionProgress("resolving");
|
|
31558
32734
|
const allFiles = await readCandidateFiles(validatedComponents, sourceFiles);
|
|
32735
|
+
const selectedCandidates = selectCandidateFiles(allFiles).map((c2) => ({ path: c2.path, content: c2.content }));
|
|
32736
|
+
const capped = capCandidatesToPromptBudget(selectedCandidates);
|
|
32737
|
+
const promptFiles = capped.kept;
|
|
32738
|
+
if (capped.dropped.length > 0) {
|
|
32739
|
+
process.stderr.write(
|
|
32740
|
+
`Warning: composition \u2014 ${capped.dropped.length} candidate file(s) omitted from the agent prompt to fit the context budget; resolution runs on the ${promptFiles.length} highest-value files.
|
|
32741
|
+
`
|
|
32742
|
+
);
|
|
32743
|
+
}
|
|
31559
32744
|
const runtimeFiles = allFiles.map((c2) => ({ path: c2.path, content: c2.content }));
|
|
32745
|
+
const resolverAgent = resolveCompositionAgentName(opts.agent);
|
|
31560
32746
|
const componentNameSet = new Set(validatedComponents.map((c2) => c2.name));
|
|
32747
|
+
const cacheVersion = await getCliCacheVersion();
|
|
32748
|
+
let lastAgentExitCode = 0;
|
|
32749
|
+
const spawnAgent = async (prompt) => {
|
|
32750
|
+
const res = await runAgent({
|
|
32751
|
+
agent: resolverAgent,
|
|
32752
|
+
prompt,
|
|
32753
|
+
timeoutMs: 12e4,
|
|
32754
|
+
promptViaStdin: true,
|
|
32755
|
+
onDebugEvent: (name, payload) => getDebugLogger().event("agent", name, payload)
|
|
32756
|
+
});
|
|
32757
|
+
lastAgentExitCode = res.exitCode;
|
|
32758
|
+
if (res.exitCode !== 0 && res.stderr.trim()) {
|
|
32759
|
+
process.stderr.write(`Warning: composition \u2014 agent exited ${res.exitCode}: ${res.stderr.trim()}
|
|
32760
|
+
`);
|
|
32761
|
+
}
|
|
32762
|
+
return res.stdout;
|
|
32763
|
+
};
|
|
31561
32764
|
const manifestDocEdges = collectManifestDocEdges(runtimeFiles, validatedComponents, componentNameSet);
|
|
31562
32765
|
const extraEdges = manifestDocEdges;
|
|
31563
|
-
const
|
|
31564
|
-
|
|
31565
|
-
|
|
31566
|
-
|
|
32766
|
+
const agentCacheKey = buildCompositionInputHash({
|
|
32767
|
+
files: promptFiles,
|
|
32768
|
+
agent: resolverAgent
|
|
32769
|
+
});
|
|
32770
|
+
const result = await resolveMapping({
|
|
31567
32771
|
components: validatedComponents,
|
|
31568
32772
|
...extraEdges.length > 0 ? { extraEdges } : {},
|
|
31569
|
-
|
|
31570
|
-
|
|
32773
|
+
forceAgent: sources.forceAgent,
|
|
32774
|
+
files: promptFiles,
|
|
32775
|
+
...compositionPrompt ? { promptOverride: compositionPrompt } : {},
|
|
32776
|
+
runAgentFn: async ({ prompt }) => {
|
|
32777
|
+
if (!noCache && !opts.compositionRefresh) {
|
|
32778
|
+
const cached = lookupCompositionCache(db, agentCacheKey, cacheVersion);
|
|
32779
|
+
if (cached !== null) {
|
|
32780
|
+
emitCompositionProgress("cache-hit");
|
|
32781
|
+
return cached;
|
|
32782
|
+
}
|
|
32783
|
+
}
|
|
32784
|
+
emitCompositionProgress(`agent:${resolverAgent}`);
|
|
32785
|
+
const stdout = await spawnAgent(prompt);
|
|
32786
|
+
if (lastAgentExitCode === 0) {
|
|
32787
|
+
storeCompositionCache(db, agentCacheKey, cacheVersion, stdout);
|
|
32788
|
+
}
|
|
32789
|
+
return stdout;
|
|
32790
|
+
}
|
|
31571
32791
|
});
|
|
31572
32792
|
emitCompositionProgress("done");
|
|
31573
32793
|
for (const w of result.warnings) process.stderr.write(`Warning: composition \u2014 ${w}
|
|
@@ -31597,13 +32817,7 @@ function registerInternalExtractCommand(program) {
|
|
|
31597
32817
|
sessionId2,
|
|
31598
32818
|
sourceFiles.map((f) => relative2(projectRoot, f))
|
|
31599
32819
|
);
|
|
31600
|
-
await retryDatabaseWrite(
|
|
31601
|
-
() => updateStep(db, stepId, "complete", {
|
|
31602
|
-
sessionId: sessionId2,
|
|
31603
|
-
compositionEvidence: JSON.stringify(sourceCallSiteEvidence),
|
|
31604
|
-
compositionRejections: JSON.stringify(sourceCallSiteRejections)
|
|
31605
|
-
})
|
|
31606
|
-
);
|
|
32820
|
+
await retryDatabaseWrite(() => updateStep(db, stepId, "complete", { sessionId: sessionId2 }));
|
|
31607
32821
|
enrichCommandResult({ extracted_component_count: validatedComponents.length });
|
|
31608
32822
|
db.close();
|
|
31609
32823
|
const allWarnings = [...extraction.warnings, ...filterWarnings];
|
|
@@ -31625,12 +32839,18 @@ var SCANNED_FILE_EXTENSIONS, DENYLIST_GATED_EXTENSIONS, DENYLISTED_EXACT_FILE_NA
|
|
|
31625
32839
|
var init_extract_command = __esm({
|
|
31626
32840
|
"packages/experience-design-system-cli-legacy/src/analyze/extract-command.ts"() {
|
|
31627
32841
|
"use strict";
|
|
32842
|
+
init_agent_model_options();
|
|
31628
32843
|
init_src2();
|
|
31629
32844
|
init_db();
|
|
32845
|
+
init_cache_keys();
|
|
31630
32846
|
init_cycle_detection();
|
|
31631
32847
|
init_resolve_mapping();
|
|
32848
|
+
init_resolve_mapping_cli();
|
|
32849
|
+
init_candidate_files();
|
|
32850
|
+
init_composition_cache_key();
|
|
31632
32851
|
init_manifest_doc_evidence();
|
|
31633
|
-
|
|
32852
|
+
init_prompt_overrides();
|
|
32853
|
+
init_src();
|
|
31634
32854
|
init_analytics();
|
|
31635
32855
|
init_debug_logger();
|
|
31636
32856
|
SCANNED_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".astro", ".js", ".jsx", ".svelte", ".ts", ".tsx", ".vue"]);
|
|
@@ -31724,9 +32944,9 @@ __export(program_exports, {
|
|
|
31724
32944
|
runBuild: () => runBuild
|
|
31725
32945
|
});
|
|
31726
32946
|
import { spawn as spawn7 } from "node:child_process";
|
|
31727
|
-
import { fileURLToPath as
|
|
31728
|
-
import { dirname as
|
|
31729
|
-
import { readFileSync as
|
|
32947
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
32948
|
+
import { dirname as dirname19, join as join29, resolve as resolve21 } from "node:path";
|
|
32949
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
31730
32950
|
import { Command } from "commander";
|
|
31731
32951
|
async function runBuild(opts) {
|
|
31732
32952
|
return new Promise((resolvePromise) => {
|
|
@@ -31755,7 +32975,7 @@ function resolveBedrockFromAncestors(actionCommand) {
|
|
|
31755
32975
|
}
|
|
31756
32976
|
function registerBuildCommand(program) {
|
|
31757
32977
|
program.command("build").description("Rebuild from source and re-link exo/experiences binaries to this build").helpOption(false).action(async () => {
|
|
31758
|
-
const pkgRoot =
|
|
32978
|
+
const pkgRoot = resolve21(dirname19(fileURLToPath4(import.meta.url)), "..", "..");
|
|
31759
32979
|
process.stderr.write("\u2699 Building from source...\n");
|
|
31760
32980
|
const { exitCode } = await runBuild({
|
|
31761
32981
|
spawnFn: () => spawn7("pnpm", ["build"], { cwd: pkgRoot, stdio: "inherit" }),
|
|
@@ -31825,7 +33045,7 @@ var init_program = __esm({
|
|
|
31825
33045
|
init_analytics();
|
|
31826
33046
|
init_credentials_store();
|
|
31827
33047
|
init_cli_path();
|
|
31828
|
-
pkg3 = JSON.parse(
|
|
33048
|
+
pkg3 = JSON.parse(readFileSync11(join29(findPkgRoot(), "package.json"), "utf8"));
|
|
31829
33049
|
}
|
|
31830
33050
|
});
|
|
31831
33051
|
|