@contentful/experience-design-system-cli 2.35.1-dev-build-a2149178.0 → 2.35.1-dev-build-925d6206.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";
|
|
@@ -10308,6 +10365,41 @@ var init_read3 = __esm({
|
|
|
10308
10365
|
}
|
|
10309
10366
|
});
|
|
10310
10367
|
|
|
10368
|
+
// packages/experience-design-system-cli-legacy/src/session/core/components/hash-component-shape.ts
|
|
10369
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
10370
|
+
function hashComponentShape(component) {
|
|
10371
|
+
const payload = {
|
|
10372
|
+
framework: component.framework,
|
|
10373
|
+
name: component.name,
|
|
10374
|
+
source: component.source,
|
|
10375
|
+
props: component.props.map((p) => ({
|
|
10376
|
+
name: p.name,
|
|
10377
|
+
type: p.type
|
|
10378
|
+
})),
|
|
10379
|
+
slots: component.slots.map((s) => ({
|
|
10380
|
+
name: s.name,
|
|
10381
|
+
isDefault: s.isDefault
|
|
10382
|
+
}))
|
|
10383
|
+
};
|
|
10384
|
+
return createHash2("sha256").update(JSON.stringify(payload)).digest("hex");
|
|
10385
|
+
}
|
|
10386
|
+
var init_hash_component_shape = __esm({
|
|
10387
|
+
"packages/experience-design-system-cli-legacy/src/session/core/components/hash-component-shape.ts"() {
|
|
10388
|
+
"use strict";
|
|
10389
|
+
}
|
|
10390
|
+
});
|
|
10391
|
+
|
|
10392
|
+
// packages/experience-design-system-cli-legacy/src/session/core/tokens/hash-token-content.ts
|
|
10393
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
10394
|
+
function hashTokenContent(rawTokenContent) {
|
|
10395
|
+
return createHash3("sha256").update(rawTokenContent.trim()).digest("hex");
|
|
10396
|
+
}
|
|
10397
|
+
var init_hash_token_content = __esm({
|
|
10398
|
+
"packages/experience-design-system-cli-legacy/src/session/core/tokens/hash-token-content.ts"() {
|
|
10399
|
+
"use strict";
|
|
10400
|
+
}
|
|
10401
|
+
});
|
|
10402
|
+
|
|
10311
10403
|
// packages/experience-design-system-cli-legacy/src/session/repositories/tokens/write.ts
|
|
10312
10404
|
function deleteRawTokensForSession(db, sessionId2) {
|
|
10313
10405
|
db.prepare("DELETE FROM raw_token_groups WHERE session_id = ?").run(sessionId2);
|
|
@@ -10471,17 +10563,47 @@ var init_replace_raw_prop_token_paths = __esm({
|
|
|
10471
10563
|
}
|
|
10472
10564
|
});
|
|
10473
10565
|
|
|
10566
|
+
// packages/experience-design-system-cli-legacy/src/session/cache-keys.ts
|
|
10567
|
+
var cache_keys_exports = {};
|
|
10568
|
+
__export(cache_keys_exports, {
|
|
10569
|
+
hashContent: () => hashContent,
|
|
10570
|
+
hashFile: () => hashFile,
|
|
10571
|
+
hashPromptForSkill: () => hashPromptForSkill
|
|
10572
|
+
});
|
|
10573
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
10574
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
10575
|
+
import { resolve as resolve8 } from "node:path";
|
|
10576
|
+
function hashContent(content) {
|
|
10577
|
+
return createHash4("sha256").update(content).digest("hex");
|
|
10578
|
+
}
|
|
10579
|
+
async function hashFile(filePath) {
|
|
10580
|
+
const content = await readFile7(filePath, "utf8");
|
|
10581
|
+
return hashContent(content);
|
|
10582
|
+
}
|
|
10583
|
+
async function hashPromptForSkill(skill, agent, model, skillPathOverride, extraInputs = [], skillContentOverride) {
|
|
10584
|
+
const promptHash = skillContentOverride ? hashContent(skillContentOverride) : skillPathOverride ? await hashFile(resolve8(skillPathOverride)) : await hashFile(resolveSkillPath(skill));
|
|
10585
|
+
const extraSegment = extraInputs.length > 0 ? `|${extraInputs.join("|")}` : "";
|
|
10586
|
+
return hashContent(`${promptHash}|${agent}|${model ?? ""}${extraSegment}`);
|
|
10587
|
+
}
|
|
10588
|
+
var init_cache_keys = __esm({
|
|
10589
|
+
"packages/experience-design-system-cli-legacy/src/session/cache-keys.ts"() {
|
|
10590
|
+
"use strict";
|
|
10591
|
+
init_src();
|
|
10592
|
+
}
|
|
10593
|
+
});
|
|
10594
|
+
|
|
10474
10595
|
// packages/experience-design-system-cli-legacy/src/session/db.ts
|
|
10475
10596
|
import { DatabaseSync } from "node:sqlite";
|
|
10476
10597
|
import { mkdirSync as mkdirSync2, readFileSync as readFileSync5 } from "node:fs";
|
|
10477
|
-
import { readFile as
|
|
10598
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
10599
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
10478
10600
|
import { homedir as homedir3 } from "node:os";
|
|
10479
|
-
import { dirname as dirname14, resolve as
|
|
10601
|
+
import { dirname as dirname14, resolve as resolve9 } from "node:path";
|
|
10480
10602
|
function getPipelineDbPath() {
|
|
10481
10603
|
if (process.env.EDS_PIPELINE_DB_PATH) {
|
|
10482
|
-
return
|
|
10604
|
+
return resolve9(process.env.EDS_PIPELINE_DB_PATH);
|
|
10483
10605
|
}
|
|
10484
|
-
return
|
|
10606
|
+
return resolve9(homedir3(), ".contentful", "experience-design-system-cli", "pipeline.db");
|
|
10485
10607
|
}
|
|
10486
10608
|
function openPipelineDb(dbPath) {
|
|
10487
10609
|
const path = dbPath ?? getPipelineDbPath();
|
|
@@ -10615,8 +10737,134 @@ function applyDbMigrations(db) {
|
|
|
10615
10737
|
if (!rawSlotColsForRationale.some((c2) => c2.name === "rationale")) {
|
|
10616
10738
|
db.exec("ALTER TABLE raw_slots ADD COLUMN rationale TEXT");
|
|
10617
10739
|
}
|
|
10618
|
-
|
|
10619
|
-
|
|
10740
|
+
const hasExtractCache = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='extract_cache'`).all();
|
|
10741
|
+
if (hasExtractCache.length === 0) {
|
|
10742
|
+
db.exec(`
|
|
10743
|
+
CREATE TABLE extract_cache (
|
|
10744
|
+
file_path TEXT NOT NULL,
|
|
10745
|
+
file_hash TEXT NOT NULL,
|
|
10746
|
+
cli_version TEXT NOT NULL,
|
|
10747
|
+
created_at TEXT NOT NULL,
|
|
10748
|
+
updated_at TEXT NOT NULL,
|
|
10749
|
+
components_json TEXT NOT NULL,
|
|
10750
|
+
PRIMARY KEY (file_hash, cli_version)
|
|
10751
|
+
);
|
|
10752
|
+
CREATE INDEX idx_extract_cache_file ON extract_cache(file_path);
|
|
10753
|
+
`);
|
|
10754
|
+
}
|
|
10755
|
+
const hasSelectCache = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='select_cache'`).all();
|
|
10756
|
+
if (hasSelectCache.length === 0) {
|
|
10757
|
+
db.exec(`
|
|
10758
|
+
CREATE TABLE select_cache (
|
|
10759
|
+
component_hash TEXT NOT NULL,
|
|
10760
|
+
prompt_hash TEXT NOT NULL,
|
|
10761
|
+
cli_version TEXT NOT NULL,
|
|
10762
|
+
decision TEXT NOT NULL CHECK (decision IN ('accepted','rejected')),
|
|
10763
|
+
reason TEXT,
|
|
10764
|
+
created_at TEXT NOT NULL,
|
|
10765
|
+
updated_at TEXT NOT NULL,
|
|
10766
|
+
PRIMARY KEY (component_hash, prompt_hash, cli_version)
|
|
10767
|
+
);
|
|
10768
|
+
`);
|
|
10769
|
+
}
|
|
10770
|
+
const tables = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='generation_cache'`).all();
|
|
10771
|
+
if (tables.length === 0) {
|
|
10772
|
+
db.exec(`
|
|
10773
|
+
CREATE TABLE generation_cache (
|
|
10774
|
+
input_hash TEXT NOT NULL,
|
|
10775
|
+
entity_type TEXT NOT NULL CHECK (entity_type IN ('component', 'token_set', 'token_mapping')),
|
|
10776
|
+
entity_id TEXT NOT NULL,
|
|
10777
|
+
source_session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
10778
|
+
human_edited INTEGER NOT NULL DEFAULT 0 CHECK (human_edited IN (0, 1)),
|
|
10779
|
+
created_at TEXT NOT NULL,
|
|
10780
|
+
updated_at TEXT NOT NULL,
|
|
10781
|
+
PRIMARY KEY (input_hash, entity_type, entity_id)
|
|
10782
|
+
);
|
|
10783
|
+
CREATE INDEX idx_generation_cache_entity ON generation_cache(entity_type, entity_id);
|
|
10784
|
+
CREATE INDEX idx_generation_cache_session ON generation_cache(source_session_id);
|
|
10785
|
+
`);
|
|
10786
|
+
}
|
|
10787
|
+
const genCacheCols = db.prepare(`PRAGMA table_info(generation_cache)`).all();
|
|
10788
|
+
const hasPromptHash = genCacheCols.some((c2) => c2.name === "prompt_hash");
|
|
10789
|
+
const oldPkCols = genCacheCols.filter((c2) => c2.pk > 0).map((c2) => c2.name);
|
|
10790
|
+
const promptHashInPk = oldPkCols.includes("prompt_hash");
|
|
10791
|
+
if (!hasPromptHash) {
|
|
10792
|
+
db.exec(`ALTER TABLE generation_cache ADD COLUMN prompt_hash TEXT NOT NULL DEFAULT ''`);
|
|
10793
|
+
}
|
|
10794
|
+
if (!promptHashInPk) {
|
|
10795
|
+
db.exec("BEGIN");
|
|
10796
|
+
try {
|
|
10797
|
+
db.exec(`
|
|
10798
|
+
CREATE TABLE generation_cache__new (
|
|
10799
|
+
input_hash TEXT NOT NULL,
|
|
10800
|
+
entity_type TEXT NOT NULL CHECK (entity_type IN ('component', 'token_set', 'token_mapping')),
|
|
10801
|
+
entity_id TEXT NOT NULL,
|
|
10802
|
+
source_session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
10803
|
+
human_edited INTEGER NOT NULL DEFAULT 0 CHECK (human_edited IN (0, 1)),
|
|
10804
|
+
created_at TEXT NOT NULL,
|
|
10805
|
+
updated_at TEXT NOT NULL,
|
|
10806
|
+
prompt_hash TEXT NOT NULL DEFAULT '',
|
|
10807
|
+
PRIMARY KEY (input_hash, prompt_hash, entity_type, entity_id)
|
|
10808
|
+
);
|
|
10809
|
+
INSERT INTO generation_cache__new
|
|
10810
|
+
(input_hash, entity_type, entity_id, source_session_id, human_edited, created_at, updated_at, prompt_hash)
|
|
10811
|
+
SELECT input_hash, entity_type, entity_id, source_session_id, human_edited, created_at, updated_at, prompt_hash
|
|
10812
|
+
FROM generation_cache;
|
|
10813
|
+
DROP TABLE generation_cache;
|
|
10814
|
+
ALTER TABLE generation_cache__new RENAME TO generation_cache;
|
|
10815
|
+
CREATE INDEX IF NOT EXISTS idx_generation_cache_entity ON generation_cache(entity_type, entity_id);
|
|
10816
|
+
CREATE INDEX IF NOT EXISTS idx_generation_cache_session ON generation_cache(source_session_id);
|
|
10817
|
+
`);
|
|
10818
|
+
db.exec("COMMIT");
|
|
10819
|
+
} catch (e) {
|
|
10820
|
+
db.exec("ROLLBACK");
|
|
10821
|
+
throw e;
|
|
10822
|
+
}
|
|
10823
|
+
}
|
|
10824
|
+
const genCacheTableSql = db.prepare(`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'generation_cache'`).get();
|
|
10825
|
+
const hasTokenMappingEntityType = genCacheTableSql?.sql.includes("'token_mapping'") ?? true;
|
|
10826
|
+
if (!hasTokenMappingEntityType) {
|
|
10827
|
+
db.exec("BEGIN");
|
|
10828
|
+
try {
|
|
10829
|
+
db.exec(`
|
|
10830
|
+
CREATE TABLE generation_cache__new2 (
|
|
10831
|
+
input_hash TEXT NOT NULL,
|
|
10832
|
+
entity_type TEXT NOT NULL CHECK (entity_type IN ('component', 'token_set', 'token_mapping')),
|
|
10833
|
+
entity_id TEXT NOT NULL,
|
|
10834
|
+
source_session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
10835
|
+
human_edited INTEGER NOT NULL DEFAULT 0 CHECK (human_edited IN (0, 1)),
|
|
10836
|
+
created_at TEXT NOT NULL,
|
|
10837
|
+
updated_at TEXT NOT NULL,
|
|
10838
|
+
prompt_hash TEXT NOT NULL DEFAULT '',
|
|
10839
|
+
PRIMARY KEY (input_hash, prompt_hash, entity_type, entity_id)
|
|
10840
|
+
);
|
|
10841
|
+
INSERT INTO generation_cache__new2
|
|
10842
|
+
(input_hash, entity_type, entity_id, source_session_id, human_edited, created_at, updated_at, prompt_hash)
|
|
10843
|
+
SELECT input_hash, entity_type, entity_id, source_session_id, human_edited, created_at, updated_at, prompt_hash
|
|
10844
|
+
FROM generation_cache;
|
|
10845
|
+
DROP TABLE generation_cache;
|
|
10846
|
+
ALTER TABLE generation_cache__new2 RENAME TO generation_cache;
|
|
10847
|
+
CREATE INDEX IF NOT EXISTS idx_generation_cache_entity ON generation_cache(entity_type, entity_id);
|
|
10848
|
+
CREATE INDEX IF NOT EXISTS idx_generation_cache_session ON generation_cache(source_session_id);
|
|
10849
|
+
`);
|
|
10850
|
+
db.exec("COMMIT");
|
|
10851
|
+
} catch (e) {
|
|
10852
|
+
db.exec("ROLLBACK");
|
|
10853
|
+
throw e;
|
|
10854
|
+
}
|
|
10855
|
+
}
|
|
10856
|
+
const hasCompositionCache = db.prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='composition_cache'`).all();
|
|
10857
|
+
if (hasCompositionCache.length === 0) {
|
|
10858
|
+
db.exec(`
|
|
10859
|
+
CREATE TABLE composition_cache (
|
|
10860
|
+
input_hash TEXT NOT NULL,
|
|
10861
|
+
cli_version TEXT NOT NULL,
|
|
10862
|
+
agent_output TEXT NOT NULL,
|
|
10863
|
+
created_at TEXT NOT NULL,
|
|
10864
|
+
updated_at TEXT NOT NULL,
|
|
10865
|
+
PRIMARY KEY (input_hash, cli_version)
|
|
10866
|
+
);
|
|
10867
|
+
`);
|
|
10620
10868
|
}
|
|
10621
10869
|
}
|
|
10622
10870
|
function loadComponentReviewMetadata(db, sessionId2, componentName) {
|
|
@@ -11156,16 +11404,16 @@ function extractRelativeImportPaths(sourceText) {
|
|
|
11156
11404
|
return [...specifiers];
|
|
11157
11405
|
}
|
|
11158
11406
|
async function resolveRelativeImport(specifier, fromDir) {
|
|
11159
|
-
const basePath =
|
|
11407
|
+
const basePath = resolve9(fromDir, specifier);
|
|
11160
11408
|
const candidates = [
|
|
11161
11409
|
basePath,
|
|
11162
11410
|
...rewrittenSourcePaths(basePath),
|
|
11163
11411
|
...SIBLING_FILE_EXTENSIONS.map((ext) => `${basePath}${ext}`),
|
|
11164
|
-
...SIBLING_FILE_EXTENSIONS.map((ext) =>
|
|
11412
|
+
...SIBLING_FILE_EXTENSIONS.map((ext) => resolve9(basePath, `index${ext}`))
|
|
11165
11413
|
];
|
|
11166
11414
|
for (const candidate of candidates) {
|
|
11167
11415
|
try {
|
|
11168
|
-
await
|
|
11416
|
+
await readFile8(candidate, "utf8");
|
|
11169
11417
|
return candidate;
|
|
11170
11418
|
} catch {
|
|
11171
11419
|
}
|
|
@@ -11181,7 +11429,7 @@ async function resolveImportSpecifiers(sourceText, fromDir) {
|
|
|
11181
11429
|
return resolvedPaths;
|
|
11182
11430
|
}
|
|
11183
11431
|
async function loadSiblingFiles(sourceText, sourcePath, propNames, candidateTypeNames = []) {
|
|
11184
|
-
const visited = /* @__PURE__ */ new Set([
|
|
11432
|
+
const visited = /* @__PURE__ */ new Set([resolve9(sourcePath)]);
|
|
11185
11433
|
const discovered = [];
|
|
11186
11434
|
let frontier = [{ text: sourceText, dir: dirname14(sourcePath) }];
|
|
11187
11435
|
for (let hop = 0; hop < MAX_SIBLING_DEPTH && discovered.length < MAX_SIBLING_CANDIDATES_EXPLORED; hop++) {
|
|
@@ -11195,7 +11443,7 @@ async function loadSiblingFiles(sourceText, sourcePath, propNames, candidateType
|
|
|
11195
11443
|
if (discovered.length >= MAX_SIBLING_CANDIDATES_EXPLORED) break;
|
|
11196
11444
|
let content;
|
|
11197
11445
|
try {
|
|
11198
|
-
content = await
|
|
11446
|
+
content = await readFile8(resolvedPath, "utf8");
|
|
11199
11447
|
} catch {
|
|
11200
11448
|
continue;
|
|
11201
11449
|
}
|
|
@@ -11232,7 +11480,7 @@ async function loadComponentSourceRef(name, sourcePath, propNames = [], propType
|
|
|
11232
11480
|
let truncatedSiblingCount = 0;
|
|
11233
11481
|
const usesNotShown = /* @__PURE__ */ new Set();
|
|
11234
11482
|
try {
|
|
11235
|
-
const rawText = await
|
|
11483
|
+
const rawText = await readFile8(sourcePath, "utf8");
|
|
11236
11484
|
let siblingUsesNotShown;
|
|
11237
11485
|
let declaredTypeNames;
|
|
11238
11486
|
({
|
|
@@ -11668,6 +11916,108 @@ function backfillUnclassifiedProps(db, sessionId2) {
|
|
|
11668
11916
|
).run(sessionId2, sessionId2);
|
|
11669
11917
|
return Number(withCategory.changes) + Number(withoutCategory.changes);
|
|
11670
11918
|
}
|
|
11919
|
+
function computeMapTokensInputHash(db, sessionId2, componentSourceRefs = []) {
|
|
11920
|
+
const props = db.prepare(
|
|
11921
|
+
`SELECT rc.name AS component_name, rp.name AS prop_name, rp.cdf_token_kind, rp.default_value
|
|
11922
|
+
FROM raw_props rp
|
|
11923
|
+
JOIN raw_components rc ON rc.session_id = rp.session_id AND rc.component_id = rp.component_id
|
|
11924
|
+
WHERE rp.session_id = ? AND rp.cdf_type = 'token' AND rp.cdf_category = 'design'
|
|
11925
|
+
ORDER BY rc.name, rp.name`
|
|
11926
|
+
).all(sessionId2);
|
|
11927
|
+
const tokens = db.prepare(`SELECT path, type FROM raw_tokens WHERE session_id = ? ORDER BY path`).all(sessionId2);
|
|
11928
|
+
const defaultMappings = db.prepare("SELECT raw_name, path, source FROM raw_token_name_paths WHERE session_id = ? ORDER BY raw_name").all(sessionId2);
|
|
11929
|
+
const payload = {
|
|
11930
|
+
props: props.map((p) => ({
|
|
11931
|
+
component: p.component_name,
|
|
11932
|
+
prop: p.prop_name,
|
|
11933
|
+
tokenKind: p.cdf_token_kind,
|
|
11934
|
+
rawDefault: p.default_value
|
|
11935
|
+
})),
|
|
11936
|
+
tokens,
|
|
11937
|
+
defaultMappings,
|
|
11938
|
+
// The agent's evidence, not just its inputs: a comment or allowlist edit
|
|
11939
|
+
// in a source file (or a sibling it reads) changes the correct answer
|
|
11940
|
+
// without touching props or tokens, so it must invalidate the cache too.
|
|
11941
|
+
sourceRefs: [...componentSourceRefs].sort((a, b) => a.component.localeCompare(b.component)).map((ref) => ({
|
|
11942
|
+
component: ref.component,
|
|
11943
|
+
content: ref.content,
|
|
11944
|
+
siblingFiles: (ref.siblingFiles ?? []).map((s) => ({ path: s.path, content: s.content })).sort((a, b) => a.path.localeCompare(b.path)),
|
|
11945
|
+
usesNotShown: [...ref.usesNotShown ?? []].sort()
|
|
11946
|
+
}))
|
|
11947
|
+
};
|
|
11948
|
+
return createHash5("sha256").update(JSON.stringify(payload)).digest("hex");
|
|
11949
|
+
}
|
|
11950
|
+
function lookupCache(db, inputHash, entityType, entityId, promptHash = "") {
|
|
11951
|
+
const row = db.prepare(
|
|
11952
|
+
`SELECT input_hash, entity_type, entity_id, source_session_id, human_edited, created_at, updated_at, prompt_hash
|
|
11953
|
+
FROM generation_cache
|
|
11954
|
+
WHERE input_hash = ? AND entity_type = ? AND entity_id = ? AND prompt_hash = ?`
|
|
11955
|
+
).get(inputHash, entityType, entityId, promptHash);
|
|
11956
|
+
if (!row) return null;
|
|
11957
|
+
return {
|
|
11958
|
+
inputHash: row.input_hash,
|
|
11959
|
+
entityType: row.entity_type,
|
|
11960
|
+
entityId: row.entity_id,
|
|
11961
|
+
sourceSessionId: row.source_session_id,
|
|
11962
|
+
humanEdited: row.human_edited === 1,
|
|
11963
|
+
promptHash: row.prompt_hash,
|
|
11964
|
+
createdAt: row.created_at,
|
|
11965
|
+
updatedAt: row.updated_at
|
|
11966
|
+
};
|
|
11967
|
+
}
|
|
11968
|
+
function lookupCacheByEntity(db, entityType, entityId) {
|
|
11969
|
+
const row = db.prepare(
|
|
11970
|
+
`SELECT input_hash, entity_type, entity_id, source_session_id, human_edited, created_at, updated_at, prompt_hash
|
|
11971
|
+
FROM generation_cache
|
|
11972
|
+
WHERE entity_type = ? AND entity_id = ?
|
|
11973
|
+
ORDER BY updated_at DESC LIMIT 1`
|
|
11974
|
+
).get(entityType, entityId);
|
|
11975
|
+
if (!row) return null;
|
|
11976
|
+
return {
|
|
11977
|
+
inputHash: row.input_hash,
|
|
11978
|
+
entityType: row.entity_type,
|
|
11979
|
+
entityId: row.entity_id,
|
|
11980
|
+
sourceSessionId: row.source_session_id,
|
|
11981
|
+
humanEdited: row.human_edited === 1,
|
|
11982
|
+
promptHash: row.prompt_hash,
|
|
11983
|
+
createdAt: row.created_at,
|
|
11984
|
+
updatedAt: row.updated_at
|
|
11985
|
+
};
|
|
11986
|
+
}
|
|
11987
|
+
function storeCache(db, inputHash, entityType, entityId, sourceSessionId, humanEdited, promptHash = "") {
|
|
11988
|
+
storeCaches(db, [{ inputHash, entityType, entityId, sourceSessionId, humanEdited, promptHash }]);
|
|
11989
|
+
}
|
|
11990
|
+
function storeCaches(db, entries) {
|
|
11991
|
+
if (entries.length === 0) return;
|
|
11992
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
11993
|
+
const insert = db.prepare(
|
|
11994
|
+
`INSERT INTO generation_cache (input_hash, entity_type, entity_id, source_session_id, human_edited, created_at, updated_at, prompt_hash)
|
|
11995
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
11996
|
+
ON CONFLICT(input_hash, prompt_hash, entity_type, entity_id) DO UPDATE SET
|
|
11997
|
+
source_session_id = excluded.source_session_id,
|
|
11998
|
+
human_edited = CASE WHEN generation_cache.human_edited = 1 THEN 1 ELSE excluded.human_edited END,
|
|
11999
|
+
updated_at = excluded.updated_at`
|
|
12000
|
+
);
|
|
12001
|
+
db.exec("BEGIN");
|
|
12002
|
+
try {
|
|
12003
|
+
for (const entry of entries) {
|
|
12004
|
+
insert.run(
|
|
12005
|
+
entry.inputHash,
|
|
12006
|
+
entry.entityType,
|
|
12007
|
+
entry.entityId,
|
|
12008
|
+
entry.sourceSessionId,
|
|
12009
|
+
entry.humanEdited ? 1 : 0,
|
|
12010
|
+
now,
|
|
12011
|
+
now,
|
|
12012
|
+
entry.promptHash ?? ""
|
|
12013
|
+
);
|
|
12014
|
+
}
|
|
12015
|
+
db.exec("COMMIT");
|
|
12016
|
+
} catch (e) {
|
|
12017
|
+
db.exec("ROLLBACK");
|
|
12018
|
+
throw e;
|
|
12019
|
+
}
|
|
12020
|
+
}
|
|
11671
12021
|
function storeScannedFiles(db, sessionId2, filePaths) {
|
|
11672
12022
|
db.exec("BEGIN");
|
|
11673
12023
|
try {
|
|
@@ -11750,7 +12100,105 @@ function filterUnknownSlotAllowedComponents(db, sessionId2, allowedComponentName
|
|
|
11750
12100
|
}
|
|
11751
12101
|
return unknown;
|
|
11752
12102
|
}
|
|
11753
|
-
function
|
|
12103
|
+
function copyComponentFromCache(db, sourceSessionId, targetSessionId, componentId, manageTransaction = true, options = {}) {
|
|
12104
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12105
|
+
if (manageTransaction) db.exec("BEGIN");
|
|
12106
|
+
try {
|
|
12107
|
+
const srcComp = db.prepare(
|
|
12108
|
+
`SELECT description, status, component_description_rationale, props_rationale, slots_rationale
|
|
12109
|
+
FROM raw_components WHERE session_id = ? AND component_id = ?`
|
|
12110
|
+
).get(sourceSessionId, componentId);
|
|
12111
|
+
if (srcComp) {
|
|
12112
|
+
db.prepare(
|
|
12113
|
+
`UPDATE raw_components
|
|
12114
|
+
SET description = ?, status = ?, component_description_rationale = ?, props_rationale = ?, slots_rationale = ?, extracted_at = ?
|
|
12115
|
+
WHERE session_id = ? AND component_id = ?`
|
|
12116
|
+
).run(
|
|
12117
|
+
srcComp.description,
|
|
12118
|
+
srcComp.status,
|
|
12119
|
+
srcComp.component_description_rationale,
|
|
12120
|
+
srcComp.props_rationale,
|
|
12121
|
+
srcComp.slots_rationale,
|
|
12122
|
+
now,
|
|
12123
|
+
targetSessionId,
|
|
12124
|
+
componentId
|
|
12125
|
+
);
|
|
12126
|
+
}
|
|
12127
|
+
const srcProps = db.prepare(
|
|
12128
|
+
`SELECT name, cdf_type, cdf_category, cdf_token_kind, required, description, default_value, rationale
|
|
12129
|
+
FROM raw_props WHERE session_id = ? AND component_id = ?`
|
|
12130
|
+
).all(sourceSessionId, componentId);
|
|
12131
|
+
for (const p of srcProps) {
|
|
12132
|
+
db.prepare(
|
|
12133
|
+
`UPDATE raw_props SET cdf_type = ?, cdf_category = ?, cdf_token_kind = ?, required = ?, description = ?, default_value = ?, rationale = ?
|
|
12134
|
+
WHERE session_id = ? AND component_id = ? AND name = ?`
|
|
12135
|
+
).run(
|
|
12136
|
+
p.cdf_type,
|
|
12137
|
+
p.cdf_category,
|
|
12138
|
+
p.cdf_token_kind,
|
|
12139
|
+
p.required,
|
|
12140
|
+
p.description,
|
|
12141
|
+
p.default_value,
|
|
12142
|
+
p.rationale,
|
|
12143
|
+
targetSessionId,
|
|
12144
|
+
componentId,
|
|
12145
|
+
p.name
|
|
12146
|
+
);
|
|
12147
|
+
}
|
|
12148
|
+
db.prepare(`DELETE FROM raw_prop_allowed_values WHERE session_id = ? AND component_id = ?`).run(
|
|
12149
|
+
targetSessionId,
|
|
12150
|
+
componentId
|
|
12151
|
+
);
|
|
12152
|
+
const srcAV = db.prepare(
|
|
12153
|
+
`SELECT prop_name, position, value FROM raw_prop_allowed_values WHERE session_id = ? AND component_id = ?`
|
|
12154
|
+
).all(sourceSessionId, componentId);
|
|
12155
|
+
const insertAV = db.prepare(
|
|
12156
|
+
`INSERT INTO raw_prop_allowed_values (session_id, component_id, prop_name, position, value) VALUES (?, ?, ?, ?, ?)`
|
|
12157
|
+
);
|
|
12158
|
+
for (const av of srcAV) {
|
|
12159
|
+
insertAV.run(targetSessionId, componentId, av.prop_name, av.position, av.value);
|
|
12160
|
+
}
|
|
12161
|
+
const srcSlots = db.prepare(`SELECT name, required, description, rationale FROM raw_slots WHERE session_id = ? AND component_id = ?`).all(sourceSessionId, componentId);
|
|
12162
|
+
for (const s of srcSlots) {
|
|
12163
|
+
db.prepare(
|
|
12164
|
+
`UPDATE raw_slots SET required = ?, description = ?, rationale = ? WHERE session_id = ? AND component_id = ? AND name = ?`
|
|
12165
|
+
).run(s.required, s.description, s.rationale, targetSessionId, componentId, s.name);
|
|
12166
|
+
}
|
|
12167
|
+
db.prepare(`DELETE FROM raw_slot_allowed_components WHERE session_id = ? AND component_id = ?`).run(
|
|
12168
|
+
targetSessionId,
|
|
12169
|
+
componentId
|
|
12170
|
+
);
|
|
12171
|
+
const srcSAC = db.prepare(
|
|
12172
|
+
`SELECT slot_name, position, allowed_component FROM raw_slot_allowed_components WHERE session_id = ? AND component_id = ?`
|
|
12173
|
+
).all(sourceSessionId, componentId);
|
|
12174
|
+
const insertSAC = db.prepare(
|
|
12175
|
+
`INSERT INTO raw_slot_allowed_components (session_id, component_id, slot_name, allowed_component, position) VALUES (?, ?, ?, ?, ?)`
|
|
12176
|
+
);
|
|
12177
|
+
const allowedSAC = options.allowedComponentNames ? srcSAC.filter((sac) => options.allowedComponentNames.has(sac.allowed_component)) : srcSAC;
|
|
12178
|
+
for (const sac of allowedSAC) {
|
|
12179
|
+
insertSAC.run(targetSessionId, componentId, sac.slot_name, sac.allowed_component, sac.position);
|
|
12180
|
+
}
|
|
12181
|
+
db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(now, targetSessionId);
|
|
12182
|
+
if (manageTransaction) db.exec("COMMIT");
|
|
12183
|
+
} catch (e) {
|
|
12184
|
+
if (manageTransaction) db.exec("ROLLBACK");
|
|
12185
|
+
throw e;
|
|
12186
|
+
}
|
|
12187
|
+
}
|
|
12188
|
+
function copyComponentsFromCache(db, entries, options = {}) {
|
|
12189
|
+
if (entries.length === 0) return;
|
|
12190
|
+
db.exec("BEGIN");
|
|
12191
|
+
try {
|
|
12192
|
+
for (const entry of entries) {
|
|
12193
|
+
copyComponentFromCache(db, entry.sourceSessionId, entry.targetSessionId, entry.componentId, false, options);
|
|
12194
|
+
}
|
|
12195
|
+
db.exec("COMMIT");
|
|
12196
|
+
} catch (e) {
|
|
12197
|
+
db.exec("ROLLBACK");
|
|
12198
|
+
throw e;
|
|
12199
|
+
}
|
|
12200
|
+
}
|
|
12201
|
+
function copyTokensFromCache(db, sourceSessionId, targetSessionId) {
|
|
11754
12202
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
11755
12203
|
db.exec("BEGIN");
|
|
11756
12204
|
try {
|
|
@@ -11771,7 +12219,153 @@ function copyTokensBetweenSessions(db, sourceSessionId, targetSessionId) {
|
|
|
11771
12219
|
throw e;
|
|
11772
12220
|
}
|
|
11773
12221
|
}
|
|
11774
|
-
|
|
12222
|
+
function copyMapTokensFromCache(db, sourceSessionId, targetSessionId) {
|
|
12223
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12224
|
+
let copiedCount = 0;
|
|
12225
|
+
db.exec("BEGIN");
|
|
12226
|
+
try {
|
|
12227
|
+
const sourceRows = db.prepare(
|
|
12228
|
+
`SELECT rc.name AS component_name, rptp.prop_name, rptp.source, rptp.position, rptp.path
|
|
12229
|
+
FROM raw_prop_token_paths rptp
|
|
12230
|
+
JOIN raw_components rc ON rc.session_id = rptp.session_id AND rc.component_id = rptp.component_id
|
|
12231
|
+
WHERE rptp.session_id = ?
|
|
12232
|
+
ORDER BY rc.name, rptp.prop_name, rptp.position`
|
|
12233
|
+
).all(sourceSessionId);
|
|
12234
|
+
const targetComponents = db.prepare(`SELECT component_id, name FROM raw_components WHERE session_id = ?`).all(targetSessionId);
|
|
12235
|
+
const targetIdByName = new Map(targetComponents.map((c2) => [c2.name, c2.component_id]));
|
|
12236
|
+
const targetProps = new Set(
|
|
12237
|
+
db.prepare(`SELECT component_id, name FROM raw_props WHERE session_id = ?`).all(targetSessionId).map((p) => `${p.component_id}::${p.name}`)
|
|
12238
|
+
);
|
|
12239
|
+
const insertPath = db.prepare(
|
|
12240
|
+
`INSERT INTO raw_prop_token_paths (session_id, component_id, prop_name, source, position, path)
|
|
12241
|
+
VALUES (?, ?, ?, ?, ?, ?)`
|
|
12242
|
+
);
|
|
12243
|
+
const clearedProps = /* @__PURE__ */ new Set();
|
|
12244
|
+
const copiedProps = /* @__PURE__ */ new Set();
|
|
12245
|
+
for (const row of sourceRows) {
|
|
12246
|
+
const targetComponentId = targetIdByName.get(row.component_name);
|
|
12247
|
+
if (!targetComponentId) continue;
|
|
12248
|
+
if (!targetProps.has(`${targetComponentId}::${row.prop_name}`)) continue;
|
|
12249
|
+
const propKey = `${targetComponentId}::${row.prop_name}`;
|
|
12250
|
+
if (!clearedProps.has(propKey)) {
|
|
12251
|
+
clearedProps.add(propKey);
|
|
12252
|
+
db.prepare(`DELETE FROM raw_prop_token_paths WHERE session_id = ? AND component_id = ? AND prop_name = ?`).run(
|
|
12253
|
+
targetSessionId,
|
|
12254
|
+
targetComponentId,
|
|
12255
|
+
row.prop_name
|
|
12256
|
+
);
|
|
12257
|
+
}
|
|
12258
|
+
insertPath.run(targetSessionId, targetComponentId, row.prop_name, row.source, row.position, row.path);
|
|
12259
|
+
copiedProps.add(propKey);
|
|
12260
|
+
}
|
|
12261
|
+
copiedCount = copiedProps.size;
|
|
12262
|
+
db.prepare("UPDATE sessions SET updated_at = ? WHERE id = ?").run(now, targetSessionId);
|
|
12263
|
+
db.exec("COMMIT");
|
|
12264
|
+
} catch (e) {
|
|
12265
|
+
db.exec("ROLLBACK");
|
|
12266
|
+
throw e;
|
|
12267
|
+
}
|
|
12268
|
+
return copiedCount;
|
|
12269
|
+
}
|
|
12270
|
+
async function getCliCacheVersion() {
|
|
12271
|
+
if (_cliCacheVersionCache) return _cliCacheVersionCache;
|
|
12272
|
+
try {
|
|
12273
|
+
const { hashContent: hashContent2 } = await Promise.resolve().then(() => (init_cache_keys(), cache_keys_exports));
|
|
12274
|
+
const { resolveSkillPath: resolveSkillPath2 } = await Promise.resolve().then(() => (init_src(), src_exports));
|
|
12275
|
+
const skills = ["components", "tokens", "select"];
|
|
12276
|
+
const parts = [];
|
|
12277
|
+
for (const s of skills) {
|
|
12278
|
+
try {
|
|
12279
|
+
const p = resolveSkillPath2(s);
|
|
12280
|
+
parts.push(readFileSync5(p, "utf8"));
|
|
12281
|
+
} catch {
|
|
12282
|
+
parts.push(`<missing:${s}>`);
|
|
12283
|
+
}
|
|
12284
|
+
}
|
|
12285
|
+
_cliCacheVersionCache = hashContent2(parts.join("\n---\n"));
|
|
12286
|
+
return _cliCacheVersionCache;
|
|
12287
|
+
} catch {
|
|
12288
|
+
_cliCacheVersionCache = "fallback";
|
|
12289
|
+
return _cliCacheVersionCache;
|
|
12290
|
+
}
|
|
12291
|
+
}
|
|
12292
|
+
function storeExtractCache(db, filePath, fileHash, cliVersion2, components) {
|
|
12293
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12294
|
+
const componentsJson = JSON.stringify(components);
|
|
12295
|
+
db.prepare(
|
|
12296
|
+
`INSERT INTO extract_cache (file_path, file_hash, cli_version, created_at, updated_at, components_json)
|
|
12297
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
12298
|
+
ON CONFLICT(file_hash, cli_version) DO UPDATE SET
|
|
12299
|
+
file_path = excluded.file_path,
|
|
12300
|
+
updated_at = excluded.updated_at,
|
|
12301
|
+
components_json = excluded.components_json`
|
|
12302
|
+
).run(filePath, fileHash, cliVersion2, now, now, componentsJson);
|
|
12303
|
+
}
|
|
12304
|
+
function lookupExtractCache(db, fileHash, cliVersion2) {
|
|
12305
|
+
const row = db.prepare(
|
|
12306
|
+
`SELECT file_path, file_hash, cli_version, created_at, updated_at, components_json
|
|
12307
|
+
FROM extract_cache
|
|
12308
|
+
WHERE file_hash = ? AND cli_version = ?`
|
|
12309
|
+
).get(fileHash, cliVersion2);
|
|
12310
|
+
if (!row) return null;
|
|
12311
|
+
let components = [];
|
|
12312
|
+
try {
|
|
12313
|
+
components = JSON.parse(row.components_json);
|
|
12314
|
+
} catch {
|
|
12315
|
+
return null;
|
|
12316
|
+
}
|
|
12317
|
+
return {
|
|
12318
|
+
filePath: row.file_path,
|
|
12319
|
+
fileHash: row.file_hash,
|
|
12320
|
+
cliVersion: row.cli_version,
|
|
12321
|
+
createdAt: row.created_at,
|
|
12322
|
+
updatedAt: row.updated_at,
|
|
12323
|
+
components
|
|
12324
|
+
};
|
|
12325
|
+
}
|
|
12326
|
+
function storeCompositionCache(db, inputHash, cliVersion2, agentOutput) {
|
|
12327
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12328
|
+
db.prepare(
|
|
12329
|
+
`INSERT INTO composition_cache (input_hash, cli_version, agent_output, created_at, updated_at)
|
|
12330
|
+
VALUES (?, ?, ?, ?, ?)
|
|
12331
|
+
ON CONFLICT(input_hash, cli_version) DO UPDATE SET
|
|
12332
|
+
agent_output = excluded.agent_output,
|
|
12333
|
+
updated_at = excluded.updated_at`
|
|
12334
|
+
).run(inputHash, cliVersion2, agentOutput, now, now);
|
|
12335
|
+
}
|
|
12336
|
+
function lookupCompositionCache(db, inputHash, cliVersion2) {
|
|
12337
|
+
const row = db.prepare(`SELECT agent_output FROM composition_cache WHERE input_hash = ? AND cli_version = ?`).get(inputHash, cliVersion2);
|
|
12338
|
+
return row ? row.agent_output : null;
|
|
12339
|
+
}
|
|
12340
|
+
function storeSelectCache(db, componentHash, promptHash, cliVersion2, decision, reason) {
|
|
12341
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12342
|
+
db.prepare(
|
|
12343
|
+
`INSERT INTO select_cache (component_hash, prompt_hash, cli_version, decision, reason, created_at, updated_at)
|
|
12344
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
12345
|
+
ON CONFLICT(component_hash, prompt_hash, cli_version) DO UPDATE SET
|
|
12346
|
+
decision = excluded.decision,
|
|
12347
|
+
reason = excluded.reason,
|
|
12348
|
+
updated_at = excluded.updated_at`
|
|
12349
|
+
).run(componentHash, promptHash, cliVersion2, decision, reason, now, now);
|
|
12350
|
+
}
|
|
12351
|
+
function lookupSelectCache(db, componentHash, promptHash, cliVersion2) {
|
|
12352
|
+
const row = db.prepare(
|
|
12353
|
+
`SELECT component_hash, prompt_hash, cli_version, decision, reason, created_at, updated_at
|
|
12354
|
+
FROM select_cache
|
|
12355
|
+
WHERE component_hash = ? AND prompt_hash = ? AND cli_version = ?`
|
|
12356
|
+
).get(componentHash, promptHash, cliVersion2);
|
|
12357
|
+
if (!row) return null;
|
|
12358
|
+
return {
|
|
12359
|
+
componentHash: row.component_hash,
|
|
12360
|
+
promptHash: row.prompt_hash,
|
|
12361
|
+
cliVersion: row.cli_version,
|
|
12362
|
+
decision: row.decision,
|
|
12363
|
+
reason: row.reason,
|
|
12364
|
+
createdAt: row.created_at,
|
|
12365
|
+
updatedAt: row.updated_at
|
|
12366
|
+
};
|
|
12367
|
+
}
|
|
12368
|
+
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;
|
|
11775
12369
|
var init_db = __esm({
|
|
11776
12370
|
"packages/experience-design-system-cli-legacy/src/session/db.ts"() {
|
|
11777
12371
|
"use strict";
|
|
@@ -11785,6 +12379,8 @@ var init_db = __esm({
|
|
|
11785
12379
|
init_write2();
|
|
11786
12380
|
init_session_resolver();
|
|
11787
12381
|
init_read3();
|
|
12382
|
+
init_hash_component_shape();
|
|
12383
|
+
init_hash_token_content();
|
|
11788
12384
|
init_read3();
|
|
11789
12385
|
init_store_dtcg_tokens();
|
|
11790
12386
|
init_apply_tool_calls();
|
|
@@ -11908,6 +12504,17 @@ CREATE TABLE IF NOT EXISTS raw_tokens (
|
|
|
11908
12504
|
FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
|
|
11909
12505
|
);
|
|
11910
12506
|
|
|
12507
|
+
CREATE TABLE IF NOT EXISTS generation_cache (
|
|
12508
|
+
input_hash TEXT NOT NULL,
|
|
12509
|
+
entity_type TEXT NOT NULL CHECK (entity_type IN ('component', 'token_set', 'token_mapping')),
|
|
12510
|
+
entity_id TEXT NOT NULL,
|
|
12511
|
+
source_session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
12512
|
+
human_edited INTEGER NOT NULL DEFAULT 0 CHECK (human_edited IN (0, 1)),
|
|
12513
|
+
created_at TEXT NOT NULL,
|
|
12514
|
+
updated_at TEXT NOT NULL,
|
|
12515
|
+
PRIMARY KEY (input_hash, entity_type, entity_id)
|
|
12516
|
+
);
|
|
12517
|
+
|
|
11911
12518
|
CREATE TABLE IF NOT EXISTS scanned_files (
|
|
11912
12519
|
session_id TEXT NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
|
11913
12520
|
path TEXT NOT NULL,
|
|
@@ -11953,9 +12560,10 @@ CREATE INDEX IF NOT EXISTS idx_raw_props_session ON raw_props(session_id,
|
|
|
11953
12560
|
CREATE INDEX IF NOT EXISTS idx_raw_slots_session ON raw_slots(session_id, component_id);
|
|
11954
12561
|
CREATE INDEX IF NOT EXISTS idx_raw_tokens_session ON raw_tokens(session_id);
|
|
11955
12562
|
CREATE INDEX IF NOT EXISTS idx_raw_token_groups_session ON raw_token_groups(session_id);
|
|
12563
|
+
CREATE INDEX IF NOT EXISTS idx_generation_cache_entity ON generation_cache(entity_type, entity_id);
|
|
12564
|
+
CREATE INDEX IF NOT EXISTS idx_generation_cache_session ON generation_cache(source_session_id);
|
|
11956
12565
|
CREATE INDEX IF NOT EXISTS idx_scanned_files_session ON scanned_files(session_id);
|
|
11957
12566
|
`;
|
|
11958
|
-
REMOVED_CACHE_TABLES = ["generation_cache", "extract_cache", "composition_cache", "select_cache"];
|
|
11959
12567
|
MAX_COMPONENT_SOURCE_CHARS = 8e3;
|
|
11960
12568
|
MAX_SIBLING_FILES = 5;
|
|
11961
12569
|
MAX_SIBLING_SNIPPET_CHARS = 1200;
|
|
@@ -11972,15 +12580,16 @@ CREATE INDEX IF NOT EXISTS idx_scanned_files_session ON scanned_files(session
|
|
|
11972
12580
|
[".cjs", [".cts", ".cjs"]]
|
|
11973
12581
|
];
|
|
11974
12582
|
IDENTIFIER_PATTERN = /[A-Za-z_$][A-Za-z0-9_$]*/g;
|
|
12583
|
+
_cliCacheVersionCache = null;
|
|
11975
12584
|
}
|
|
11976
12585
|
});
|
|
11977
12586
|
|
|
11978
12587
|
// packages/experience-design-system-cli-legacy/src/helpers/read-existing-contentful-entities-from-session.ts
|
|
11979
|
-
import { readFile as
|
|
12588
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
11980
12589
|
async function readExistingContentfulEntitiesFromSession(path) {
|
|
11981
12590
|
if (!path) return void 0;
|
|
11982
12591
|
try {
|
|
11983
|
-
const raw = await
|
|
12592
|
+
const raw = await readFile9(path, "utf8");
|
|
11984
12593
|
const parsed = JSON.parse(raw);
|
|
11985
12594
|
if (!Array.isArray(parsed.components) || !Array.isArray(parsed.tokens)) return void 0;
|
|
11986
12595
|
return parsed;
|
|
@@ -12104,21 +12713,21 @@ var init_resolve_session_id = __esm({
|
|
|
12104
12713
|
});
|
|
12105
12714
|
|
|
12106
12715
|
// packages/experience-design-system-cli-legacy/src/analyze/select/persistence.ts
|
|
12107
|
-
import { access, appendFile, mkdir as mkdir2, readFile as
|
|
12716
|
+
import { access, appendFile, mkdir as mkdir2, readFile as readFile10, writeFile as writeFile2 } from "node:fs/promises";
|
|
12108
12717
|
import { homedir as homedir4 } from "node:os";
|
|
12109
|
-
import { resolve as
|
|
12718
|
+
import { resolve as resolve10 } from "node:path";
|
|
12110
12719
|
function getRefineArtifactsRoot() {
|
|
12111
12720
|
if (process.env.EDS_REVIEW_ARTIFACTS_DIR) {
|
|
12112
|
-
return
|
|
12721
|
+
return resolve10(process.env.EDS_REVIEW_ARTIFACTS_DIR);
|
|
12113
12722
|
}
|
|
12114
|
-
return
|
|
12723
|
+
return resolve10(homedir4(), ".contentful", "experience-design-system-cli", "reviews");
|
|
12115
12724
|
}
|
|
12116
12725
|
async function getRefineSessionPaths(sessionId2, artifactsRoot) {
|
|
12117
|
-
const sessionDir =
|
|
12726
|
+
const sessionDir = resolve10(artifactsRoot, sessionId2);
|
|
12118
12727
|
return {
|
|
12119
12728
|
sessionDir,
|
|
12120
|
-
eventsPath:
|
|
12121
|
-
statePath:
|
|
12729
|
+
eventsPath: resolve10(sessionDir, "events.jsonl"),
|
|
12730
|
+
statePath: resolve10(sessionDir, "current-review-state.json")
|
|
12122
12731
|
};
|
|
12123
12732
|
}
|
|
12124
12733
|
async function saveReviewState(statePath, session) {
|
|
@@ -12129,7 +12738,7 @@ async function ensureRefineSession(sessionId2, artifactsRoot, initialSnapshot) {
|
|
|
12129
12738
|
await mkdir2(paths.sessionDir, { recursive: true });
|
|
12130
12739
|
try {
|
|
12131
12740
|
await access(paths.statePath);
|
|
12132
|
-
const savedState = await
|
|
12741
|
+
const savedState = await readFile10(paths.statePath, "utf8");
|
|
12133
12742
|
return JSON.parse(savedState);
|
|
12134
12743
|
} catch {
|
|
12135
12744
|
await writeFile2(paths.statePath, JSON.stringify(initialSnapshot, null, 2), "utf8");
|
|
@@ -12614,8 +13223,8 @@ var init_path_exists = __esm({
|
|
|
12614
13223
|
});
|
|
12615
13224
|
|
|
12616
13225
|
// packages/experience-design-system-cli-legacy/src/lib/prompt-overrides.ts
|
|
12617
|
-
import { readFile as
|
|
12618
|
-
import { resolve as
|
|
13226
|
+
import { readFile as readFile11 } from "node:fs/promises";
|
|
13227
|
+
import { resolve as resolve11 } from "node:path";
|
|
12619
13228
|
function looksLikePath(value) {
|
|
12620
13229
|
if (value.includes("/") || value.includes("\\")) return true;
|
|
12621
13230
|
if (value.startsWith("~")) return true;
|
|
@@ -12647,9 +13256,9 @@ function parsePromptOverrides(inputs) {
|
|
|
12647
13256
|
}
|
|
12648
13257
|
async function resolvePromptOverride(override) {
|
|
12649
13258
|
if (override.kind === "text") return override.value;
|
|
12650
|
-
const abs =
|
|
13259
|
+
const abs = resolve11(override.value);
|
|
12651
13260
|
try {
|
|
12652
|
-
return await
|
|
13261
|
+
return await readFile11(abs, "utf8");
|
|
12653
13262
|
} catch {
|
|
12654
13263
|
throw new Error(`--prompt: could not read prompt file: ${abs}`);
|
|
12655
13264
|
}
|
|
@@ -12664,21 +13273,21 @@ var init_prompt_overrides = __esm({
|
|
|
12664
13273
|
|
|
12665
13274
|
// packages/experience-design-system-cli-legacy/src/generate/command.ts
|
|
12666
13275
|
import { createElement } from "react";
|
|
12667
|
-
import { readFile as
|
|
12668
|
-
import { join as join14, resolve as
|
|
13276
|
+
import { readFile as readFile12, readdir, stat } from "node:fs/promises";
|
|
13277
|
+
import { join as join14, resolve as resolve12 } from "node:path";
|
|
12669
13278
|
async function assertFileExists(flag, p) {
|
|
12670
13279
|
if (!await pathExists(p)) die(`Error: file not found: ${p} (from ${flag})`);
|
|
12671
13280
|
}
|
|
12672
13281
|
async function readFileInline(path) {
|
|
12673
13282
|
if (!path) return void 0;
|
|
12674
|
-
const resolved =
|
|
13283
|
+
const resolved = resolve12(path);
|
|
12675
13284
|
let s;
|
|
12676
13285
|
try {
|
|
12677
13286
|
s = await stat(resolved);
|
|
12678
13287
|
} catch {
|
|
12679
13288
|
return void 0;
|
|
12680
13289
|
}
|
|
12681
|
-
if (!s.isDirectory()) return
|
|
13290
|
+
if (!s.isDirectory()) return readFile12(resolved, "utf8");
|
|
12682
13291
|
const files = [];
|
|
12683
13292
|
async function walk(dir) {
|
|
12684
13293
|
let entries;
|
|
@@ -12704,7 +13313,7 @@ async function readFileInline(path) {
|
|
|
12704
13313
|
}
|
|
12705
13314
|
await walk(resolved);
|
|
12706
13315
|
if (files.length === 0) return void 0;
|
|
12707
|
-
const parts = await Promise.all(files.map((f) =>
|
|
13316
|
+
const parts = await Promise.all(files.map((f) => readFile12(f, "utf8").catch(() => "")));
|
|
12708
13317
|
return parts.filter(Boolean).join("\n\n");
|
|
12709
13318
|
}
|
|
12710
13319
|
function printFallbackInstructions(options) {
|
|
@@ -12726,6 +13335,23 @@ function printFallbackInstructions(options) {
|
|
|
12726
13335
|
lines.push(` Re-run the generate command with the agent available, or use --dry-run to inspect the prompt.`);
|
|
12727
13336
|
process.stderr.write(lines.join("\n") + "\n");
|
|
12728
13337
|
}
|
|
13338
|
+
function createCachedComponentResult(componentName, warnings = []) {
|
|
13339
|
+
return {
|
|
13340
|
+
componentName,
|
|
13341
|
+
classified: 0,
|
|
13342
|
+
excluded: 0,
|
|
13343
|
+
slots: 0,
|
|
13344
|
+
warnings,
|
|
13345
|
+
failed: false,
|
|
13346
|
+
cached: true,
|
|
13347
|
+
renamedSlotsCount: 0
|
|
13348
|
+
};
|
|
13349
|
+
}
|
|
13350
|
+
function writeCachedComponentStatus(position, componentName, pinned) {
|
|
13351
|
+
const status = pinned ? c.cyan("pinned (human-edited)") : c.green("cached");
|
|
13352
|
+
process.stderr.write(` ${position} ${c.bold(componentName)} ${status}
|
|
13353
|
+
`);
|
|
13354
|
+
}
|
|
12729
13355
|
async function showGenerateView(result) {
|
|
12730
13356
|
if (process.stdout.isTTY) {
|
|
12731
13357
|
const { waitUntilExit } = renderWithGoodbye(
|
|
@@ -12746,6 +13372,29 @@ session=${result.sessionId}
|
|
|
12746
13372
|
);
|
|
12747
13373
|
await exitWithAnalytics(0);
|
|
12748
13374
|
}
|
|
13375
|
+
function normalizeComponentForCache(component) {
|
|
13376
|
+
const slots = component.slots.map((slot, index, allSlots) => ({
|
|
13377
|
+
...slot,
|
|
13378
|
+
name: slot.name.trim() || (allSlots.length === 1 ? "children" : `slot_${index}`)
|
|
13379
|
+
}));
|
|
13380
|
+
return { ...component, slots };
|
|
13381
|
+
}
|
|
13382
|
+
function lookupComponentCache(db, component, promptHash) {
|
|
13383
|
+
const normalized = normalizeComponentForCache(component);
|
|
13384
|
+
const inputHash = hashComponentShape(normalized);
|
|
13385
|
+
const cached = lookupCache(db, inputHash, "component", component.component_id, promptHash);
|
|
13386
|
+
if (cached) return cached;
|
|
13387
|
+
const legacyInputHash = hashComponentShape(component);
|
|
13388
|
+
return legacyInputHash === inputHash ? null : lookupCache(db, legacyInputHash, "component", component.component_id, promptHash);
|
|
13389
|
+
}
|
|
13390
|
+
function resolveComponentCache(db, component, promptHash, allowedComponentNames2) {
|
|
13391
|
+
const cached = lookupComponentCache(db, component, promptHash);
|
|
13392
|
+
if (cached && findUnknownSlotAllowedComponents(db, cached.sourceSessionId, allowedComponentNames2, component.component_id).length === 0) {
|
|
13393
|
+
return { entry: cached, humanEdited: cached.humanEdited };
|
|
13394
|
+
}
|
|
13395
|
+
const pinned = lookupCacheByEntity(db, "component", component.component_id);
|
|
13396
|
+
return pinned?.humanEdited && findUnknownSlotAllowedComponents(db, pinned.sourceSessionId, allowedComponentNames2, component.component_id).length === 0 ? { entry: pinned, humanEdited: true } : null;
|
|
13397
|
+
}
|
|
12749
13398
|
async function runOneComponent(options, component, index, total) {
|
|
12750
13399
|
const {
|
|
12751
13400
|
agent,
|
|
@@ -12755,10 +13404,13 @@ async function runOneComponent(options, component, index, total) {
|
|
|
12755
13404
|
tokensInline,
|
|
12756
13405
|
tokenMapInline,
|
|
12757
13406
|
verbose,
|
|
13407
|
+
noCache,
|
|
12758
13408
|
skillPathOverride,
|
|
12759
13409
|
skillContentOverride,
|
|
13410
|
+
promptHash,
|
|
12760
13411
|
existingContentfulEntities,
|
|
12761
13412
|
existingTokensInline,
|
|
13413
|
+
precomputedCachedNames,
|
|
12762
13414
|
allowedComponentNames: allowedComponentNames2
|
|
12763
13415
|
} = options;
|
|
12764
13416
|
const pos = c.dim(`[${index + 1}/${total}]`);
|
|
@@ -12783,6 +13435,40 @@ async function runOneComponent(options, component, index, total) {
|
|
|
12783
13435
|
allowedComponents: slot.allowedComponents.filter((name) => allowedComponentNames2.has(name))
|
|
12784
13436
|
};
|
|
12785
13437
|
});
|
|
13438
|
+
const cacheComponent = normalizeComponentForCache(component);
|
|
13439
|
+
if (!noCache && precomputedCachedNames.has(component.name)) {
|
|
13440
|
+
writeCachedComponentStatus(pos, component.name, false);
|
|
13441
|
+
return createCachedComponentResult(component.name);
|
|
13442
|
+
}
|
|
13443
|
+
if (!noCache) {
|
|
13444
|
+
const inputHash = hashComponentShape(cacheComponent);
|
|
13445
|
+
const resolution = resolveComponentCache(db, component, promptHash, allowedComponentNames2);
|
|
13446
|
+
if (resolution && !resolution.humanEdited) {
|
|
13447
|
+
copyComponentFromCache(db, resolution.entry.sourceSessionId, sessionId2, component.component_id, true, {
|
|
13448
|
+
allowedComponentNames: allowedComponentNames2
|
|
13449
|
+
});
|
|
13450
|
+
storeCache(
|
|
13451
|
+
db,
|
|
13452
|
+
inputHash,
|
|
13453
|
+
"component",
|
|
13454
|
+
component.component_id,
|
|
13455
|
+
resolution.entry.sourceSessionId,
|
|
13456
|
+
resolution.entry.humanEdited,
|
|
13457
|
+
promptHash
|
|
13458
|
+
);
|
|
13459
|
+
writeCachedComponentStatus(pos, component.name, false);
|
|
13460
|
+
return createCachedComponentResult(component.name);
|
|
13461
|
+
}
|
|
13462
|
+
if (resolution?.humanEdited) {
|
|
13463
|
+
copyComponentFromCache(db, resolution.entry.sourceSessionId, sessionId2, component.component_id, true, {
|
|
13464
|
+
allowedComponentNames: allowedComponentNames2
|
|
13465
|
+
});
|
|
13466
|
+
writeCachedComponentStatus(pos, component.name, true);
|
|
13467
|
+
return createCachedComponentResult(`${component.name}`, [
|
|
13468
|
+
`${component.name}: source changed but human edits preserved`
|
|
13469
|
+
]);
|
|
13470
|
+
}
|
|
13471
|
+
}
|
|
12786
13472
|
const componentBuckets = bucketComponentProps(component);
|
|
12787
13473
|
getDebugLogger().event("analyze", "prop-buckets.generate", { ...componentBuckets });
|
|
12788
13474
|
const rawComponentsInline = JSON.stringify(
|
|
@@ -12857,6 +13543,10 @@ ${outputBuf}`);
|
|
|
12857
13543
|
const applied = applyToolCalls(db, sessionId2, component.component_id, component.name, calls, warnings, {
|
|
12858
13544
|
allowedComponentNames: allowedComponentNames2
|
|
12859
13545
|
});
|
|
13546
|
+
if (!noCache) {
|
|
13547
|
+
const inputHash = hashComponentShape(cacheComponent);
|
|
13548
|
+
storeCache(db, inputHash, "component", component.component_id, sessionId2, false, promptHash);
|
|
13549
|
+
}
|
|
12860
13550
|
return {
|
|
12861
13551
|
componentName: component.name,
|
|
12862
13552
|
classified: applied.classified,
|
|
@@ -12908,7 +13598,7 @@ async function loadAcceptedNames(sessionId2) {
|
|
|
12908
13598
|
try {
|
|
12909
13599
|
const artifactsRoot = getRefineArtifactsRoot();
|
|
12910
13600
|
const paths = await getRefineSessionPaths(sessionId2, artifactsRoot);
|
|
12911
|
-
const raw = await
|
|
13601
|
+
const raw = await readFile12(paths.statePath, "utf8");
|
|
12912
13602
|
const snapshot = JSON.parse(raw);
|
|
12913
13603
|
const accepted = snapshot.components.filter((c2) => c2.status === "accepted").map((c2) => c2.name);
|
|
12914
13604
|
if (accepted.length === 0) return null;
|
|
@@ -12917,6 +13607,15 @@ async function loadAcceptedNames(sessionId2) {
|
|
|
12917
13607
|
return null;
|
|
12918
13608
|
}
|
|
12919
13609
|
}
|
|
13610
|
+
function parsePrecomputedCachedNames(value) {
|
|
13611
|
+
if (!value) return /* @__PURE__ */ new Set();
|
|
13612
|
+
try {
|
|
13613
|
+
const parsed = JSON.parse(value);
|
|
13614
|
+
return new Set(Array.isArray(parsed) ? parsed.filter((name) => typeof name === "string") : []);
|
|
13615
|
+
} catch {
|
|
13616
|
+
return /* @__PURE__ */ new Set();
|
|
13617
|
+
}
|
|
13618
|
+
}
|
|
12920
13619
|
async function runGenerateSkill(skill, opts, verbose = false) {
|
|
12921
13620
|
const savedCreds = await readExperiencesCredentials();
|
|
12922
13621
|
const agentName = opts.agent ?? savedCreds.agent;
|
|
@@ -12945,8 +13644,8 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
12945
13644
|
}
|
|
12946
13645
|
const generatePromptPath = generatePrompt === void 0 ? configuredGeneratePromptPath : void 0;
|
|
12947
13646
|
if (generatePromptPath) {
|
|
12948
|
-
if (!await pathExists(
|
|
12949
|
-
die(`Error: custom prompt path not found: ${
|
|
13647
|
+
if (!await pathExists(resolve12(generatePromptPath))) {
|
|
13648
|
+
die(`Error: custom prompt path not found: ${resolve12(generatePromptPath)}`);
|
|
12950
13649
|
}
|
|
12951
13650
|
if (!generatePromptPath.toLowerCase().endsWith(".md")) {
|
|
12952
13651
|
process.stderr.write(
|
|
@@ -12954,7 +13653,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
12954
13653
|
`
|
|
12955
13654
|
);
|
|
12956
13655
|
}
|
|
12957
|
-
process.stderr.write(formatCustomPromptBanner("components",
|
|
13656
|
+
process.stderr.write(formatCustomPromptBanner("components", resolve12(generatePromptPath)));
|
|
12958
13657
|
}
|
|
12959
13658
|
if (skill === "tokens" && !opts.rawTokens) {
|
|
12960
13659
|
die("Error: --raw-tokens is required when using generate tokens");
|
|
@@ -12970,7 +13669,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
12970
13669
|
let existingContentfulEntities;
|
|
12971
13670
|
let existingTokensInline;
|
|
12972
13671
|
if (opts.existingEntitiesPath) {
|
|
12973
|
-
existingContentfulEntities = await readExistingContentfulEntitiesFromSession(
|
|
13672
|
+
existingContentfulEntities = await readExistingContentfulEntitiesFromSession(resolve12(opts.existingEntitiesPath));
|
|
12974
13673
|
if (existingContentfulEntities) {
|
|
12975
13674
|
existingTokensInline = JSON.stringify(summarizeForMapTokens(existingContentfulEntities));
|
|
12976
13675
|
} else {
|
|
@@ -13071,7 +13770,7 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
13071
13770
|
rawComponentsInline: sampleInline ?? rawTokensInline,
|
|
13072
13771
|
propBucketsInline: sampleBuckets ? JSON.stringify(sampleBuckets) : void 0,
|
|
13073
13772
|
rawTokensInline: skill === "tokens" ? rawTokensInline : void 0,
|
|
13074
|
-
rawTokensFilename: opts.rawTokens ?
|
|
13773
|
+
rawTokensFilename: opts.rawTokens ? resolve12(opts.rawTokens).split("/").pop() : void 0,
|
|
13075
13774
|
tokensInline,
|
|
13076
13775
|
tokenMapInline,
|
|
13077
13776
|
outDir: process.cwd(),
|
|
@@ -13097,7 +13796,64 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
13097
13796
|
if (skill === "components" && allComponents && sessionId2) {
|
|
13098
13797
|
const db = openPipelineDb();
|
|
13099
13798
|
let componentResults;
|
|
13799
|
+
const precomputedCachedNames = parsePrecomputedCachedNames(opts.cachedComponents);
|
|
13100
13800
|
try {
|
|
13801
|
+
const existingContentfulEntitiesHashInputs = [];
|
|
13802
|
+
if (existingTokensInline) existingContentfulEntitiesHashInputs.push(hashContent(existingTokensInline));
|
|
13803
|
+
const promptHash = await hashPromptForSkill(
|
|
13804
|
+
"components",
|
|
13805
|
+
agent,
|
|
13806
|
+
model,
|
|
13807
|
+
generatePromptPath,
|
|
13808
|
+
existingContentfulEntitiesHashInputs,
|
|
13809
|
+
generatePrompt
|
|
13810
|
+
);
|
|
13811
|
+
if (opts.cacheStatus) {
|
|
13812
|
+
const cacheEnabled = opts.cache !== false && process.env.EDS_NO_CACHE !== "1";
|
|
13813
|
+
const cachedComponents = cacheEnabled ? allComponents.flatMap((component) => {
|
|
13814
|
+
const resolution = resolveComponentCache(db, component, promptHash, allowedComponentNames2);
|
|
13815
|
+
return resolution ? [{ component, resolution }] : [];
|
|
13816
|
+
}) : [];
|
|
13817
|
+
if (cacheEnabled && opts.restoreCache) {
|
|
13818
|
+
const restorations = [];
|
|
13819
|
+
const rekeyed = [];
|
|
13820
|
+
const componentStatus = db.prepare(
|
|
13821
|
+
"SELECT status FROM raw_components WHERE session_id = ? AND component_id = ?"
|
|
13822
|
+
);
|
|
13823
|
+
for (const { component, resolution } of cachedComponents) {
|
|
13824
|
+
const current = componentStatus.get(sessionId2, component.component_id);
|
|
13825
|
+
if (current?.status === "generated") continue;
|
|
13826
|
+
renameEmptySlots(db, sessionId2, component.component_id, component.name, component.slots.length);
|
|
13827
|
+
restorations.push({
|
|
13828
|
+
sourceSessionId: resolution.entry.sourceSessionId,
|
|
13829
|
+
targetSessionId: sessionId2,
|
|
13830
|
+
componentId: component.component_id
|
|
13831
|
+
});
|
|
13832
|
+
rekeyed.push({ component, cached: resolution.entry });
|
|
13833
|
+
}
|
|
13834
|
+
copyComponentsFromCache(db, restorations, { allowedComponentNames: allowedComponentNames2 });
|
|
13835
|
+
storeCaches(
|
|
13836
|
+
db,
|
|
13837
|
+
rekeyed.map(({ component, cached }) => ({
|
|
13838
|
+
inputHash: hashComponentShape(normalizeComponentForCache(component)),
|
|
13839
|
+
entityType: "component",
|
|
13840
|
+
entityId: component.component_id,
|
|
13841
|
+
sourceSessionId: cached.sourceSessionId,
|
|
13842
|
+
humanEdited: cached.humanEdited,
|
|
13843
|
+
promptHash
|
|
13844
|
+
}))
|
|
13845
|
+
);
|
|
13846
|
+
}
|
|
13847
|
+
const fullyCached = cacheEnabled && cachedComponents.length === allComponents.length;
|
|
13848
|
+
process.stdout.write(`cache-status=${fullyCached ? "hit" : "miss"}
|
|
13849
|
+
`);
|
|
13850
|
+
process.stdout.write(
|
|
13851
|
+
`cache-components=${JSON.stringify(cachedComponents.map(({ component }) => component.name))}
|
|
13852
|
+
`
|
|
13853
|
+
);
|
|
13854
|
+
await exitWithAnalytics(0);
|
|
13855
|
+
return;
|
|
13856
|
+
}
|
|
13101
13857
|
componentResults = await runAllComponents(
|
|
13102
13858
|
{
|
|
13103
13859
|
agent,
|
|
@@ -13107,10 +13863,13 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
13107
13863
|
tokensInline,
|
|
13108
13864
|
tokenMapInline,
|
|
13109
13865
|
verbose,
|
|
13866
|
+
noCache: opts.cache === false || process.env.EDS_NO_CACHE === "1",
|
|
13110
13867
|
skillPathOverride: generatePromptPath,
|
|
13111
13868
|
skillContentOverride: generatePrompt,
|
|
13869
|
+
promptHash,
|
|
13112
13870
|
existingContentfulEntities,
|
|
13113
13871
|
existingTokensInline,
|
|
13872
|
+
precomputedCachedNames,
|
|
13114
13873
|
allowedComponentNames: allowedComponentNames2
|
|
13115
13874
|
},
|
|
13116
13875
|
allComponents
|
|
@@ -13119,7 +13878,8 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
13119
13878
|
db.close();
|
|
13120
13879
|
}
|
|
13121
13880
|
const failed = componentResults.filter((r) => r.failed);
|
|
13122
|
-
const
|
|
13881
|
+
const cachedResults = componentResults.filter((r) => r.cached);
|
|
13882
|
+
const generated = componentResults.filter((r) => !r.failed && !r.cached);
|
|
13123
13883
|
const allWarnings = componentResults.flatMap((r) => r.warnings.map((w) => ` ${r.componentName}: ${w}`));
|
|
13124
13884
|
if (allWarnings.length > 0) {
|
|
13125
13885
|
process.stderr.write(c.yellow("Warnings:") + "\n" + allWarnings.join("\n") + "\n");
|
|
@@ -13135,17 +13895,21 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
13135
13895
|
const totalExcluded = generated.reduce((s, r) => s + r.excluded, 0);
|
|
13136
13896
|
const totalRenamedSlots = componentResults.reduce((s, r) => s + r.renamedSlotsCount, 0);
|
|
13137
13897
|
const allOk = failed.length === 0;
|
|
13898
|
+
const cachedNote = cachedResults.length > 0 ? c.dim(` (${cachedResults.length} cached)`) : "";
|
|
13138
13899
|
process.stderr.write(
|
|
13139
|
-
(allOk ? c.green("\u2713") : c.yellow("\u26A0")) + ` ${generated.length}/${componentResults.length} components` + c.dim(` ${totalClassified} classified, ${totalExcluded} unattached`) + "\n"
|
|
13900
|
+
(allOk ? c.green("\u2713") : c.yellow("\u26A0")) + ` ${generated.length + cachedResults.length}/${componentResults.length} components` + cachedNote + c.dim(` ${totalClassified} classified, ${totalExcluded} unattached`) + "\n"
|
|
13140
13901
|
);
|
|
13141
13902
|
process.stdout.write(`renamed-slots: ${totalRenamedSlots}
|
|
13142
13903
|
`);
|
|
13143
|
-
if (generated.length === 0) {
|
|
13904
|
+
if (generated.length === 0 && cachedResults.length === 0) {
|
|
13144
13905
|
die(
|
|
13145
13906
|
`Error: all ${componentResults.length} component(s) failed to generate \u2014 see the per-component errors above.`
|
|
13146
13907
|
);
|
|
13147
13908
|
}
|
|
13148
13909
|
} else if (skill === "tokens") {
|
|
13910
|
+
const noCache = opts.cache === false || process.env.EDS_NO_CACHE === "1";
|
|
13911
|
+
const tokenInputContent = rawTokensInline ?? "";
|
|
13912
|
+
const tokenInputHash = hashTokenContent(tokenInputContent);
|
|
13149
13913
|
const db = openPipelineDb();
|
|
13150
13914
|
try {
|
|
13151
13915
|
let resolvedSessionId = opts.session;
|
|
@@ -13172,11 +13936,26 @@ async function runGenerateSkill(skill, opts, verbose = false) {
|
|
|
13172
13936
|
}
|
|
13173
13937
|
sessionId2 = resolvedSessionId;
|
|
13174
13938
|
await bindAnalyticsSessionId(resolvedSessionId);
|
|
13939
|
+
const tokenPromptHash = await hashPromptForSkill("tokens", agent, model);
|
|
13940
|
+
if (!noCache) {
|
|
13941
|
+
const tokenCached = lookupCache(db, tokenInputHash, "token_set", "__tokens__", tokenPromptHash);
|
|
13942
|
+
if (tokenCached) {
|
|
13943
|
+
copyTokensFromCache(db, tokenCached.sourceSessionId, resolvedSessionId);
|
|
13944
|
+
sessionId2 = resolvedSessionId;
|
|
13945
|
+
process.stderr.write(
|
|
13946
|
+
`Done: tokens reused from cache ${c.dim(`(source: ${tokenCached.sourceSessionId.slice(0, 12)})`)}
|
|
13947
|
+
`
|
|
13948
|
+
);
|
|
13949
|
+
db.close();
|
|
13950
|
+
await showGenerateView({ skill, agent, sessionId: sessionId2 ?? "" });
|
|
13951
|
+
return;
|
|
13952
|
+
}
|
|
13953
|
+
}
|
|
13175
13954
|
const prompt = await buildPrompt({
|
|
13176
13955
|
skill,
|
|
13177
13956
|
mode: "autonomous",
|
|
13178
13957
|
rawTokensInline,
|
|
13179
|
-
rawTokensFilename: opts.rawTokens ?
|
|
13958
|
+
rawTokensFilename: opts.rawTokens ? resolve12(opts.rawTokens).split("/").pop() : void 0,
|
|
13180
13959
|
tokensInline,
|
|
13181
13960
|
tokenMapInline,
|
|
13182
13961
|
outDir: process.cwd()
|
|
@@ -13213,6 +13992,9 @@ ${tokenWarnings.map((w) => ` ${w}`).join("\n")}
|
|
|
13213
13992
|
`);
|
|
13214
13993
|
}
|
|
13215
13994
|
applyTokenToolCalls(db, resolvedSessionId, tokenCalls, []);
|
|
13995
|
+
if (!noCache) {
|
|
13996
|
+
storeCache(db, tokenInputHash, "token_set", "__tokens__", resolvedSessionId, false, tokenPromptHash);
|
|
13997
|
+
}
|
|
13216
13998
|
sessionId2 = resolvedSessionId;
|
|
13217
13999
|
const groupCount = tokenCalls.filter((tc) => tc.tool === "set_group").length;
|
|
13218
14000
|
process.stderr.write(`Done: ${tokenCount} tokens, ${groupCount} groups stored
|
|
@@ -13224,7 +14006,10 @@ ${tokenWarnings.map((w) => ` ${w}`).join("\n")}
|
|
|
13224
14006
|
await showGenerateView({ skill, agent, sessionId: sessionId2 ?? "" });
|
|
13225
14007
|
}
|
|
13226
14008
|
function addAgentFlags(cmd) {
|
|
13227
|
-
return addAgentModelOptions(cmd).option("--verbose", "Show full agent output including reasoning text").option("--dry-run", "Print the prompt without invoking the agent")
|
|
14009
|
+
return addAgentModelOptions(cmd).option("--verbose", "Show full agent output including reasoning text").option("--dry-run", "Print the prompt without invoking the agent").option(
|
|
14010
|
+
"--no-cache",
|
|
14011
|
+
"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."
|
|
14012
|
+
);
|
|
13228
14013
|
}
|
|
13229
14014
|
function registerInternalGenerateCommand(program) {
|
|
13230
14015
|
const generate = program.command("__generate", { hidden: true }).description("Internal import pipeline generation command");
|
|
@@ -13240,6 +14025,12 @@ function registerInternalGenerateCommand(program) {
|
|
|
13240
14025
|
"--existing-entities-path <path>",
|
|
13241
14026
|
"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."
|
|
13242
14027
|
);
|
|
14028
|
+
componentsCmd.option("--cache-status", "Check whether all selected component definitions are cached");
|
|
14029
|
+
componentsCmd.option("--restore-cache", "Restore cached component definitions into the current session");
|
|
14030
|
+
componentsCmd.option(
|
|
14031
|
+
"--cached-components <json>",
|
|
14032
|
+
"Component names already restored by a prior cache-status lookup; skip per-component cache lookup"
|
|
14033
|
+
);
|
|
13243
14034
|
addAgentFlags(componentsCmd).action(async (opts) => {
|
|
13244
14035
|
await runGenerateSkill("components", opts, opts.verbose ?? false);
|
|
13245
14036
|
});
|
|
@@ -13265,6 +14056,7 @@ var init_command = __esm({
|
|
|
13265
14056
|
init_agent_output();
|
|
13266
14057
|
init_GenerateView();
|
|
13267
14058
|
init_db();
|
|
14059
|
+
init_cache_keys();
|
|
13268
14060
|
init_read_existing_contentful_entities_from_session();
|
|
13269
14061
|
init_summarize_existing_contentful_entities();
|
|
13270
14062
|
init_resolve_session_id();
|
|
@@ -13980,7 +14772,7 @@ var init_user_agent = __esm({
|
|
|
13980
14772
|
// packages/experience-design-system-cli-legacy/src/apply/api-client.ts
|
|
13981
14773
|
import { parseCDFComponents } from "@contentful/experience-design-system-types";
|
|
13982
14774
|
function defaultSleep(delayMs) {
|
|
13983
|
-
return new Promise((
|
|
14775
|
+
return new Promise((resolve22) => setTimeout(resolve22, delayMs));
|
|
13984
14776
|
}
|
|
13985
14777
|
function isTransientStatus(status) {
|
|
13986
14778
|
return status >= 500 && status <= 599;
|
|
@@ -14370,7 +15162,7 @@ ${trimmed}`;
|
|
|
14370
15162
|
const progress = maxAttempts > 1 ? attempt / (maxAttempts - 1) : 0;
|
|
14371
15163
|
const baseDelay = intervalMs + (maxIntervalMs - intervalMs) * progress;
|
|
14372
15164
|
const jitter = Math.random() * baseDelay * 0.15;
|
|
14373
|
-
await new Promise((
|
|
15165
|
+
await new Promise((resolve22) => setTimeout(resolve22, baseDelay + jitter));
|
|
14374
15166
|
}
|
|
14375
15167
|
}
|
|
14376
15168
|
throw new Error(`Operation ${operationId} timed out after ${maxAttempts} attempts`);
|
|
@@ -15180,7 +15972,7 @@ var init_terminal_capabilities = __esm({
|
|
|
15180
15972
|
|
|
15181
15973
|
// packages/experience-design-system-cli-legacy/src/apply/command.ts
|
|
15182
15974
|
import { createElement as createElement2 } from "react";
|
|
15183
|
-
import { readFile as
|
|
15975
|
+
import { readFile as readFile13, readdir as readdir2, stat as stat2 } from "node:fs/promises";
|
|
15184
15976
|
import { join as join16 } from "node:path";
|
|
15185
15977
|
import {
|
|
15186
15978
|
validateCDF,
|
|
@@ -15201,7 +15993,7 @@ function dieWithApiError(error) {
|
|
|
15201
15993
|
async function readJsonFile(flag, p) {
|
|
15202
15994
|
let text;
|
|
15203
15995
|
try {
|
|
15204
|
-
text = await
|
|
15996
|
+
text = await readFile13(p, "utf8");
|
|
15205
15997
|
} catch {
|
|
15206
15998
|
return await die2(`Error: file not found: ${p} (from ${flag})`);
|
|
15207
15999
|
}
|
|
@@ -15255,7 +16047,7 @@ async function readTokensFromPath(flag, p) {
|
|
|
15255
16047
|
for (const file of files.sort()) {
|
|
15256
16048
|
let text;
|
|
15257
16049
|
try {
|
|
15258
|
-
text = await
|
|
16050
|
+
text = await readFile13(file, "utf8");
|
|
15259
16051
|
} catch {
|
|
15260
16052
|
continue;
|
|
15261
16053
|
}
|
|
@@ -15624,11 +16416,11 @@ var init_command2 = __esm({
|
|
|
15624
16416
|
});
|
|
15625
16417
|
|
|
15626
16418
|
// packages/experience-design-system-cli-legacy/src/print/validate/validators/read-json-file.ts
|
|
15627
|
-
import { readFile as
|
|
16419
|
+
import { readFile as readFile14 } from "node:fs/promises";
|
|
15628
16420
|
async function readJsonFile2(filePath) {
|
|
15629
16421
|
let content;
|
|
15630
16422
|
try {
|
|
15631
|
-
content = await
|
|
16423
|
+
content = await readFile14(filePath, "utf-8");
|
|
15632
16424
|
} catch (err) {
|
|
15633
16425
|
return {
|
|
15634
16426
|
ok: false,
|
|
@@ -16039,7 +16831,7 @@ var init_ValidateView = __esm({
|
|
|
16039
16831
|
// packages/experience-design-system-cli-legacy/src/print/command.ts
|
|
16040
16832
|
import { createElement as createElement3 } from "react";
|
|
16041
16833
|
import { access as access3, mkdir as mkdir3, stat as stat3, writeFile as writeFile3 } from "node:fs/promises";
|
|
16042
|
-
import { basename as basename5, resolve as
|
|
16834
|
+
import { basename as basename5, resolve as resolve13 } from "node:path";
|
|
16043
16835
|
import { CDF_SCHEMA_URL } from "@contentful/experience-design-system-types";
|
|
16044
16836
|
async function die3(message) {
|
|
16045
16837
|
process.stderr.write(`${message}
|
|
@@ -16106,7 +16898,7 @@ function registerPrintCommand(program) {
|
|
|
16106
16898
|
"--allow-empty",
|
|
16107
16899
|
"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."
|
|
16108
16900
|
).action(async (opts) => {
|
|
16109
|
-
const outPath =
|
|
16901
|
+
const outPath = resolve13(opts.out);
|
|
16110
16902
|
await assertOutIsNotDirectory(outPath);
|
|
16111
16903
|
const sessionId2 = await resolveSession(opts.session, "generate components");
|
|
16112
16904
|
await bindAnalyticsSessionId(sessionId2);
|
|
@@ -16154,7 +16946,7 @@ function registerPrintCommand(program) {
|
|
|
16154
16946
|
`
|
|
16155
16947
|
);
|
|
16156
16948
|
}
|
|
16157
|
-
await mkdir3(
|
|
16949
|
+
await mkdir3(resolve13(outPath, ".."), { recursive: true });
|
|
16158
16950
|
await writeFile3(outPath, `${JSON.stringify(cdfObj, null, 2)}
|
|
16159
16951
|
`);
|
|
16160
16952
|
process.stdout.write(
|
|
@@ -16163,7 +16955,7 @@ function registerPrintCommand(program) {
|
|
|
16163
16955
|
);
|
|
16164
16956
|
});
|
|
16165
16957
|
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) => {
|
|
16166
|
-
const outPath =
|
|
16958
|
+
const outPath = resolve13(opts.out);
|
|
16167
16959
|
await assertOutIsNotDirectory(outPath);
|
|
16168
16960
|
const sessionId2 = await resolveSession(opts.session, "generate tokens");
|
|
16169
16961
|
await bindAnalyticsSessionId(sessionId2);
|
|
@@ -16178,7 +16970,7 @@ function registerPrintCommand(program) {
|
|
|
16178
16970
|
await die3(`Error: no generated tokens in session '${sessionId2}'. Run generate tokens first.`);
|
|
16179
16971
|
}
|
|
16180
16972
|
const tree = rebuildDTCGTree(result.groups, result.tokens);
|
|
16181
|
-
await mkdir3(
|
|
16973
|
+
await mkdir3(resolve13(outPath, ".."), { recursive: true });
|
|
16182
16974
|
await writeFile3(outPath, `${JSON.stringify(tree, null, 2)}
|
|
16183
16975
|
`);
|
|
16184
16976
|
process.stdout.write(
|
|
@@ -16327,7 +17119,7 @@ function MapTokensView({ result, onExit }) {
|
|
|
16327
17119
|
const timer = setTimeout(onExit, 100);
|
|
16328
17120
|
return () => clearTimeout(timer);
|
|
16329
17121
|
}, [onExit]);
|
|
16330
|
-
const summary = `${result.applied} mapping${result.applied === 1 ? "" : "s"} applied`;
|
|
17122
|
+
const summary = result.cached ? "reused from cache" : `${result.applied} mapping${result.applied === 1 ? "" : "s"} applied`;
|
|
16331
17123
|
return /* @__PURE__ */ jsx8(
|
|
16332
17124
|
CommandCompletionView,
|
|
16333
17125
|
{
|
|
@@ -16461,8 +17253,8 @@ var init_resolve_defaults = __esm({
|
|
|
16461
17253
|
|
|
16462
17254
|
// packages/experience-design-system-cli-legacy/src/map-tokens/command.ts
|
|
16463
17255
|
import { createElement as createElement4 } from "react";
|
|
16464
|
-
import { readFile as
|
|
16465
|
-
import { resolve as
|
|
17256
|
+
import { readFile as readFile15 } from "node:fs/promises";
|
|
17257
|
+
import { resolve as resolve14 } from "node:path";
|
|
16466
17258
|
async function renderResult(result) {
|
|
16467
17259
|
if (process.stdout.isTTY) {
|
|
16468
17260
|
const { waitUntilExit } = renderWithGoodbye(
|
|
@@ -16470,13 +17262,12 @@ async function renderResult(result) {
|
|
|
16470
17262
|
);
|
|
16471
17263
|
await waitUntilExit();
|
|
16472
17264
|
} else {
|
|
16473
|
-
|
|
16474
|
-
|
|
17265
|
+
const summary = result.cached ? "cached" : `${result.applied} mapping(s) applied`;
|
|
17266
|
+
process.stdout.write(`map tokens complete
|
|
16475
17267
|
agent: ${result.agent}
|
|
16476
17268
|
session=${result.sessionId}
|
|
16477
|
-
${
|
|
16478
|
-
`
|
|
16479
|
-
);
|
|
17269
|
+
${summary}
|
|
17270
|
+
`);
|
|
16480
17271
|
await exitWithAnalytics(0);
|
|
16481
17272
|
}
|
|
16482
17273
|
}
|
|
@@ -16498,7 +17289,7 @@ async function runMapTokens(opts) {
|
|
|
16498
17289
|
let mapPromptPath;
|
|
16499
17290
|
if (mapPromptOverride?.kind === "text") mapPromptText = mapPromptOverride.value;
|
|
16500
17291
|
if (mapPromptOverride?.kind === "path") {
|
|
16501
|
-
mapPromptPath =
|
|
17292
|
+
mapPromptPath = resolve14(mapPromptOverride.value);
|
|
16502
17293
|
try {
|
|
16503
17294
|
await resolvePromptOverride(mapPromptOverride);
|
|
16504
17295
|
} catch (error) {
|
|
@@ -16518,7 +17309,7 @@ async function runMapTokens(opts) {
|
|
|
16518
17309
|
const knownTokenPaths = new Set(tokenLeaves.map((t) => t.path));
|
|
16519
17310
|
const tokenMapDiagnostics = [];
|
|
16520
17311
|
if (opts.tokenMap) {
|
|
16521
|
-
const fileMappings = JSON.parse(await
|
|
17312
|
+
const fileMappings = JSON.parse(await readFile15(opts.tokenMap, "utf8"));
|
|
16522
17313
|
const validMappings = {};
|
|
16523
17314
|
for (const [rawName, path] of Object.entries(fileMappings)) {
|
|
16524
17315
|
if (knownTokenPaths.has(path)) {
|
|
@@ -16596,7 +17387,7 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
|
|
|
16596
17387
|
let existingTokensInline;
|
|
16597
17388
|
if (opts.existingEntitiesPath) {
|
|
16598
17389
|
const existingContentfulEntities = await readExistingContentfulEntitiesFromSession(
|
|
16599
|
-
|
|
17390
|
+
resolve14(opts.existingEntitiesPath)
|
|
16600
17391
|
);
|
|
16601
17392
|
if (existingContentfulEntities) {
|
|
16602
17393
|
existingTokensInline = JSON.stringify(summarizeForMapTokens(existingContentfulEntities));
|
|
@@ -16631,10 +17422,30 @@ ${defaultDiagnostics.map((diagnostic) => ` ${diagnostic}`).join("\n")}
|
|
|
16631
17422
|
skipAgent: "true"
|
|
16632
17423
|
});
|
|
16633
17424
|
updateStep(db, stepId2, "complete", { applied: "0", skipAgent: "true" });
|
|
16634
|
-
await renderResult({ agent: resultAgent, sessionId: sessionId2, applied: 0 });
|
|
17425
|
+
await renderResult({ agent: resultAgent, sessionId: sessionId2, applied: 0, cached: false });
|
|
16635
17426
|
return;
|
|
16636
17427
|
}
|
|
16637
17428
|
const agent = configuredAgent;
|
|
17429
|
+
const noCache = opts.cache === false || process.env.EDS_NO_CACHE === "1";
|
|
17430
|
+
const promptHash = await hashPromptForSkill(
|
|
17431
|
+
"map-tokens",
|
|
17432
|
+
agent,
|
|
17433
|
+
model,
|
|
17434
|
+
void 0,
|
|
17435
|
+
existingTokensInline ? [hashContent(existingTokensInline)] : [],
|
|
17436
|
+
mapPromptText
|
|
17437
|
+
);
|
|
17438
|
+
const inputHash = computeMapTokensInputHash(db, sessionId2, componentSourceRefs);
|
|
17439
|
+
if (!noCache) {
|
|
17440
|
+
const cached = lookupCache(db, inputHash, "token_mapping", "__map_tokens__", promptHash);
|
|
17441
|
+
if (cached) {
|
|
17442
|
+
const appliedFromCache = copyMapTokensFromCache(db, cached.sourceSessionId, sessionId2);
|
|
17443
|
+
const stepId2 = createStep(db, sessionId2, "map tokens", { agent, model: model ?? "" });
|
|
17444
|
+
updateStep(db, stepId2, "complete", { cached: "true", applied: String(appliedFromCache) });
|
|
17445
|
+
await renderResult({ agent, sessionId: sessionId2, applied: appliedFromCache, cached: true });
|
|
17446
|
+
return;
|
|
17447
|
+
}
|
|
17448
|
+
}
|
|
16638
17449
|
const binary = resolveAgentBinary(agent);
|
|
16639
17450
|
if (!await assertBinaryInPath(binary)) {
|
|
16640
17451
|
die(
|
|
@@ -16654,20 +17465,23 @@ Install it, choose another agent with --agent, or use --print-prompt to run the
|
|
|
16654
17465
|
}
|
|
16655
17466
|
const { calls, warnings: parseWarnings } = parseMapTokenPropToolCallLines(result.stdout);
|
|
16656
17467
|
const { applied, warnings } = applyMapTokenPropCalls(db, sessionId2, calls, parseWarnings);
|
|
17468
|
+
if (!noCache) {
|
|
17469
|
+
storeCache(db, inputHash, "token_mapping", "__map_tokens__", sessionId2, false, promptHash);
|
|
17470
|
+
}
|
|
16657
17471
|
updateStep(db, stepId, "complete", { applied: String(applied), warnings: String(warnings.length) });
|
|
16658
17472
|
if (warnings.length > 0) {
|
|
16659
17473
|
process.stderr.write(`Warnings:
|
|
16660
17474
|
${warnings.map((w) => ` ${w}`).join("\n")}
|
|
16661
17475
|
`);
|
|
16662
17476
|
}
|
|
16663
|
-
await renderResult({ agent, sessionId: sessionId2, applied });
|
|
17477
|
+
await renderResult({ agent, sessionId: sessionId2, applied, cached: false });
|
|
16664
17478
|
} finally {
|
|
16665
17479
|
db.close();
|
|
16666
17480
|
}
|
|
16667
17481
|
}
|
|
16668
17482
|
function registerMapTokensCommand(program) {
|
|
16669
17483
|
const map = program.command("map", { hidden: true }).description("Suggest token restrictions for generated design-token props");
|
|
16670
|
-
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(
|
|
17484
|
+
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(
|
|
16671
17485
|
"--prompt <stage=value>",
|
|
16672
17486
|
"Override a stage prompt (repeatable). Used here for the map-tokens stage.",
|
|
16673
17487
|
(v, acc) => [...acc, v],
|
|
@@ -16687,6 +17501,7 @@ var init_command4 = __esm({
|
|
|
16687
17501
|
init_render_with_goodbye();
|
|
16688
17502
|
init_src();
|
|
16689
17503
|
init_db();
|
|
17504
|
+
init_cache_keys();
|
|
16690
17505
|
init_read_existing_contentful_entities_from_session();
|
|
16691
17506
|
init_summarize_existing_contentful_entities();
|
|
16692
17507
|
init_command3();
|
|
@@ -16703,7 +17518,7 @@ var init_command4 = __esm({
|
|
|
16703
17518
|
});
|
|
16704
17519
|
|
|
16705
17520
|
// packages/experience-design-system-cli-legacy/src/import/path-utils.ts
|
|
16706
|
-
import { resolve as
|
|
17521
|
+
import { resolve as resolve15 } from "node:path";
|
|
16707
17522
|
import { homedir as homedir5 } from "node:os";
|
|
16708
17523
|
function expandTilde(input) {
|
|
16709
17524
|
if (input === "~" || input.startsWith("~/") || input.startsWith("~\\")) {
|
|
@@ -16717,7 +17532,7 @@ function normalizePath(input) {
|
|
|
16717
17532
|
p = p.slice(1, -1);
|
|
16718
17533
|
}
|
|
16719
17534
|
p = expandTilde(p);
|
|
16720
|
-
return
|
|
17535
|
+
return resolve15(p);
|
|
16721
17536
|
}
|
|
16722
17537
|
var init_path_utils = __esm({
|
|
16723
17538
|
"packages/experience-design-system-cli-legacy/src/import/path-utils.ts"() {
|
|
@@ -16942,7 +17757,7 @@ var init_save_path_resolver = __esm({
|
|
|
16942
17757
|
});
|
|
16943
17758
|
|
|
16944
17759
|
// packages/experience-design-system-cli-legacy/src/runs/store.ts
|
|
16945
|
-
import { readFile as
|
|
17760
|
+
import { readFile as readFile16, writeFile as writeFile4, mkdir as mkdir4, rename } from "node:fs/promises";
|
|
16946
17761
|
import { join as join20 } from "node:path";
|
|
16947
17762
|
import { homedir as homedir6 } from "node:os";
|
|
16948
17763
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
@@ -16982,7 +17797,7 @@ function migrateRecord(rec) {
|
|
|
16982
17797
|
}
|
|
16983
17798
|
async function readFileMaybe() {
|
|
16984
17799
|
try {
|
|
16985
|
-
const raw = await
|
|
17800
|
+
const raw = await readFile16(RUNS_PATH, "utf8");
|
|
16986
17801
|
const parsed = JSON.parse(raw);
|
|
16987
17802
|
if (!READABLE_VERSIONS.has(parsed.version)) {
|
|
16988
17803
|
throw new Error(
|
|
@@ -17046,15 +17861,15 @@ var init_store = __esm({
|
|
|
17046
17861
|
});
|
|
17047
17862
|
|
|
17048
17863
|
// packages/experience-design-system-cli-legacy/src/runs/fingerprint.ts
|
|
17049
|
-
import { createHash as
|
|
17050
|
-
import { readFile as
|
|
17051
|
-
import { resolve as
|
|
17864
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
17865
|
+
import { readFile as readFile17, stat as stat4 } from "node:fs/promises";
|
|
17866
|
+
import { resolve as resolve16 } from "node:path";
|
|
17052
17867
|
function rowField(row, key) {
|
|
17053
17868
|
const v = row[key];
|
|
17054
17869
|
return typeof v === "string" ? v : null;
|
|
17055
17870
|
}
|
|
17056
17871
|
function sha256Hex(buf) {
|
|
17057
|
-
return
|
|
17872
|
+
return createHash6("sha256").update(buf).digest("hex");
|
|
17058
17873
|
}
|
|
17059
17874
|
async function buildSourceFingerprint(opts) {
|
|
17060
17875
|
const rows = opts.db.prepare("SELECT name, source_path FROM raw_components WHERE session_id = ?").all(opts.extractSessionId);
|
|
@@ -17064,7 +17879,7 @@ async function buildSourceFingerprint(opts) {
|
|
|
17064
17879
|
const sourcePath = rowField(row, "source_path");
|
|
17065
17880
|
const name = rowField(row, "name");
|
|
17066
17881
|
if (!sourcePath) continue;
|
|
17067
|
-
const abs =
|
|
17882
|
+
const abs = resolve16(sourcePath);
|
|
17068
17883
|
if (seen.has(abs)) continue;
|
|
17069
17884
|
seen.add(abs);
|
|
17070
17885
|
try {
|
|
@@ -17079,10 +17894,10 @@ async function buildSourceFingerprint(opts) {
|
|
|
17079
17894
|
let rawTokensMtime = null;
|
|
17080
17895
|
let rawTokensContentHash = null;
|
|
17081
17896
|
if (opts.rawTokensPath) {
|
|
17082
|
-
const abs =
|
|
17897
|
+
const abs = resolve16(opts.rawTokensPath);
|
|
17083
17898
|
rawTokensPath = abs;
|
|
17084
17899
|
try {
|
|
17085
|
-
const [st, buf] = await Promise.all([stat4(abs),
|
|
17900
|
+
const [st, buf] = await Promise.all([stat4(abs), readFile17(abs)]);
|
|
17086
17901
|
rawTokensMtime = st.mtime.toISOString();
|
|
17087
17902
|
rawTokensContentHash = sha256Hex(buf);
|
|
17088
17903
|
} catch {
|
|
@@ -18837,11 +19652,11 @@ var init_slot_graph = __esm({
|
|
|
18837
19652
|
});
|
|
18838
19653
|
|
|
18839
19654
|
// packages/experience-design-system-cli-legacy/src/analyze/select/parser.ts
|
|
18840
|
-
import { createHash as
|
|
19655
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
18841
19656
|
import { access as access5 } from "node:fs/promises";
|
|
18842
|
-
import { isAbsolute, relative, resolve as
|
|
19657
|
+
import { isAbsolute, relative, resolve as resolve17 } from "node:path";
|
|
18843
19658
|
function createComponentId(name, resolvedSourcePath) {
|
|
18844
|
-
const sourceHash =
|
|
19659
|
+
const sourceHash = createHash7("sha256").update(`${name}:${resolvedSourcePath}`).digest("hex").slice(0, 12);
|
|
18845
19660
|
return `${name}-${sourceHash}`;
|
|
18846
19661
|
}
|
|
18847
19662
|
async function resolveComponentSourcePath(source, reviewRoot) {
|
|
@@ -18853,7 +19668,7 @@ async function resolveComponentSourcePath(source, reviewRoot) {
|
|
|
18853
19668
|
throw new Error(`Unable to access component source at ${source}`);
|
|
18854
19669
|
}
|
|
18855
19670
|
}
|
|
18856
|
-
const candidate =
|
|
19671
|
+
const candidate = resolve17(reviewRoot, source);
|
|
18857
19672
|
const relativeToRoot = relative(reviewRoot, candidate);
|
|
18858
19673
|
if (relativeToRoot.startsWith("..") || relativeToRoot === ".." || isAbsolute(relativeToRoot)) {
|
|
18859
19674
|
throw new Error(
|
|
@@ -18868,7 +19683,7 @@ async function resolveComponentSourcePath(source, reviewRoot) {
|
|
|
18868
19683
|
}
|
|
18869
19684
|
}
|
|
18870
19685
|
async function loadReviewInput(components, options = {}) {
|
|
18871
|
-
const reviewRoot =
|
|
19686
|
+
const reviewRoot = resolve17(options.reviewRoot ?? process.cwd());
|
|
18872
19687
|
const records = await Promise.all(
|
|
18873
19688
|
components.map(async (component) => {
|
|
18874
19689
|
let resolvedSourcePath;
|
|
@@ -18899,7 +19714,7 @@ var init_parser = __esm({
|
|
|
18899
19714
|
});
|
|
18900
19715
|
|
|
18901
19716
|
// packages/experience-design-system-cli-legacy/src/analyze/select/command.ts
|
|
18902
|
-
import { access as access6, readFile as
|
|
19717
|
+
import { access as access6, readFile as readFile18 } from "node:fs/promises";
|
|
18903
19718
|
async function loadAndValidateForReview(sessionId2, projectRoot) {
|
|
18904
19719
|
const db = openPipelineDb();
|
|
18905
19720
|
let rawComponents;
|
|
@@ -18917,7 +19732,7 @@ async function patchReviewStateWithValidationErrors(sessionId2, errors, opts = {
|
|
|
18917
19732
|
let snapshot;
|
|
18918
19733
|
try {
|
|
18919
19734
|
await access6(paths.statePath);
|
|
18920
|
-
snapshot = JSON.parse(await
|
|
19735
|
+
snapshot = JSON.parse(await readFile18(paths.statePath, "utf8"));
|
|
18921
19736
|
} catch {
|
|
18922
19737
|
snapshot = await loadAndValidateForReview(sessionId2, void 0);
|
|
18923
19738
|
snapshot = await ensureRefineSession(sessionId2, artifactsRoot, snapshot);
|
|
@@ -18968,7 +19783,7 @@ async function rejectComponentsByName(sessionId2, names, opts = {}) {
|
|
|
18968
19783
|
const nameSet = new Set(names);
|
|
18969
19784
|
let snapshot;
|
|
18970
19785
|
try {
|
|
18971
|
-
snapshot = JSON.parse(await
|
|
19786
|
+
snapshot = JSON.parse(await readFile18(paths.statePath, "utf8"));
|
|
18972
19787
|
} catch {
|
|
18973
19788
|
return;
|
|
18974
19789
|
}
|
|
@@ -19067,9 +19882,9 @@ function spawnGenerateChild(opts) {
|
|
|
19067
19882
|
stderr += chunk;
|
|
19068
19883
|
opts.onStderr?.(chunk);
|
|
19069
19884
|
});
|
|
19070
|
-
const donePromise = new Promise((
|
|
19885
|
+
const donePromise = new Promise((resolve22) => {
|
|
19071
19886
|
child.on("close", (code, signal) => {
|
|
19072
|
-
|
|
19887
|
+
resolve22({
|
|
19073
19888
|
exitCode: code ?? 0,
|
|
19074
19889
|
signal: signal ?? null,
|
|
19075
19890
|
stdout,
|
|
@@ -19077,7 +19892,7 @@ function spawnGenerateChild(opts) {
|
|
|
19077
19892
|
});
|
|
19078
19893
|
});
|
|
19079
19894
|
child.on("error", (err) => {
|
|
19080
|
-
|
|
19895
|
+
resolve22({
|
|
19081
19896
|
exitCode: 1,
|
|
19082
19897
|
signal: null,
|
|
19083
19898
|
stdout,
|
|
@@ -27215,6 +28030,9 @@ function shouldGenerateAfterCredentialsValidated(opts) {
|
|
|
27215
28030
|
function shouldSkipFinalReviewAfterCredentials(state) {
|
|
27216
28031
|
return state.finalReviewPassed && state.generateSessionId != null;
|
|
27217
28032
|
}
|
|
28033
|
+
function resolveNoCacheForGenerate(opts) {
|
|
28034
|
+
return opts.cliNoCache;
|
|
28035
|
+
}
|
|
27218
28036
|
function shouldBypassPreview(state) {
|
|
27219
28037
|
return state.credentialsSkipped === true;
|
|
27220
28038
|
}
|
|
@@ -27241,43 +28059,70 @@ var init_wizard_state_transitions = __esm({
|
|
|
27241
28059
|
async function runSelectionAgent(options) {
|
|
27242
28060
|
const db = openPipelineDb();
|
|
27243
28061
|
let components;
|
|
28062
|
+
const cachedDecisions = /* @__PURE__ */ new Map();
|
|
28063
|
+
const cliVersion2 = await getCliCacheVersion();
|
|
28064
|
+
const promptHash = await hashPromptForSkill(
|
|
28065
|
+
"select",
|
|
28066
|
+
options.agent,
|
|
28067
|
+
options.model,
|
|
28068
|
+
options.promptPath,
|
|
28069
|
+
[SELECT_PAYLOAD_FORMAT],
|
|
28070
|
+
options.promptText
|
|
28071
|
+
);
|
|
27244
28072
|
try {
|
|
27245
28073
|
components = loadRawComponents(db, options.sessionId);
|
|
28074
|
+
if (!options.noCache) {
|
|
28075
|
+
for (const component of components) {
|
|
28076
|
+
const componentHash = hashComponentShape(component);
|
|
28077
|
+
const cached = lookupSelectCache(db, componentHash, promptHash, cliVersion2);
|
|
28078
|
+
if (cached) {
|
|
28079
|
+
cachedDecisions.set(component.name, {
|
|
28080
|
+
decision: cached.decision,
|
|
28081
|
+
reason: cached.reason
|
|
28082
|
+
});
|
|
28083
|
+
}
|
|
28084
|
+
}
|
|
28085
|
+
}
|
|
27246
28086
|
} finally {
|
|
27247
28087
|
db.close();
|
|
27248
28088
|
}
|
|
27249
28089
|
if (components.length === 0) return;
|
|
27250
|
-
const
|
|
27251
|
-
|
|
27252
|
-
|
|
27253
|
-
|
|
27254
|
-
|
|
27255
|
-
|
|
27256
|
-
|
|
27257
|
-
|
|
27258
|
-
|
|
27259
|
-
|
|
27260
|
-
|
|
27261
|
-
|
|
27262
|
-
|
|
27263
|
-
|
|
27264
|
-
|
|
27265
|
-
|
|
27266
|
-
|
|
27267
|
-
|
|
27268
|
-
|
|
27269
|
-
|
|
27270
|
-
|
|
27271
|
-
|
|
27272
|
-
|
|
27273
|
-
|
|
27274
|
-
|
|
27275
|
-
|
|
27276
|
-
|
|
27277
|
-
|
|
27278
|
-
|
|
28090
|
+
const componentsToRun = components.filter((component) => !cachedDecisions.has(component.name));
|
|
28091
|
+
let calls = [];
|
|
28092
|
+
if (componentsToRun.length > 0) {
|
|
28093
|
+
const invoker2 = createLocalCliAgentInvoker({
|
|
28094
|
+
onDebugEvent: (name, payload) => getDebugLogger().event("agent", name, payload)
|
|
28095
|
+
});
|
|
28096
|
+
const selectBuckets = bucketComponentsProps(componentsToRun);
|
|
28097
|
+
for (const assignment of selectBuckets) {
|
|
28098
|
+
getDebugLogger().event("analyze", "prop-buckets.select", { ...assignment });
|
|
28099
|
+
}
|
|
28100
|
+
const prompt = await buildPrompt({
|
|
28101
|
+
skill: "select",
|
|
28102
|
+
mode: "autonomous",
|
|
28103
|
+
rawComponentsInline: JSON.stringify(
|
|
28104
|
+
componentsToRun.map((component) => ({ ...component, props: component.props.map(stripPropProvenance) })),
|
|
28105
|
+
null,
|
|
28106
|
+
2
|
|
28107
|
+
),
|
|
28108
|
+
propBucketsInline: JSON.stringify(selectBuckets),
|
|
28109
|
+
outDir: process.cwd(),
|
|
28110
|
+
...options.promptText !== void 0 ? { skillContentOverride: options.promptText } : {},
|
|
28111
|
+
...options.promptText === void 0 && options.promptPath ? { skillPathOverride: options.promptPath } : {}
|
|
28112
|
+
});
|
|
28113
|
+
const { result } = await invokeAgentWithOutput(
|
|
28114
|
+
invoker2,
|
|
28115
|
+
{ agent: options.agent, model: options.model, prompt, timeoutMs: DEFAULT_TIMEOUT_MS4 },
|
|
28116
|
+
false
|
|
28117
|
+
);
|
|
28118
|
+
if (result.timedOut) throw new Error("selection agent timed out");
|
|
28119
|
+
if (result.exitCode !== 0) throw new Error(`selection agent exited with code ${result.exitCode}`);
|
|
28120
|
+
const parsed = parseSelectToolCallLines(result.stdout);
|
|
28121
|
+
for (const warning of parsed.warnings) process.stderr.write(`Warning: selection agent: ${warning}
|
|
27279
28122
|
`);
|
|
27280
|
-
|
|
28123
|
+
calls = parsed.calls;
|
|
28124
|
+
}
|
|
28125
|
+
const byName = new Map(calls.map((call) => [call.name, call]));
|
|
27281
28126
|
const writeDb = openPipelineDb();
|
|
27282
28127
|
try {
|
|
27283
28128
|
writeDb.exec("BEGIN");
|
|
@@ -27285,15 +28130,27 @@ async function runSelectionAgent(options) {
|
|
|
27285
28130
|
`UPDATE raw_components SET status = ?, reject_reason = ? WHERE session_id = ? AND component_id = ?`
|
|
27286
28131
|
);
|
|
27287
28132
|
for (const component of components) {
|
|
28133
|
+
const cached = cachedDecisions.get(component.name);
|
|
27288
28134
|
const call = byName.get(component.name);
|
|
27289
|
-
if (!call) continue;
|
|
27290
|
-
const rejected = call.tool === "reject_component";
|
|
28135
|
+
if (!cached && !call) continue;
|
|
28136
|
+
const rejected = cached ? cached.decision === "rejected" : call.tool === "reject_component";
|
|
28137
|
+
const reason = cached ? cached.reason : call.reason ?? null;
|
|
27291
28138
|
update.run(
|
|
27292
28139
|
rejected ? "rejected" : "accepted",
|
|
27293
|
-
rejected ?
|
|
28140
|
+
rejected ? reason : null,
|
|
27294
28141
|
options.sessionId,
|
|
27295
28142
|
component.component_id
|
|
27296
28143
|
);
|
|
28144
|
+
if (!cached) {
|
|
28145
|
+
storeSelectCache(
|
|
28146
|
+
writeDb,
|
|
28147
|
+
hashComponentShape(component),
|
|
28148
|
+
promptHash,
|
|
28149
|
+
cliVersion2,
|
|
28150
|
+
rejected ? "rejected" : "accepted",
|
|
28151
|
+
rejected ? reason : null
|
|
28152
|
+
);
|
|
28153
|
+
}
|
|
27297
28154
|
}
|
|
27298
28155
|
writeDb.exec("COMMIT");
|
|
27299
28156
|
} catch (error) {
|
|
@@ -27303,7 +28160,7 @@ async function runSelectionAgent(options) {
|
|
|
27303
28160
|
writeDb.close();
|
|
27304
28161
|
}
|
|
27305
28162
|
}
|
|
27306
|
-
var DEFAULT_TIMEOUT_MS4;
|
|
28163
|
+
var SELECT_PAYLOAD_FORMAT, DEFAULT_TIMEOUT_MS4;
|
|
27307
28164
|
var init_run_selection_agent = __esm({
|
|
27308
28165
|
"packages/experience-design-system-cli-legacy/src/import/tui/run-selection-agent.ts"() {
|
|
27309
28166
|
"use strict";
|
|
@@ -27312,6 +28169,8 @@ var init_run_selection_agent = __esm({
|
|
|
27312
28169
|
init_debug_logger();
|
|
27313
28170
|
init_agent_output();
|
|
27314
28171
|
init_db();
|
|
28172
|
+
init_cache_keys();
|
|
28173
|
+
SELECT_PAYLOAD_FORMAT = "prop-buckets-v1";
|
|
27315
28174
|
DEFAULT_TIMEOUT_MS4 = Number(process.env.EDS_AGENT_TIMEOUT_MS ?? 5 * 60 * 1e3);
|
|
27316
28175
|
}
|
|
27317
28176
|
});
|
|
@@ -27330,7 +28189,7 @@ __export(WizardApp_exports, {
|
|
|
27330
28189
|
});
|
|
27331
28190
|
import { useEffect as useEffect15, useRef as useRef10, useState as useState23 } from "react";
|
|
27332
28191
|
import { Box as Box42, Text as Text46 } from "ink";
|
|
27333
|
-
import { join as join23, resolve as
|
|
28192
|
+
import { join as join23, resolve as resolve18 } from "node:path";
|
|
27334
28193
|
import { appendFileSync as appendFileSync2, writeFileSync } from "node:fs";
|
|
27335
28194
|
import { access as access7, stat as stat5, writeFile as writeFile6 } from "node:fs/promises";
|
|
27336
28195
|
import { tmpdir } from "node:os";
|
|
@@ -27343,21 +28202,28 @@ function buildGenerateComponentsArgs(opts) {
|
|
|
27343
28202
|
if (opts.tokensPath) args.push("--tokens", opts.tokensPath);
|
|
27344
28203
|
if (opts.model) args.push("--model", opts.model);
|
|
27345
28204
|
if (opts.bedrock) args.push("--bedrock");
|
|
28205
|
+
if (opts.noCache) args.push("--no-cache");
|
|
27346
28206
|
if (opts.generatePromptPath) args.push("--generate-prompt-path", opts.generatePromptPath);
|
|
27347
28207
|
for (const prompt of opts.promptOverrides ?? []) args.push("--prompt", prompt);
|
|
27348
28208
|
if (opts.existingEntitiesPath) args.push("--existing-entities-path", opts.existingEntitiesPath);
|
|
28209
|
+
if (opts.restoreCache) args.push("--restore-cache");
|
|
28210
|
+
if (opts.cachedComponents && opts.cachedComponents.length > 0) {
|
|
28211
|
+
args.push("--cached-components", JSON.stringify(opts.cachedComponents));
|
|
28212
|
+
}
|
|
27349
28213
|
return args;
|
|
27350
28214
|
}
|
|
27351
28215
|
function buildGenerateTokensArgs(opts) {
|
|
27352
28216
|
const args = [findCliPath(), "__generate", "tokens", "--agent", opts.agent, "--raw-tokens", opts.rawTokensPath];
|
|
27353
28217
|
if (opts.model) args.push("--model", opts.model);
|
|
27354
28218
|
if (opts.bedrock) args.push("--bedrock");
|
|
28219
|
+
if (opts.noCache) args.push("--no-cache");
|
|
27355
28220
|
for (const prompt of opts.promptOverrides ?? []) args.push("--prompt", prompt);
|
|
27356
28221
|
return args;
|
|
27357
28222
|
}
|
|
27358
28223
|
function buildMapTokensArgs(opts) {
|
|
27359
28224
|
const args = ["map", "tokens", "--session", opts.sessionId, "--agent", opts.agent];
|
|
27360
28225
|
if (opts.model) args.push("--model", opts.model);
|
|
28226
|
+
if (opts.noCache) args.push("--no-cache");
|
|
27361
28227
|
if (opts.skipAgent) args.push("--skip-agent");
|
|
27362
28228
|
for (const prompt of opts.promptOverrides ?? []) args.push("--prompt", prompt);
|
|
27363
28229
|
if (opts.existingEntitiesPath) args.push("--existing-entities-path", opts.existingEntitiesPath);
|
|
@@ -27449,6 +28315,7 @@ function WizardApp({
|
|
|
27449
28315
|
initialProjectPath,
|
|
27450
28316
|
host,
|
|
27451
28317
|
promptOverrides,
|
|
28318
|
+
noCache = false,
|
|
27452
28319
|
livePreview = true,
|
|
27453
28320
|
generatePromptPath,
|
|
27454
28321
|
skipMapTokens = false,
|
|
@@ -27473,6 +28340,7 @@ function WizardApp({
|
|
|
27473
28340
|
});
|
|
27474
28341
|
const allowEmptyDeleteAllRef = useRef10(false);
|
|
27475
28342
|
const generateChildRef = useRef10(null);
|
|
28343
|
+
const generationCachePreflightRef = useRef10(null);
|
|
27476
28344
|
const selectionToReviewStartedAtRef = useRef10(null);
|
|
27477
28345
|
const credentialsValidationIdRef = useRef10(0);
|
|
27478
28346
|
const pendingCredentialValidationRef = useRef10(null);
|
|
@@ -27487,8 +28355,9 @@ function WizardApp({
|
|
|
27487
28355
|
const existingEntitiesPromiseRef = useRef10(null);
|
|
27488
28356
|
const generatePromiseRef = useRef10(null);
|
|
27489
28357
|
const rawTokensEntryReady = !!initialRawTokensPath;
|
|
28358
|
+
const effectiveNoCache = resolveNoCacheForGenerate({ cliNoCache: noCache });
|
|
27490
28359
|
const initialStepResolved = rawTokensEntryReady ? initialProjectPath ? "path-validation" : "credentials" : initialProjectPath ? "token-input" : "welcome";
|
|
27491
|
-
const initialOutDir = initialProjectPath ? join23(
|
|
28360
|
+
const initialOutDir = initialProjectPath ? join23(resolve18(initialProjectPath), ".contentful") : "";
|
|
27492
28361
|
const [state, setState] = useState23({
|
|
27493
28362
|
step: initialStepResolved,
|
|
27494
28363
|
agent: initialAgent ?? "claude",
|
|
@@ -27664,13 +28533,14 @@ If you are using AWS Bedrock, run:
|
|
|
27664
28533
|
if (!deferStep) update({ step: nextStep });
|
|
27665
28534
|
return true;
|
|
27666
28535
|
};
|
|
27667
|
-
const runGenerateTokens = async (rawTokensPath, outDir) => {
|
|
28536
|
+
const runGenerateTokens = async (rawTokensPath, outDir, forceRegenerate = false) => {
|
|
27668
28537
|
update({ tokenGenerationStatus: "running" });
|
|
27669
28538
|
const tokenArgs = buildGenerateTokensArgs({
|
|
27670
28539
|
rawTokensPath,
|
|
27671
28540
|
agent: state.agent,
|
|
27672
28541
|
...state.agentModel ? { model: state.agentModel } : {},
|
|
27673
28542
|
...state.bedrock ? { bedrock: true } : {},
|
|
28543
|
+
noCache: effectiveNoCache || forceRegenerate,
|
|
27674
28544
|
promptOverrides
|
|
27675
28545
|
});
|
|
27676
28546
|
const result = await runSpawnedCli(tokenArgs);
|
|
@@ -27719,6 +28589,7 @@ If you are using AWS Bedrock, run:
|
|
|
27719
28589
|
const timer = startWizardTimer("token-mapping", {
|
|
27720
28590
|
sessionId: sessionId2,
|
|
27721
28591
|
silent,
|
|
28592
|
+
noCache: effectiveNoCache,
|
|
27722
28593
|
skipAgent: skipMapTokens
|
|
27723
28594
|
});
|
|
27724
28595
|
let mappablePropCount = 0;
|
|
@@ -27727,7 +28598,7 @@ If you are using AWS Bedrock, run:
|
|
|
27727
28598
|
const db = openPipelineDb();
|
|
27728
28599
|
try {
|
|
27729
28600
|
if (state.tokenSessionId && state.tokenSessionId !== sessionId2) {
|
|
27730
|
-
|
|
28601
|
+
copyTokensFromCache(db, state.tokenSessionId, sessionId2);
|
|
27731
28602
|
} else if (!state.tokenSessionId && state.tokensPath) {
|
|
27732
28603
|
const tokens = await readTokensFromPath("tokens", state.tokensPath);
|
|
27733
28604
|
storeDtcgTokens(db, sessionId2, [], tokens);
|
|
@@ -27767,6 +28638,7 @@ If you are using AWS Bedrock, run:
|
|
|
27767
28638
|
sessionId: sessionId2,
|
|
27768
28639
|
agent: state.agent,
|
|
27769
28640
|
...state.agentModel ? { model: state.agentModel } : {},
|
|
28641
|
+
noCache: effectiveNoCache,
|
|
27770
28642
|
skipAgent: skipMapTokens,
|
|
27771
28643
|
promptOverrides,
|
|
27772
28644
|
...state.existingEntitiesPath ? { existingEntitiesPath: state.existingEntitiesPath } : {}
|
|
@@ -27846,7 +28718,7 @@ If you are using AWS Bedrock, run:
|
|
|
27846
28718
|
return promise;
|
|
27847
28719
|
};
|
|
27848
28720
|
const runExtract = async (projectPath, showProgress = true) => {
|
|
27849
|
-
const outDir = join23(
|
|
28721
|
+
const outDir = join23(resolve18(projectPath), ".contentful");
|
|
27850
28722
|
const existingEntitiesExpected = !state.credentialsSkipped && Boolean(state.spaceId && state.environmentId && state.cmaToken && projectPath);
|
|
27851
28723
|
update({
|
|
27852
28724
|
...showProgress ? { step: "extracting" } : {},
|
|
@@ -27861,6 +28733,10 @@ If you are using AWS Bedrock, run:
|
|
|
27861
28733
|
});
|
|
27862
28734
|
const existingEntitiesPromise = startExistingEntitiesFetch(projectPath, outDir);
|
|
27863
28735
|
const extractArgs = [findCliPath(), "__extract", "--project", projectPath];
|
|
28736
|
+
if (effectiveNoCache) extractArgs.push("--composition-refresh", "--no-cache");
|
|
28737
|
+
for (const p of promptOverrides ?? []) extractArgs.push("--prompt", p);
|
|
28738
|
+
if (state.agent) extractArgs.push("--agent", state.agent);
|
|
28739
|
+
if (state.bedrock) extractArgs.push("--bedrock");
|
|
27864
28740
|
let selectionPromptText;
|
|
27865
28741
|
let selectionPromptPath;
|
|
27866
28742
|
try {
|
|
@@ -27869,7 +28745,7 @@ If you are using AWS Bedrock, run:
|
|
|
27869
28745
|
const selectOverride = overrides.get("select");
|
|
27870
28746
|
if (selectOverride?.kind === "text") selectionPromptText = selectOverride.value;
|
|
27871
28747
|
if (selectOverride?.kind === "path") {
|
|
27872
|
-
selectionPromptPath =
|
|
28748
|
+
selectionPromptPath = resolve18(selectOverride.value);
|
|
27873
28749
|
await resolvePromptOverride(selectOverride);
|
|
27874
28750
|
}
|
|
27875
28751
|
} catch (error) {
|
|
@@ -27893,7 +28769,8 @@ If you are using AWS Bedrock, run:
|
|
|
27893
28769
|
agent: state.agent,
|
|
27894
28770
|
...state.agentModel ? { model: state.agentModel } : {},
|
|
27895
28771
|
...selectionPromptText !== void 0 ? { promptText: selectionPromptText } : {},
|
|
27896
|
-
...selectionPromptPath ? { promptPath: selectionPromptPath } : {}
|
|
28772
|
+
...selectionPromptPath ? { promptPath: selectionPromptPath } : {},
|
|
28773
|
+
noCache: effectiveNoCache
|
|
27897
28774
|
});
|
|
27898
28775
|
})().catch((error) => {
|
|
27899
28776
|
selectionError = error;
|
|
@@ -28038,17 +28915,136 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
|
|
|
28038
28915
|
generateProgress: null
|
|
28039
28916
|
}));
|
|
28040
28917
|
};
|
|
28041
|
-
const buildGenerateOptions = (extractSessionId, tokensPath, generatePromptPath2) => ({
|
|
28918
|
+
const buildGenerateOptions = (extractSessionId, tokensPath, generatePromptPath2, cachedComponents) => ({
|
|
28042
28919
|
sessionId: extractSessionId,
|
|
28043
28920
|
tokensPath,
|
|
28044
28921
|
agent: state.agent,
|
|
28045
28922
|
...state.agentModel ? { model: state.agentModel } : {},
|
|
28046
28923
|
...state.bedrock ? { bedrock: true } : {},
|
|
28924
|
+
noCache: effectiveNoCache,
|
|
28047
28925
|
...state.existingEntitiesPath ? { existingEntitiesPath: state.existingEntitiesPath } : {},
|
|
28048
28926
|
...generatePromptPath2 ? { generatePromptPath: generatePromptPath2 } : {},
|
|
28049
|
-
promptOverrides
|
|
28927
|
+
promptOverrides,
|
|
28928
|
+
...cachedComponents && cachedComponents.length > 0 ? { cachedComponents } : {}
|
|
28050
28929
|
});
|
|
28051
|
-
const buildGenerateArgs = (extractSessionId, tokensPath, generatePromptPath2) => buildGenerateProcessArgs(buildGenerateOptions(extractSessionId, tokensPath, generatePromptPath2));
|
|
28930
|
+
const buildGenerateArgs = (extractSessionId, tokensPath, generatePromptPath2, cachedComponents) => buildGenerateProcessArgs(buildGenerateOptions(extractSessionId, tokensPath, generatePromptPath2, cachedComponents));
|
|
28931
|
+
const buildGenerateCliArgs = (extractSessionId, tokensPath, generatePromptPath2, cachedComponents) => buildGenerateComponentsArgs(
|
|
28932
|
+
buildGenerateOptions(extractSessionId, tokensPath, generatePromptPath2, cachedComponents)
|
|
28933
|
+
);
|
|
28934
|
+
const checkGenerateCache = async (extractSessionId, tokensPath) => {
|
|
28935
|
+
const timer = startWizardTimer("generation-cache-status", {
|
|
28936
|
+
sessionId: extractSessionId,
|
|
28937
|
+
noCache: effectiveNoCache
|
|
28938
|
+
});
|
|
28939
|
+
if (effectiveNoCache) {
|
|
28940
|
+
finishWizardTimer("generation-cache-status", timer, { status: "skipped" });
|
|
28941
|
+
return false;
|
|
28942
|
+
}
|
|
28943
|
+
const result = await runCli([...buildGenerateCliArgs(extractSessionId, tokensPath), "--cache-status"]);
|
|
28944
|
+
const hit = result.exitCode === 0 && /^cache-status=hit$/m.test(result.stdout);
|
|
28945
|
+
finishWizardTimer("generation-cache-status", timer, {
|
|
28946
|
+
status: hit ? "hit" : "miss",
|
|
28947
|
+
exitCode: result.exitCode,
|
|
28948
|
+
...result.exitCode !== 0 ? { stderrTail: result.stderr.trim().slice(-500) } : {}
|
|
28949
|
+
});
|
|
28950
|
+
return hit;
|
|
28951
|
+
};
|
|
28952
|
+
const checkGenerateCacheComponents = async (extractSessionId, tokensPath, restoreCache = false) => {
|
|
28953
|
+
const timer = startWizardTimer("generation-cache-components", {
|
|
28954
|
+
sessionId: extractSessionId,
|
|
28955
|
+
restoreCache,
|
|
28956
|
+
noCache: effectiveNoCache
|
|
28957
|
+
});
|
|
28958
|
+
if (effectiveNoCache) {
|
|
28959
|
+
finishWizardTimer("generation-cache-components", timer, { status: "skipped" });
|
|
28960
|
+
return /* @__PURE__ */ new Set();
|
|
28961
|
+
}
|
|
28962
|
+
const args = [...buildGenerateCliArgs(extractSessionId, tokensPath), "--cache-status"];
|
|
28963
|
+
if (restoreCache) args.push("--restore-cache");
|
|
28964
|
+
const result = await runCli(args);
|
|
28965
|
+
if (result.exitCode !== 0) {
|
|
28966
|
+
finishWizardTimer("generation-cache-components", timer, {
|
|
28967
|
+
status: "error",
|
|
28968
|
+
exitCode: result.exitCode,
|
|
28969
|
+
stderrTail: result.stderr.trim().slice(-500)
|
|
28970
|
+
});
|
|
28971
|
+
return /* @__PURE__ */ new Set();
|
|
28972
|
+
}
|
|
28973
|
+
const line = /^cache-components=(.+)$/m.exec(result.stdout)?.[1];
|
|
28974
|
+
if (!line) {
|
|
28975
|
+
finishWizardTimer("generation-cache-components", timer, {
|
|
28976
|
+
status: "missing-output",
|
|
28977
|
+
exitCode: result.exitCode,
|
|
28978
|
+
cachedCount: 0
|
|
28979
|
+
});
|
|
28980
|
+
return /* @__PURE__ */ new Set();
|
|
28981
|
+
}
|
|
28982
|
+
try {
|
|
28983
|
+
const names = JSON.parse(line);
|
|
28984
|
+
const cachedNames = new Set(
|
|
28985
|
+
Array.isArray(names) ? names.filter((name) => typeof name === "string") : []
|
|
28986
|
+
);
|
|
28987
|
+
finishWizardTimer("generation-cache-components", timer, {
|
|
28988
|
+
status: "complete",
|
|
28989
|
+
exitCode: result.exitCode,
|
|
28990
|
+
cachedCount: cachedNames.size
|
|
28991
|
+
});
|
|
28992
|
+
return cachedNames;
|
|
28993
|
+
} catch {
|
|
28994
|
+
finishWizardTimer("generation-cache-components", timer, {
|
|
28995
|
+
status: "invalid-output",
|
|
28996
|
+
exitCode: result.exitCode,
|
|
28997
|
+
cachedCount: 0
|
|
28998
|
+
});
|
|
28999
|
+
return /* @__PURE__ */ new Set();
|
|
29000
|
+
}
|
|
29001
|
+
};
|
|
29002
|
+
useEffect15(() => {
|
|
29003
|
+
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) {
|
|
29004
|
+
return;
|
|
29005
|
+
}
|
|
29006
|
+
const sessionId2 = state.extractSessionId;
|
|
29007
|
+
if (generationCachePreflightRef.current?.sessionId === sessionId2) return;
|
|
29008
|
+
const timer = startWizardTimer("generation-cache-preflight", { sessionId: sessionId2 });
|
|
29009
|
+
const db = openPipelineDb();
|
|
29010
|
+
let generatedNames = null;
|
|
29011
|
+
try {
|
|
29012
|
+
const rows = db.prepare("SELECT name, status FROM raw_components WHERE session_id = ?").all(sessionId2);
|
|
29013
|
+
if (rows.length > 0 && rows.every((row) => row.status === "generated")) {
|
|
29014
|
+
generatedNames = new Set(rows.map((row) => row.name));
|
|
29015
|
+
}
|
|
29016
|
+
} finally {
|
|
29017
|
+
db.close();
|
|
29018
|
+
}
|
|
29019
|
+
if (generatedNames) {
|
|
29020
|
+
generationCachePreflightRef.current = { sessionId: sessionId2, promise: Promise.resolve(generatedNames) };
|
|
29021
|
+
finishWizardTimer("generation-cache-preflight", timer, {
|
|
29022
|
+
status: "complete",
|
|
29023
|
+
source: "session-db",
|
|
29024
|
+
cachedCount: generatedNames.size
|
|
29025
|
+
});
|
|
29026
|
+
return;
|
|
29027
|
+
}
|
|
29028
|
+
const promise = checkGenerateCacheComponents(sessionId2, state.tokensPath, true);
|
|
29029
|
+
generationCachePreflightRef.current = { sessionId: sessionId2, promise };
|
|
29030
|
+
void promise.then((cachedNames) => {
|
|
29031
|
+
finishWizardTimer("generation-cache-preflight", timer, {
|
|
29032
|
+
status: "complete",
|
|
29033
|
+
source: "cache-status",
|
|
29034
|
+
cachedCount: cachedNames.size
|
|
29035
|
+
});
|
|
29036
|
+
});
|
|
29037
|
+
}, [
|
|
29038
|
+
state.step,
|
|
29039
|
+
state.extractSessionId,
|
|
29040
|
+
state.tokensPath,
|
|
29041
|
+
state.rawTokensPath,
|
|
29042
|
+
state.tokenGenerationStatus,
|
|
29043
|
+
state.selectionAgentStatus,
|
|
29044
|
+
state.compositionPhase,
|
|
29045
|
+
state.existingEntitiesStatus,
|
|
29046
|
+
state.existingEntitiesPath
|
|
29047
|
+
]);
|
|
28052
29048
|
const startGeneratePrefetch = (extractSessionId, tokensPath) => {
|
|
28053
29049
|
const args = buildGenerateArgs(extractSessionId, tokensPath);
|
|
28054
29050
|
let progressCursor = null;
|
|
@@ -28103,13 +29099,14 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
|
|
|
28103
29099
|
});
|
|
28104
29100
|
return donePromise;
|
|
28105
29101
|
};
|
|
28106
|
-
const runGenerate = async (extractSessionId, tokensPath, acceptedCount, suppressScreen = false) => {
|
|
29102
|
+
const runGenerate = async (extractSessionId, tokensPath, acceptedCount, suppressScreen = false, cachedComponents = []) => {
|
|
28107
29103
|
const timer = startWizardTimer("component-generation", {
|
|
28108
29104
|
sessionId: extractSessionId,
|
|
28109
29105
|
acceptedCount,
|
|
28110
|
-
suppressScreen
|
|
29106
|
+
suppressScreen,
|
|
29107
|
+
noCache: effectiveNoCache
|
|
28111
29108
|
});
|
|
28112
|
-
const args = buildGenerateArgs(extractSessionId, tokensPath, generatePromptPath);
|
|
29109
|
+
const args = buildGenerateArgs(extractSessionId, tokensPath, generatePromptPath, cachedComponents);
|
|
28113
29110
|
let progressCursor = state.generateProgress;
|
|
28114
29111
|
const { donePromise } = spawnGenerateChild({
|
|
28115
29112
|
command: "node",
|
|
@@ -28179,6 +29176,25 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
|
|
|
28179
29176
|
finishSelectionToReviewTimer("error");
|
|
28180
29177
|
}
|
|
28181
29178
|
};
|
|
29179
|
+
const finishCachedGeneration = async (sessionId2, acceptedCount) => {
|
|
29180
|
+
if (await runMapTokens2(sessionId2, true)) {
|
|
29181
|
+
finishSelectionToReviewTimer("cached");
|
|
29182
|
+
update(
|
|
29183
|
+
{
|
|
29184
|
+
acceptedCount,
|
|
29185
|
+
autoRejectedCount: 0,
|
|
29186
|
+
generateSessionId: sessionId2,
|
|
29187
|
+
generatedCount: acceptedCount,
|
|
29188
|
+
generateProgress: null,
|
|
29189
|
+
mapTokensStatus: "complete",
|
|
29190
|
+
step: "final-review"
|
|
29191
|
+
},
|
|
29192
|
+
{ clearScreen: false }
|
|
29193
|
+
);
|
|
29194
|
+
} else {
|
|
29195
|
+
finishSelectionToReviewTimer("error");
|
|
29196
|
+
}
|
|
29197
|
+
};
|
|
28182
29198
|
const advanceToPushFlow = (generatedAcceptedCount) => {
|
|
28183
29199
|
update({ generatedAcceptedCount });
|
|
28184
29200
|
void runSaveAndPush();
|
|
@@ -28363,8 +29379,14 @@ Make sure this path contains TypeScript/React/Vue component files (.tsx, .ts, .v
|
|
|
28363
29379
|
}
|
|
28364
29380
|
}
|
|
28365
29381
|
if (await runAgentAuthCheck("generating", true)) {
|
|
28366
|
-
|
|
28367
|
-
|
|
29382
|
+
const cacheHit = await checkGenerateCache(sid, state.tokensPath);
|
|
29383
|
+
if (cacheHit) {
|
|
29384
|
+
update({ step: "generating" });
|
|
29385
|
+
void finishCachedGeneration(sid, state.acceptedCount);
|
|
29386
|
+
} else {
|
|
29387
|
+
update({ step: "generating" });
|
|
29388
|
+
void runGenerate(sid, state.tokensPath, state.acceptedCount);
|
|
29389
|
+
}
|
|
28368
29390
|
}
|
|
28369
29391
|
return;
|
|
28370
29392
|
}
|
|
@@ -28728,7 +29750,7 @@ If using a custom host configuration, make sure the space exists on that host.`
|
|
|
28728
29750
|
});
|
|
28729
29751
|
return { ok: false };
|
|
28730
29752
|
}
|
|
28731
|
-
await new Promise((
|
|
29753
|
+
await new Promise((resolve22) => setTimeout(resolve22, SAVE_CONFIRMATION_DELAY_MS));
|
|
28732
29754
|
update(nextStateAfterPrint({ skipGate: opts.skipGate, componentsPath }));
|
|
28733
29755
|
return { ok: true };
|
|
28734
29756
|
};
|
|
@@ -28805,6 +29827,12 @@ If using a custom host configuration, make sure the space exists on that host.`
|
|
|
28805
29827
|
tokenReuseChecked.current = true;
|
|
28806
29828
|
const tokenNextStep = state.projectPath ? "path-validation" : "credentials";
|
|
28807
29829
|
const existingTokensPath = join23(state.outDir, "tokens.json");
|
|
29830
|
+
if (effectiveNoCache) {
|
|
29831
|
+
tokenGenerationPromiseRef.current = runAgentAuthCheck(tokenNextStep).then(
|
|
29832
|
+
(ok2) => ok2 ? runGenerateTokens(state.rawTokensPath, state.outDir) : false
|
|
29833
|
+
);
|
|
29834
|
+
return;
|
|
29835
|
+
}
|
|
28808
29836
|
(async () => {
|
|
28809
29837
|
try {
|
|
28810
29838
|
await access7(existingTokensPath);
|
|
@@ -28888,7 +29916,7 @@ If using a custom host configuration, make sure the space exists on that host.`
|
|
|
28888
29916
|
const tokenNextStep = state.projectPath ? "path-validation" : "credentials";
|
|
28889
29917
|
update({ step: tokenNextStep });
|
|
28890
29918
|
if (await runAgentAuthCheck(tokenNextStep)) {
|
|
28891
|
-
tokenGenerationPromiseRef.current = runGenerateTokens(state.rawTokensPath, state.outDir);
|
|
29919
|
+
tokenGenerationPromiseRef.current = runGenerateTokens(state.rawTokensPath, state.outDir, true);
|
|
28892
29920
|
}
|
|
28893
29921
|
},
|
|
28894
29922
|
onQuit: () => process.exit(0)
|
|
@@ -28922,7 +29950,7 @@ If using a custom host configuration, make sure the space exists on that host.`
|
|
|
28922
29950
|
);
|
|
28923
29951
|
case "extracting": {
|
|
28924
29952
|
const ep = state.extractProgress;
|
|
28925
|
-
const compositionComplete = state.compositionPhase === "done";
|
|
29953
|
+
const compositionComplete = state.compositionPhase === "done" || state.compositionPhase === "cache-hit";
|
|
28926
29954
|
const tokenGenerationComplete = !state.rawTokensPath || state.tokenGenerationStatus === "complete";
|
|
28927
29955
|
const extractionTasksComplete = ep !== null && ep.totalFiles > 0 && compositionComplete && state.selectionAgentStatus === "complete" && tokenGenerationComplete && state.existingEntitiesStatus !== "running";
|
|
28928
29956
|
if (extractionTasksComplete) return null;
|
|
@@ -28937,7 +29965,7 @@ If using a custom host configuration, make sure the space exists on that host.`
|
|
|
28937
29965
|
extractDetail = "Scanning files...";
|
|
28938
29966
|
}
|
|
28939
29967
|
const selectionDetail = state.selectionAgentStatus === "complete" ? "Selection agent complete" : `Filtering component selection via ${state.agent}...`;
|
|
28940
|
-
const compositionDetail = compositionComplete ? "Composition mapping complete" : "Mapping composition
|
|
29968
|
+
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}...`;
|
|
28941
29969
|
return /* @__PURE__ */ jsx50(
|
|
28942
29970
|
RunningStep,
|
|
28943
29971
|
{
|
|
@@ -28987,6 +30015,29 @@ If using a custom host configuration, make sure the space exists on that host.`
|
|
|
28987
30015
|
acceptedCount: decisions.accepted.length,
|
|
28988
30016
|
rejectedCount: decisions.rejected.length
|
|
28989
30017
|
}) : null;
|
|
30018
|
+
const preflight = generationCachePreflightRef.current;
|
|
30019
|
+
const cachePromise = preflight?.sessionId === sessionId2 ? preflight.promise : checkGenerateCacheComponents(sessionId2, state.tokensPath, true);
|
|
30020
|
+
if (!preflight || preflight.sessionId !== sessionId2) {
|
|
30021
|
+
generationCachePreflightRef.current = { sessionId: sessionId2, promise: cachePromise };
|
|
30022
|
+
}
|
|
30023
|
+
const cacheWaitStartedAt = startWizardTimer("selection-cache-restoration-wait", {
|
|
30024
|
+
sessionId: sessionId2,
|
|
30025
|
+
preflight: Boolean(preflight?.sessionId === sessionId2)
|
|
30026
|
+
});
|
|
30027
|
+
try {
|
|
30028
|
+
const cachedNames = await cachePromise;
|
|
30029
|
+
finishWizardTimer("selection-cache-restoration-wait", cacheWaitStartedAt, {
|
|
30030
|
+
status: "complete",
|
|
30031
|
+
cachedCount: cachedNames.size
|
|
30032
|
+
});
|
|
30033
|
+
} catch (error) {
|
|
30034
|
+
finishWizardTimer("selection-cache-restoration-wait", cacheWaitStartedAt, {
|
|
30035
|
+
status: "error",
|
|
30036
|
+
error: error instanceof Error ? error.message : String(error)
|
|
30037
|
+
});
|
|
30038
|
+
finishSelectionToReviewTimer("error");
|
|
30039
|
+
throw error;
|
|
30040
|
+
}
|
|
28990
30041
|
await runScopeGate({
|
|
28991
30042
|
sessionId: sessionId2,
|
|
28992
30043
|
decisions,
|
|
@@ -28995,12 +30046,35 @@ If using a custom host configuration, make sure the space exists on that host.`
|
|
|
28995
30046
|
if (shouldGenerateAfterScopeGate({ acceptedCount })) {
|
|
28996
30047
|
const authPromise = runAgentAuthCheck("generating", true);
|
|
28997
30048
|
if (await authPromise) {
|
|
28998
|
-
|
|
28999
|
-
|
|
29000
|
-
|
|
29001
|
-
|
|
30049
|
+
const comparisonStartedAt = startWizardTimer("generation-cache-set-comparison", {
|
|
30050
|
+
sessionId: sid,
|
|
30051
|
+
acceptedCount: decisions?.accepted.length ?? 0
|
|
30052
|
+
});
|
|
30053
|
+
let cachedNames = await cachePromise;
|
|
30054
|
+
const acceptedNames = decisions?.accepted ?? [];
|
|
30055
|
+
let cacheHit = !effectiveNoCache && acceptedNames.length > 0 && acceptedNames.every((name) => cachedNames.has(name));
|
|
30056
|
+
if (!cacheHit && !effectiveNoCache && acceptedNames.length > 0) {
|
|
30057
|
+
cachedNames = await checkGenerateCacheComponents(sid, state.tokensPath, true);
|
|
30058
|
+
cacheHit = acceptedNames.every((name) => cachedNames.has(name));
|
|
30059
|
+
}
|
|
30060
|
+
finishWizardTimer("generation-cache-set-comparison", comparisonStartedAt, {
|
|
30061
|
+
status: "complete",
|
|
30062
|
+
cacheHit,
|
|
30063
|
+
cachedCount: cachedNames.size,
|
|
30064
|
+
acceptedCount: acceptedNames.length
|
|
29002
30065
|
});
|
|
29003
|
-
|
|
30066
|
+
if (cacheHit) {
|
|
30067
|
+
void finishCachedGeneration(sid, acceptedCount);
|
|
30068
|
+
} else {
|
|
30069
|
+
const acceptedNameSet = new Set(acceptedNames);
|
|
30070
|
+
const restoredCachedNames = [...cachedNames].filter((name) => acceptedNameSet.has(name));
|
|
30071
|
+
update({
|
|
30072
|
+
step: "generating",
|
|
30073
|
+
generateProgress: null,
|
|
30074
|
+
acceptedCount
|
|
30075
|
+
});
|
|
30076
|
+
void runGenerate(sid, state.tokensPath, acceptedCount, false, restoredCachedNames);
|
|
30077
|
+
}
|
|
29004
30078
|
} else {
|
|
29005
30079
|
finishSelectionToReviewTimer("error");
|
|
29006
30080
|
}
|
|
@@ -29366,7 +30440,7 @@ function registerImportCommand(program) {
|
|
|
29366
30440
|
"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",
|
|
29367
30441
|
(v, acc) => [...acc, v],
|
|
29368
30442
|
[]
|
|
29369
|
-
).action(async (opts) => {
|
|
30443
|
+
).option("--no-cache", "Re-run all steps even if output already exists").action(async (opts) => {
|
|
29370
30444
|
const interactiveTerminalSupported = getInteractiveTerminalSupport().supported;
|
|
29371
30445
|
if (opts.tokens !== void 0) {
|
|
29372
30446
|
const { access: access9 } = await import("node:fs/promises");
|
|
@@ -29403,6 +30477,7 @@ function registerImportCommand(program) {
|
|
|
29403
30477
|
...resolvedModel ? { initialModel: resolvedModel } : {},
|
|
29404
30478
|
initialProjectPath: opts.project !== "." ? normalizePath(opts.project) : void 0,
|
|
29405
30479
|
...buildCompositionForwardingOptions(opts),
|
|
30480
|
+
noCache: opts.cache === false,
|
|
29406
30481
|
skipMapTokens: false,
|
|
29407
30482
|
livePreview: true,
|
|
29408
30483
|
generatePromptPath: creds.generatePromptPath,
|
|
@@ -29490,7 +30565,7 @@ async function pathExists3(path) {
|
|
|
29490
30565
|
return access8(path).then(() => true).catch(() => false);
|
|
29491
30566
|
}
|
|
29492
30567
|
function runSpawn(cmd, args, opts = {}) {
|
|
29493
|
-
return new Promise((
|
|
30568
|
+
return new Promise((resolve22) => {
|
|
29494
30569
|
const child = spawn6(cmd, args, {
|
|
29495
30570
|
cwd: opts.cwd,
|
|
29496
30571
|
env: opts.env ?? process.env,
|
|
@@ -29502,7 +30577,7 @@ function runSpawn(cmd, args, opts = {}) {
|
|
|
29502
30577
|
const settle = (result) => {
|
|
29503
30578
|
if (settled) return;
|
|
29504
30579
|
settled = true;
|
|
29505
|
-
|
|
30580
|
+
resolve22(result);
|
|
29506
30581
|
};
|
|
29507
30582
|
child.on("error", (err) => settle({ exitCode: 1, stdout: "", stderr: err.message }));
|
|
29508
30583
|
child.stdout.on("data", (d) => {
|
|
@@ -30703,13 +31778,13 @@ function PrerequisitesScreen({
|
|
|
30703
31778
|
const driver = {
|
|
30704
31779
|
...base,
|
|
30705
31780
|
emit: (event) => setEvents((current) => [...current, event]),
|
|
30706
|
-
confirm: (question, defaultYes = true) => new Promise((
|
|
31781
|
+
confirm: (question, defaultYes = true) => new Promise((resolve22) => {
|
|
30707
31782
|
setConfirm({
|
|
30708
31783
|
question,
|
|
30709
31784
|
defaultYes,
|
|
30710
31785
|
resolve: (answer) => {
|
|
30711
31786
|
setConfirm(null);
|
|
30712
|
-
|
|
31787
|
+
resolve22(answer);
|
|
30713
31788
|
}
|
|
30714
31789
|
});
|
|
30715
31790
|
})
|
|
@@ -30784,8 +31859,8 @@ function SetupScreen({
|
|
|
30784
31859
|
useEffect21(() => {
|
|
30785
31860
|
if (startedRef.current) return;
|
|
30786
31861
|
startedRef.current = true;
|
|
30787
|
-
const runScreen = (build) => new Promise((
|
|
30788
|
-
setScreen(build(
|
|
31862
|
+
const runScreen = (build) => new Promise((resolve22) => {
|
|
31863
|
+
setScreen(build(resolve22));
|
|
30789
31864
|
});
|
|
30790
31865
|
void (async () => {
|
|
30791
31866
|
const results = [];
|
|
@@ -30963,9 +32038,9 @@ var init_command8 = __esm({
|
|
|
30963
32038
|
function rank(p) {
|
|
30964
32039
|
if (p === "typed-slot") return 1;
|
|
30965
32040
|
if (p === "structural") return 2;
|
|
30966
|
-
if (p === "
|
|
30967
|
-
if (p === "
|
|
30968
|
-
if (p
|
|
32041
|
+
if (p === "manifest") return 3;
|
|
32042
|
+
if (p === "doc") return 4;
|
|
32043
|
+
if (p.startsWith("adapter:")) return 5;
|
|
30969
32044
|
return 6;
|
|
30970
32045
|
}
|
|
30971
32046
|
function mergeEdges(all) {
|
|
@@ -31001,6 +32076,65 @@ var init_merge_edges = __esm({
|
|
|
31001
32076
|
}
|
|
31002
32077
|
});
|
|
31003
32078
|
|
|
32079
|
+
// packages/experience-design-system-cli-legacy/src/analyze/composition/parse-map-edges.ts
|
|
32080
|
+
function parseMapEdges(raw, opts) {
|
|
32081
|
+
const edges = [];
|
|
32082
|
+
const warnings = [];
|
|
32083
|
+
const { componentNames } = opts;
|
|
32084
|
+
for (const line of raw.split("\n")) {
|
|
32085
|
+
const trimmed = line.trim();
|
|
32086
|
+
if (!trimmed.startsWith("{")) continue;
|
|
32087
|
+
let obj;
|
|
32088
|
+
try {
|
|
32089
|
+
obj = JSON.parse(trimmed);
|
|
32090
|
+
} catch {
|
|
32091
|
+
warnings.push(`unparseable line: ${trimmed.slice(0, 120)}`);
|
|
32092
|
+
continue;
|
|
32093
|
+
}
|
|
32094
|
+
if (typeof obj !== "object" || obj === null || !("tool" in obj)) continue;
|
|
32095
|
+
const rec = obj;
|
|
32096
|
+
if (!VALID_MAP_TOOL_NAMES.has(rec.tool)) {
|
|
32097
|
+
warnings.push(`unknown tool: ${String(rec.tool)}`);
|
|
32098
|
+
continue;
|
|
32099
|
+
}
|
|
32100
|
+
if (typeof rec.parent !== "string" || !rec.parent || typeof rec.child !== "string" || !rec.child) {
|
|
32101
|
+
warnings.push("map_edge missing parent/child \u2014 skipped");
|
|
32102
|
+
continue;
|
|
32103
|
+
}
|
|
32104
|
+
const { parent, child } = rec;
|
|
32105
|
+
if (!componentNames.has(parent)) {
|
|
32106
|
+
warnings.push(`map_edge names unknown component (parent): ${parent} \u2014 skipped`);
|
|
32107
|
+
continue;
|
|
32108
|
+
}
|
|
32109
|
+
if (!componentNames.has(child)) {
|
|
32110
|
+
warnings.push(`map_edge names unknown component (child): ${child} \u2014 skipped`);
|
|
32111
|
+
continue;
|
|
32112
|
+
}
|
|
32113
|
+
const edge = { parent, child, provenance: "agent" };
|
|
32114
|
+
if (typeof rec.slot === "string" && rec.slot) {
|
|
32115
|
+
edge.slot = rec.slot;
|
|
32116
|
+
}
|
|
32117
|
+
if (rec.confidence !== void 0) {
|
|
32118
|
+
if (typeof rec.confidence === "number" && rec.confidence >= 1 && rec.confidence <= 5) {
|
|
32119
|
+
edge.confidence = rec.confidence;
|
|
32120
|
+
} else {
|
|
32121
|
+
warnings.push(
|
|
32122
|
+
`map_edge (${parent}\u2192${child}): invalid confidence ${String(rec.confidence)} \u2014 edge kept without confidence`
|
|
32123
|
+
);
|
|
32124
|
+
}
|
|
32125
|
+
}
|
|
32126
|
+
edges.push(edge);
|
|
32127
|
+
}
|
|
32128
|
+
return { edges, warnings };
|
|
32129
|
+
}
|
|
32130
|
+
var VALID_MAP_TOOL_NAMES;
|
|
32131
|
+
var init_parse_map_edges = __esm({
|
|
32132
|
+
"packages/experience-design-system-cli-legacy/src/analyze/composition/parse-map-edges.ts"() {
|
|
32133
|
+
"use strict";
|
|
32134
|
+
VALID_MAP_TOOL_NAMES = /* @__PURE__ */ new Set(["map_edge"]);
|
|
32135
|
+
}
|
|
32136
|
+
});
|
|
32137
|
+
|
|
31004
32138
|
// packages/experience-design-system-cli-legacy/src/analyze/composition/apply-mapping.ts
|
|
31005
32139
|
function applyMapping(components, edges) {
|
|
31006
32140
|
const warnings = [];
|
|
@@ -31060,9 +32194,44 @@ var init_apply_mapping = __esm({
|
|
|
31060
32194
|
}
|
|
31061
32195
|
});
|
|
31062
32196
|
|
|
32197
|
+
// packages/experience-design-system-cli-legacy/src/analyze/composition/prompt-loader.ts
|
|
32198
|
+
import { existsSync as existsSync10, readFileSync as readFileSync10 } from "node:fs";
|
|
32199
|
+
import { dirname as dirname17, join as join27, resolve as resolve19 } from "node:path";
|
|
32200
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
32201
|
+
function resolvePromptPath(fileName) {
|
|
32202
|
+
const thisDir = dirname17(fileURLToPath3(import.meta.url));
|
|
32203
|
+
let dir = thisDir;
|
|
32204
|
+
for (; ; ) {
|
|
32205
|
+
const candidate = join27(dir, "prompts");
|
|
32206
|
+
if (existsSync10(candidate)) return join27(candidate, fileName);
|
|
32207
|
+
const parent = resolve19(dir, "..");
|
|
32208
|
+
if (parent === dir) {
|
|
32209
|
+
throw new Error(
|
|
32210
|
+
`prompt file missing from CLI installation (could not locate prompts/ directory from: ${thisDir})`
|
|
32211
|
+
);
|
|
32212
|
+
}
|
|
32213
|
+
dir = parent;
|
|
32214
|
+
}
|
|
32215
|
+
}
|
|
32216
|
+
function loadPrompt(fileName) {
|
|
32217
|
+
const path = resolvePromptPath(fileName);
|
|
32218
|
+
try {
|
|
32219
|
+
return readFileSync10(path, "utf8");
|
|
32220
|
+
} catch {
|
|
32221
|
+
throw new Error(`prompt file missing from CLI installation \u2014 try reinstalling the CLI (looked for: ${path})`);
|
|
32222
|
+
}
|
|
32223
|
+
}
|
|
32224
|
+
var init_prompt_loader = __esm({
|
|
32225
|
+
"packages/experience-design-system-cli-legacy/src/analyze/composition/prompt-loader.ts"() {
|
|
32226
|
+
"use strict";
|
|
32227
|
+
}
|
|
32228
|
+
});
|
|
32229
|
+
|
|
31063
32230
|
// packages/experience-design-system-cli-legacy/src/analyze/composition/resolve-mapping.ts
|
|
31064
|
-
function resolveMapping(input) {
|
|
32231
|
+
async function resolveMapping(input) {
|
|
32232
|
+
const componentNames = new Set(input.components.map((c2) => c2.name));
|
|
31065
32233
|
const collected = [];
|
|
32234
|
+
const agentWarnings = [];
|
|
31066
32235
|
for (const c2 of input.components) {
|
|
31067
32236
|
for (const slot of c2.slots) {
|
|
31068
32237
|
for (const child of slot.allowedComponents ?? []) {
|
|
@@ -31080,41 +32249,17 @@ function resolveMapping(input) {
|
|
|
31080
32249
|
if (input.extraEdges) {
|
|
31081
32250
|
collected.push(...input.extraEdges);
|
|
31082
32251
|
}
|
|
31083
|
-
for (const evidence of input.sourceCallSiteEvidence ?? []) {
|
|
31084
|
-
collected.push({
|
|
31085
|
-
parent: evidence.parent,
|
|
31086
|
-
child: evidence.child,
|
|
31087
|
-
...evidence.slot ? { slot: evidence.slot } : {},
|
|
31088
|
-
citation: { sourcePath: evidence.sourcePath, startLine: evidence.startLine, endLine: evidence.endLine },
|
|
31089
|
-
provenance: "call-site"
|
|
31090
|
-
});
|
|
31091
|
-
}
|
|
31092
32252
|
const coveredParents = new Set(collected.map((e) => e.parent));
|
|
31093
32253
|
const residueParents = input.components.map((c2) => c2.name).filter((n) => !coveredParents.has(n));
|
|
31094
|
-
const
|
|
31095
|
-
|
|
31096
|
-
const
|
|
31097
|
-
|
|
31098
|
-
|
|
31099
|
-
|
|
31100
|
-
|
|
31101
|
-
|
|
31102
|
-
coveredParents: [...coveredParents].sort(),
|
|
31103
|
-
residueParents,
|
|
31104
|
-
sourceCallSiteAccepted: input.sourceCallSiteEvidence?.length ?? 0,
|
|
31105
|
-
sourceCallSiteRejected: input.sourceCallSiteRejections?.length ?? 0
|
|
31106
|
-
});
|
|
32254
|
+
const shouldRunAgent = input.forceAgent || residueParents.length > 0 && input.files.length > 0;
|
|
32255
|
+
if (shouldRunAgent) {
|
|
32256
|
+
const prompt = input.buildPrompt ? input.buildPrompt(input.files, [...componentNames]) : defaultPrompt(input.files, [...componentNames], input.promptOverride);
|
|
32257
|
+
const raw = await input.runAgentFn({ prompt, files: input.files }) ?? "";
|
|
32258
|
+
const parsed = parseMapEdges(raw, { componentNames });
|
|
32259
|
+
collected.push(...parsed.edges);
|
|
32260
|
+
agentWarnings.push(...parsed.warnings);
|
|
32261
|
+
}
|
|
31107
32262
|
const merged = mergeEdges(collected);
|
|
31108
|
-
debug.event("analyze", "composition.merged", {
|
|
31109
|
-
edgeCountsByProvenance: countByProvenance(merged.edges),
|
|
31110
|
-
conflicts: merged.conflicts,
|
|
31111
|
-
edges: merged.edges.map((edge) => ({
|
|
31112
|
-
parent: edge.parent,
|
|
31113
|
-
child: edge.child,
|
|
31114
|
-
slot: edge.slot ?? null,
|
|
31115
|
-
provenance: edge.provenance
|
|
31116
|
-
}))
|
|
31117
|
-
});
|
|
31118
32263
|
const base = input.components.map((c2) => ({
|
|
31119
32264
|
...c2,
|
|
31120
32265
|
slots: c2.slots.map((s) => {
|
|
@@ -31123,32 +32268,127 @@ function resolveMapping(input) {
|
|
|
31123
32268
|
})
|
|
31124
32269
|
}));
|
|
31125
32270
|
const applied = applyMapping(base, merged.edges);
|
|
31126
|
-
debug.event("analyze", "composition.applied", {
|
|
31127
|
-
slots: applied.components.flatMap(
|
|
31128
|
-
(component) => component.slots.filter((slot) => (slot.allowedComponents?.length ?? 0) > 0).map((slot) => ({ component: component.name, slot: slot.name, allowedComponents: slot.allowedComponents }))
|
|
31129
|
-
),
|
|
31130
|
-
warnings: applied.warnings
|
|
31131
|
-
});
|
|
31132
32271
|
return {
|
|
31133
32272
|
components: applied.components,
|
|
31134
32273
|
edges: merged.edges,
|
|
31135
32274
|
conflicts: merged.conflicts,
|
|
31136
|
-
warnings: applied.warnings
|
|
31137
|
-
sourceCallSiteEvidence: [...input.sourceCallSiteEvidence ?? []],
|
|
31138
|
-
sourceCallSiteRejections: [...input.sourceCallSiteRejections ?? []]
|
|
32275
|
+
warnings: [...agentWarnings, ...applied.warnings]
|
|
31139
32276
|
};
|
|
31140
32277
|
}
|
|
32278
|
+
function defaultPrompt(files, componentNames, promptOverride) {
|
|
32279
|
+
const fileBlocks = files.map((f) => `--- ${f.path} ---
|
|
32280
|
+
${f.content}`).join("\n\n");
|
|
32281
|
+
const instruction = promptOverride?.trim() ? promptOverride.trim() : loadPrompt("composition-edges.md").trim();
|
|
32282
|
+
return [
|
|
32283
|
+
instruction,
|
|
32284
|
+
"",
|
|
32285
|
+
'Emit one JSON object per line, each: {"tool":"map_edge","parent":"<Name>","child":"<Name>","slot"?:"<slot>","confidence"?:1-5,"reason":"<cite the file + declaration>"}.',
|
|
32286
|
+
"Use ONLY these exact component names (an edge naming anything else is dropped):",
|
|
32287
|
+
componentNames.join(", "),
|
|
32288
|
+
"",
|
|
32289
|
+
"Candidate files:",
|
|
32290
|
+
fileBlocks
|
|
32291
|
+
].join("\n");
|
|
32292
|
+
}
|
|
31141
32293
|
var init_resolve_mapping = __esm({
|
|
31142
32294
|
"packages/experience-design-system-cli-legacy/src/analyze/composition/resolve-mapping.ts"() {
|
|
31143
32295
|
"use strict";
|
|
31144
32296
|
init_merge_edges();
|
|
32297
|
+
init_parse_map_edges();
|
|
31145
32298
|
init_apply_mapping();
|
|
31146
|
-
|
|
32299
|
+
init_prompt_loader();
|
|
32300
|
+
}
|
|
32301
|
+
});
|
|
32302
|
+
|
|
32303
|
+
// packages/experience-design-system-cli-legacy/src/analyze/composition/resolve-mapping-cli.ts
|
|
32304
|
+
function resolveCompositionSources(opts) {
|
|
32305
|
+
return {
|
|
32306
|
+
forceAgent: opts.compositionRefresh === true || opts.noCache === true
|
|
32307
|
+
};
|
|
32308
|
+
}
|
|
32309
|
+
var init_resolve_mapping_cli = __esm({
|
|
32310
|
+
"packages/experience-design-system-cli-legacy/src/analyze/composition/resolve-mapping-cli.ts"() {
|
|
32311
|
+
"use strict";
|
|
32312
|
+
}
|
|
32313
|
+
});
|
|
32314
|
+
|
|
32315
|
+
// packages/experience-design-system-cli-legacy/src/analyze/composition/candidate-files.ts
|
|
32316
|
+
function matchReason(file) {
|
|
32317
|
+
const segments = file.path.split("/").filter((s) => s !== "");
|
|
32318
|
+
for (const pattern of CANDIDATE_NAME_PATTERNS) {
|
|
32319
|
+
if (segments.some((seg) => pattern.test(seg))) {
|
|
32320
|
+
return `name:${pattern.source.toLowerCase()}`;
|
|
32321
|
+
}
|
|
32322
|
+
}
|
|
32323
|
+
for (const marker of CANDIDATE_CONTENT_MARKERS) {
|
|
32324
|
+
if (file.content.includes(marker)) return `content:${marker}`;
|
|
32325
|
+
}
|
|
32326
|
+
return void 0;
|
|
32327
|
+
}
|
|
32328
|
+
function selectCandidateFiles(files) {
|
|
32329
|
+
const selected = [];
|
|
32330
|
+
const seen = /* @__PURE__ */ new Set();
|
|
32331
|
+
for (const file of files) {
|
|
32332
|
+
if (seen.has(file.path)) continue;
|
|
32333
|
+
const reason = matchReason(file);
|
|
32334
|
+
if (reason === void 0) continue;
|
|
32335
|
+
seen.add(file.path);
|
|
32336
|
+
selected.push({ path: file.path, content: file.content, reason });
|
|
32337
|
+
}
|
|
32338
|
+
return selected;
|
|
32339
|
+
}
|
|
32340
|
+
function capCandidatesToPromptBudget(files, budget = PROMPT_CANDIDATE_TOKEN_BUDGET) {
|
|
32341
|
+
const ordered = [...files].sort((a, b) => a.content.length - b.content.length || a.path.localeCompare(b.path));
|
|
32342
|
+
const kept = [];
|
|
32343
|
+
const dropped = [];
|
|
32344
|
+
let spent = 0;
|
|
32345
|
+
for (const file of ordered) {
|
|
32346
|
+
const cost = tokenCost(file);
|
|
32347
|
+
if (spent + cost > budget) {
|
|
32348
|
+
dropped.push(file);
|
|
32349
|
+
continue;
|
|
32350
|
+
}
|
|
32351
|
+
kept.push(file);
|
|
32352
|
+
spent += cost;
|
|
32353
|
+
}
|
|
32354
|
+
return { kept, dropped };
|
|
32355
|
+
}
|
|
32356
|
+
function tokenCost(file) {
|
|
32357
|
+
return Math.ceil(file.content.length / CHARS_PER_TOKEN);
|
|
32358
|
+
}
|
|
32359
|
+
var CANDIDATE_NAME_PATTERNS, CANDIDATE_CONTENT_MARKERS, PROMPT_CANDIDATE_TOKEN_BUDGET, CHARS_PER_TOKEN;
|
|
32360
|
+
var init_candidate_files = __esm({
|
|
32361
|
+
"packages/experience-design-system-cli-legacy/src/analyze/composition/candidate-files.ts"() {
|
|
32362
|
+
"use strict";
|
|
32363
|
+
CANDIDATE_NAME_PATTERNS = [/mapping/i, /meta/i, /registry/i, /schema/i, /composition/i];
|
|
32364
|
+
CANDIDATE_CONTENT_MARKERS = [
|
|
32365
|
+
"requiredParent",
|
|
32366
|
+
"withParentType",
|
|
32367
|
+
"allowedTagNames",
|
|
32368
|
+
"createContext",
|
|
32369
|
+
"MappingContext",
|
|
32370
|
+
"allowedComponents"
|
|
32371
|
+
];
|
|
32372
|
+
PROMPT_CANDIDATE_TOKEN_BUDGET = 8e4;
|
|
32373
|
+
CHARS_PER_TOKEN = 4;
|
|
32374
|
+
}
|
|
32375
|
+
});
|
|
32376
|
+
|
|
32377
|
+
// packages/experience-design-system-cli-legacy/src/analyze/composition/composition-cache-key.ts
|
|
32378
|
+
function buildCompositionInputHash(input) {
|
|
32379
|
+
const fileDigest = input.files.map((f) => `${f.path} ${hashContent(f.content)}`).sort().join("");
|
|
32380
|
+
return hashContent(`agent:${input.agent}
|
|
32381
|
+
${fileDigest}`);
|
|
32382
|
+
}
|
|
32383
|
+
var init_composition_cache_key = __esm({
|
|
32384
|
+
"packages/experience-design-system-cli-legacy/src/analyze/composition/composition-cache-key.ts"() {
|
|
32385
|
+
"use strict";
|
|
32386
|
+
init_cache_keys();
|
|
31147
32387
|
}
|
|
31148
32388
|
});
|
|
31149
32389
|
|
|
31150
32390
|
// packages/experience-design-system-cli-legacy/src/analyze/composition/manifest-doc-evidence.ts
|
|
31151
|
-
import { dirname as
|
|
32391
|
+
import { dirname as dirname18 } from "node:path";
|
|
31152
32392
|
function kebabToPascal2(name) {
|
|
31153
32393
|
return name.split("-").filter(Boolean).map((seg) => seg.charAt(0).toUpperCase() + seg.slice(1)).join("");
|
|
31154
32394
|
}
|
|
@@ -31198,8 +32438,8 @@ function collectAgentsDocEdges(files, components, componentNames) {
|
|
|
31198
32438
|
const seen = /* @__PURE__ */ new Set();
|
|
31199
32439
|
for (const file of files) {
|
|
31200
32440
|
if (!file.path.endsWith("AGENTS.md")) continue;
|
|
31201
|
-
const docDir =
|
|
31202
|
-
const parent = components.find((c2) => c2.sourcePath &&
|
|
32441
|
+
const docDir = dirname18(file.path);
|
|
32442
|
+
const parent = components.find((c2) => c2.sourcePath && dirname18(c2.sourcePath) === docDir)?.name;
|
|
31203
32443
|
if (!parent || !componentNames.has(parent)) continue;
|
|
31204
32444
|
for (const line of file.content.split("\n")) {
|
|
31205
32445
|
const lower = line.toLowerCase();
|
|
@@ -31229,172 +32469,12 @@ var init_manifest_doc_evidence = __esm({
|
|
|
31229
32469
|
}
|
|
31230
32470
|
});
|
|
31231
32471
|
|
|
31232
|
-
// packages/experience-design-system-cli-legacy/src/analyze/composition/source-call-site-evidence.ts
|
|
31233
|
-
import { Node as Node49, Project as Project11, SyntaxKind as SyntaxKind15 } from "ts-morph";
|
|
31234
|
-
function collectSourceCallSiteEvidence(files, components) {
|
|
31235
|
-
const componentNames = new Set(components.map((component) => component.name));
|
|
31236
|
-
const componentsBySource = /* @__PURE__ */ new Map();
|
|
31237
|
-
for (const component of components) {
|
|
31238
|
-
const sourcePath = component.sourcePath ?? component.source;
|
|
31239
|
-
const siblings = componentsBySource.get(sourcePath) ?? [];
|
|
31240
|
-
siblings.push(component);
|
|
31241
|
-
componentsBySource.set(sourcePath, siblings);
|
|
31242
|
-
}
|
|
31243
|
-
const project = new Project11({
|
|
31244
|
-
compilerOptions: { jsx: 1, target: 99, module: 99, moduleResolution: 100, skipLibCheck: true, allowJs: true },
|
|
31245
|
-
skipAddingFilesFromTsConfig: true
|
|
31246
|
-
});
|
|
31247
|
-
const sourceFiles = new Map(
|
|
31248
|
-
files.map((file) => [file.path, project.createSourceFile(file.path, file.content, { overwrite: true })])
|
|
31249
|
-
);
|
|
31250
|
-
const accepted = [];
|
|
31251
|
-
const rejected = [];
|
|
31252
|
-
for (const [sourcePath, parents] of componentsBySource) {
|
|
31253
|
-
const sourceFile = sourceFiles.get(sourcePath);
|
|
31254
|
-
if (!sourceFile) continue;
|
|
31255
|
-
const boundNames = collectBoundNames(sourceFile);
|
|
31256
|
-
for (const parent of parents) {
|
|
31257
|
-
for (const jsxElement of [
|
|
31258
|
-
...sourceFile.getDescendantsOfKind(SyntaxKind15.JsxSelfClosingElement),
|
|
31259
|
-
...sourceFile.getDescendantsOfKind(SyntaxKind15.JsxElement)
|
|
31260
|
-
]) {
|
|
31261
|
-
const tagName = Node49.isJsxSelfClosingElement(jsxElement) ? jsxElement.getTagNameNode().getText() : jsxElement.getOpeningElement().getTagNameNode().getText();
|
|
31262
|
-
const candidate = tagName.split(".").at(-1) ?? tagName;
|
|
31263
|
-
if (candidate === parent.name || isIntrinsicTag(candidate)) continue;
|
|
31264
|
-
const lines = sourceExcerpt(sourceFile, jsxElement);
|
|
31265
|
-
if (!componentNames.has(candidate)) {
|
|
31266
|
-
rejected.push({ parent: parent.name, candidate, ...lines, reason: "unknown-component" });
|
|
31267
|
-
continue;
|
|
31268
|
-
}
|
|
31269
|
-
if (!boundNames.has(tagName) && !boundNames.has(candidate)) {
|
|
31270
|
-
rejected.push({ parent: parent.name, candidate, ...lines, reason: "unbound-component" });
|
|
31271
|
-
continue;
|
|
31272
|
-
}
|
|
31273
|
-
accepted.push({ parent: parent.name, child: candidate, ...lines, kind: "jsx-render" });
|
|
31274
|
-
}
|
|
31275
|
-
}
|
|
31276
|
-
}
|
|
31277
|
-
for (const sourceFile of sourceFiles.values()) {
|
|
31278
|
-
collectCallerSlotEvidence(sourceFile, componentNames, collectBoundNames(sourceFile), accepted, rejected);
|
|
31279
|
-
}
|
|
31280
|
-
const verifiedPairs = new Set(accepted.map((evidence) => `${evidence.parent}\0${evidence.child}`));
|
|
31281
|
-
for (const component of components) {
|
|
31282
|
-
const candidates = component.slots.flatMap((slot) => [
|
|
31283
|
-
...slot.allowedComponents ?? [],
|
|
31284
|
-
...slot.structuralAllowedComponents ?? []
|
|
31285
|
-
]);
|
|
31286
|
-
for (const candidate of candidates) {
|
|
31287
|
-
if (verifiedPairs.has(`${component.name}\0${candidate}`)) continue;
|
|
31288
|
-
rejected.push({
|
|
31289
|
-
parent: component.name,
|
|
31290
|
-
candidate,
|
|
31291
|
-
sourcePath: component.sourcePath ?? component.source,
|
|
31292
|
-
reason: "no-call-site"
|
|
31293
|
-
});
|
|
31294
|
-
}
|
|
31295
|
-
}
|
|
31296
|
-
return {
|
|
31297
|
-
accepted: dedupeEvidence(accepted),
|
|
31298
|
-
rejected: dedupeRejections(rejected)
|
|
31299
|
-
};
|
|
31300
|
-
}
|
|
31301
|
-
function collectCallerSlotEvidence(sourceFile, componentNames, boundNames, accepted, rejected) {
|
|
31302
|
-
for (const parentElement of sourceFile.getDescendantsOfKind(SyntaxKind15.JsxElement)) {
|
|
31303
|
-
const parentTag = parentElement.getOpeningElement().getTagNameNode().getText();
|
|
31304
|
-
const parent = parentTag.split(".").at(-1) ?? parentTag;
|
|
31305
|
-
if (!componentNames.has(parent) || !boundNames.has(parentTag)) continue;
|
|
31306
|
-
for (const childNode of parentElement.getJsxChildren()) {
|
|
31307
|
-
if (!Node49.isJsxElement(childNode) && !Node49.isJsxSelfClosingElement(childNode)) {
|
|
31308
|
-
if (Node49.isJsxText(childNode) && childNode.getText().trim()) {
|
|
31309
|
-
const lines2 = sourceExcerpt(sourceFile, childNode);
|
|
31310
|
-
rejected.push({ parent, candidate: "<text>", ...lines2, reason: "text-only-child" });
|
|
31311
|
-
}
|
|
31312
|
-
continue;
|
|
31313
|
-
}
|
|
31314
|
-
const childTag = Node49.isJsxElement(childNode) ? childNode.getOpeningElement().getTagNameNode().getText() : childNode.getTagNameNode().getText();
|
|
31315
|
-
const child = childTag.split(".").at(-1) ?? childTag;
|
|
31316
|
-
if (isIntrinsicTag(child)) continue;
|
|
31317
|
-
const lines = sourceExcerpt(sourceFile, childNode);
|
|
31318
|
-
if (!componentNames.has(child)) {
|
|
31319
|
-
rejected.push({ parent, candidate: child, ...lines, reason: "unknown-component" });
|
|
31320
|
-
continue;
|
|
31321
|
-
}
|
|
31322
|
-
if (!boundNames.has(childTag) && !boundNames.has(child)) {
|
|
31323
|
-
rejected.push({ parent, candidate: child, ...lines, reason: "unbound-component" });
|
|
31324
|
-
continue;
|
|
31325
|
-
}
|
|
31326
|
-
const slotAttribute = Node49.isJsxElement(childNode) ? childNode.getOpeningElement().getAttribute("slot") : childNode.getAttribute("slot");
|
|
31327
|
-
const slotValue = slotAttribute && Node49.isJsxAttribute(slotAttribute) ? slotAttribute.getInitializer() : void 0;
|
|
31328
|
-
const slot = slotValue && Node49.isStringLiteral(slotValue) ? slotValue.getLiteralValue() : void 0;
|
|
31329
|
-
accepted.push({ parent, child, ...slot ? { slot } : {}, ...lines, kind: "jsx-render" });
|
|
31330
|
-
}
|
|
31331
|
-
}
|
|
31332
|
-
}
|
|
31333
|
-
function collectBoundNames(sourceFile) {
|
|
31334
|
-
const names = /* @__PURE__ */ new Set();
|
|
31335
|
-
for (const declaration of sourceFile.getImportDeclarations()) {
|
|
31336
|
-
const defaultImport = declaration.getDefaultImport();
|
|
31337
|
-
if (defaultImport) names.add(defaultImport.getText());
|
|
31338
|
-
const namespaceImport = declaration.getNamespaceImport();
|
|
31339
|
-
if (namespaceImport) names.add(namespaceImport.getText());
|
|
31340
|
-
for (const namedImport of declaration.getNamedImports()) {
|
|
31341
|
-
names.add((namedImport.getAliasNode() ?? namedImport.getNameNode()).getText());
|
|
31342
|
-
}
|
|
31343
|
-
}
|
|
31344
|
-
for (const declaration of sourceFile.getVariableDeclarations()) names.add(declaration.getName());
|
|
31345
|
-
for (const declaration of sourceFile.getFunctions()) {
|
|
31346
|
-
if (declaration.getName()) names.add(declaration.getName());
|
|
31347
|
-
}
|
|
31348
|
-
for (const declaration of sourceFile.getClasses()) {
|
|
31349
|
-
if (declaration.getName()) names.add(declaration.getName());
|
|
31350
|
-
}
|
|
31351
|
-
return names;
|
|
31352
|
-
}
|
|
31353
|
-
function sourceExcerpt(sourceFile, node) {
|
|
31354
|
-
const startLine = node.getStartLineNumber();
|
|
31355
|
-
const endLine = node.getEndLineNumber();
|
|
31356
|
-
const lines = sourceFile.getFullText().split("\n");
|
|
31357
|
-
return {
|
|
31358
|
-
sourcePath: sourceFile.getFilePath(),
|
|
31359
|
-
startLine,
|
|
31360
|
-
endLine,
|
|
31361
|
-
excerpt: lines.slice(startLine - 1, endLine).join("\n").trim()
|
|
31362
|
-
};
|
|
31363
|
-
}
|
|
31364
|
-
function isIntrinsicTag(tagName) {
|
|
31365
|
-
return /^[a-z]/.test(tagName) || tagName.includes("-");
|
|
31366
|
-
}
|
|
31367
|
-
function dedupeEvidence(evidence) {
|
|
31368
|
-
const seen = /* @__PURE__ */ new Set();
|
|
31369
|
-
return evidence.filter((item) => {
|
|
31370
|
-
const key = `${item.parent}\0${item.child}\0${item.slot ?? ""}\0${item.sourcePath}\0${item.startLine}`;
|
|
31371
|
-
if (seen.has(key)) return false;
|
|
31372
|
-
seen.add(key);
|
|
31373
|
-
return true;
|
|
31374
|
-
}).sort(
|
|
31375
|
-
(left, right) => `${left.parent}\0${left.child}\0${left.sourcePath}\0${left.startLine}`.localeCompare(
|
|
31376
|
-
`${right.parent}\0${right.child}\0${right.sourcePath}\0${right.startLine}`
|
|
31377
|
-
)
|
|
31378
|
-
);
|
|
31379
|
-
}
|
|
31380
|
-
function dedupeRejections(rejections) {
|
|
31381
|
-
const seen = /* @__PURE__ */ new Set();
|
|
31382
|
-
return rejections.filter((item) => {
|
|
31383
|
-
const key = `${item.parent}\0${item.candidate}\0${item.sourcePath}\0${item.startLine}`;
|
|
31384
|
-
if (seen.has(key)) return false;
|
|
31385
|
-
seen.add(key);
|
|
31386
|
-
return true;
|
|
31387
|
-
});
|
|
31388
|
-
}
|
|
31389
|
-
var init_source_call_site_evidence = __esm({
|
|
31390
|
-
"packages/experience-design-system-cli-legacy/src/analyze/composition/source-call-site-evidence.ts"() {
|
|
31391
|
-
"use strict";
|
|
31392
|
-
}
|
|
31393
|
-
});
|
|
31394
|
-
|
|
31395
32472
|
// packages/experience-design-system-cli-legacy/src/analyze/extract-command.ts
|
|
31396
|
-
import { mkdir as mkdir6, readdir as readdir3, readFile as
|
|
31397
|
-
import { isAbsolute as isAbsolute2, join as
|
|
32473
|
+
import { mkdir as mkdir6, readdir as readdir3, readFile as readFile19, stat as stat6 } from "node:fs/promises";
|
|
32474
|
+
import { isAbsolute as isAbsolute2, join as join28, relative as relative2, resolve as resolve20 } from "node:path";
|
|
32475
|
+
function resolveExtractNoCache(opts) {
|
|
32476
|
+
return opts.noCache === true || opts.cache === false;
|
|
32477
|
+
}
|
|
31398
32478
|
function isDenylistedNoiseFile(name) {
|
|
31399
32479
|
return DENYLISTED_EXACT_FILE_NAMES.has(name) || DENYLISTED_FILE_NAME_PATTERNS.some((pattern) => pattern.test(name));
|
|
31400
32480
|
}
|
|
@@ -31408,12 +32488,12 @@ async function retryDatabaseWrite(operation, attempts = 8) {
|
|
|
31408
32488
|
} catch (error) {
|
|
31409
32489
|
const message = error instanceof Error ? error.message : String(error);
|
|
31410
32490
|
if (!/database is locked|database is busy/i.test(message) || attempt >= attempts) throw error;
|
|
31411
|
-
await new Promise((
|
|
32491
|
+
await new Promise((resolve22) => setTimeout(resolve22, Math.min(250 * attempt, 2e3)));
|
|
31412
32492
|
}
|
|
31413
32493
|
}
|
|
31414
32494
|
}
|
|
31415
32495
|
function resolveFromProjectRoot(projectRoot, inputPath) {
|
|
31416
|
-
return isAbsolute2(inputPath) ? inputPath :
|
|
32496
|
+
return isAbsolute2(inputPath) ? inputPath : resolve20(projectRoot, inputPath);
|
|
31417
32497
|
}
|
|
31418
32498
|
async function pathExists4(path) {
|
|
31419
32499
|
return Boolean(await stat6(path).catch(() => null));
|
|
@@ -31424,7 +32504,7 @@ async function collectSourceFiles(directory, onProgress) {
|
|
|
31424
32504
|
const entries = await readdir3(currentDirectory, { withFileTypes: true });
|
|
31425
32505
|
const subdirs = [];
|
|
31426
32506
|
for (const entry of entries) {
|
|
31427
|
-
const fullPath =
|
|
32507
|
+
const fullPath = join28(currentDirectory, entry.name);
|
|
31428
32508
|
if (entry.isDirectory()) {
|
|
31429
32509
|
if (!IGNORED_DIRECTORY_NAMES.has(entry.name)) {
|
|
31430
32510
|
subdirs.push(fullPath);
|
|
@@ -31451,6 +32531,12 @@ async function collectSourceFiles(directory, onProgress) {
|
|
|
31451
32531
|
await visit(directory);
|
|
31452
32532
|
return files.sort();
|
|
31453
32533
|
}
|
|
32534
|
+
function resolveCompositionAgentName(flagValue) {
|
|
32535
|
+
if (flagValue && isAgentName(flagValue)) return flagValue;
|
|
32536
|
+
const env = process.env["EDS_COMPOSITION_AGENT"];
|
|
32537
|
+
if (env && isAgentName(env)) return env;
|
|
32538
|
+
return DEFAULT_AGENT_NAME;
|
|
32539
|
+
}
|
|
31454
32540
|
async function readCandidateFiles(components, extraFiles = []) {
|
|
31455
32541
|
const paths = new Set(extraFiles);
|
|
31456
32542
|
for (const c2 of components) {
|
|
@@ -31460,7 +32546,7 @@ async function readCandidateFiles(components, extraFiles = []) {
|
|
|
31460
32546
|
await Promise.all(
|
|
31461
32547
|
[...paths].map(async (p) => {
|
|
31462
32548
|
try {
|
|
31463
|
-
const content = await
|
|
32549
|
+
const content = await readFile19(p, "utf8");
|
|
31464
32550
|
out.push({ path: p, content });
|
|
31465
32551
|
} catch {
|
|
31466
32552
|
}
|
|
@@ -31469,11 +32555,21 @@ async function readCandidateFiles(components, extraFiles = []) {
|
|
|
31469
32555
|
return out;
|
|
31470
32556
|
}
|
|
31471
32557
|
function registerInternalExtractCommand(program) {
|
|
31472
|
-
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(
|
|
32558
|
+
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(
|
|
31473
32559
|
"--resolve-unreachable <mode>",
|
|
31474
32560
|
"Retry pass for unresolved Svelte Props types: 'auto' (default), 'always', or 'never'",
|
|
31475
32561
|
"auto"
|
|
31476
|
-
).
|
|
32562
|
+
).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(
|
|
32563
|
+
"--prompt <stage=value>",
|
|
32564
|
+
"Override a stage prompt (repeatable). value is a file path or literal text, e.g. --prompt composition=./p.md",
|
|
32565
|
+
(v, acc) => [...acc, v],
|
|
32566
|
+
[]
|
|
32567
|
+
);
|
|
32568
|
+
addAgentModelOptions(extractCmd, {
|
|
32569
|
+
includeModel: false,
|
|
32570
|
+
agentDescription: "Coding agent for composition mapping resolution (claude|codex|opencode|cursor)"
|
|
32571
|
+
}).action(async (opts) => {
|
|
32572
|
+
const noCache = resolveExtractNoCache(opts);
|
|
31477
32573
|
const resolveUnreachable = (() => {
|
|
31478
32574
|
const v = opts.resolveUnreachable ?? "auto";
|
|
31479
32575
|
if (v !== "auto" && v !== "always" && v !== "never") {
|
|
@@ -31483,8 +32579,16 @@ function registerInternalExtractCommand(program) {
|
|
|
31483
32579
|
}
|
|
31484
32580
|
return v;
|
|
31485
32581
|
})();
|
|
31486
|
-
|
|
31487
|
-
|
|
32582
|
+
if (opts.bedrock) {
|
|
32583
|
+
const bedrockAgent = resolveCompositionAgentName(opts.agent);
|
|
32584
|
+
if (!agentSupportsBedrock(bedrockAgent)) {
|
|
32585
|
+
process.stderr.write(`Error: --bedrock is not supported for --agent ${bedrockAgent}
|
|
32586
|
+
`);
|
|
32587
|
+
process.exit(1);
|
|
32588
|
+
}
|
|
32589
|
+
}
|
|
32590
|
+
const projectRoot = resolve20(opts.project);
|
|
32591
|
+
const outDir = join28(projectRoot, ".contentful");
|
|
31488
32592
|
let sourceDirectory;
|
|
31489
32593
|
if (opts.dir !== void 0) {
|
|
31490
32594
|
sourceDirectory = resolveFromProjectRoot(projectRoot, opts.dir);
|
|
@@ -31507,16 +32611,50 @@ function registerInternalExtractCommand(program) {
|
|
|
31507
32611
|
process.stderr.write(`progress=scan-done:${sourceFiles.length}
|
|
31508
32612
|
`);
|
|
31509
32613
|
}
|
|
31510
|
-
const
|
|
31511
|
-
|
|
31512
|
-
|
|
32614
|
+
const extractionCacheDb = openPipelineDb();
|
|
32615
|
+
let extraction;
|
|
32616
|
+
let extractionCacheHits = 0;
|
|
32617
|
+
try {
|
|
32618
|
+
const cacheVersion = await getCliCacheVersion();
|
|
32619
|
+
const cachedByPath = /* @__PURE__ */ new Map();
|
|
32620
|
+
if (!noCache && sourceFiles.length > 0) {
|
|
32621
|
+
const hashes = await Promise.all(
|
|
32622
|
+
sourceFiles.map(async (filePath) => [filePath, await hashFile(filePath)])
|
|
32623
|
+
);
|
|
32624
|
+
for (const [filePath, fileHash] of hashes) {
|
|
32625
|
+
cachedByPath.set(filePath, lookupExtractCache(extractionCacheDb, fileHash, cacheVersion));
|
|
32626
|
+
}
|
|
32627
|
+
}
|
|
32628
|
+
const allFilesCached = !noCache && sourceFiles.length > 0 && sourceFiles.every((filePath) => cachedByPath.get(filePath) !== null);
|
|
32629
|
+
if (allFilesCached) {
|
|
32630
|
+
const cachedComponents = sourceFiles.flatMap((filePath) => cachedByPath.get(filePath).components);
|
|
32631
|
+
extractionCacheHits = sourceFiles.length;
|
|
32632
|
+
extraction = { components: cachedComponents, warnings: [], exclusions: [] };
|
|
31513
32633
|
if (!process.stdout.isTTY) {
|
|
31514
|
-
process.stderr.write(
|
|
31515
|
-
`
|
|
32634
|
+
process.stderr.write(
|
|
32635
|
+
`progress=extract:${sourceFiles.length}/${sourceFiles.length}:${cachedComponents.length}
|
|
32636
|
+
`
|
|
32637
|
+
);
|
|
31516
32638
|
}
|
|
31517
|
-
|
|
31518
|
-
|
|
31519
|
-
|
|
32639
|
+
getDebugLogger().event("analyze", "extract.cache-hit", {
|
|
32640
|
+
files: sourceFiles.length,
|
|
32641
|
+
components: cachedComponents.length
|
|
32642
|
+
});
|
|
32643
|
+
} else {
|
|
32644
|
+
extraction = await extractComponents(
|
|
32645
|
+
sourceFiles,
|
|
32646
|
+
({ filesProcessed, componentsFound }) => {
|
|
32647
|
+
if (!process.stdout.isTTY) {
|
|
32648
|
+
process.stderr.write(`progress=extract:${filesProcessed}/${sourceFiles.length}:${componentsFound}
|
|
32649
|
+
`);
|
|
32650
|
+
}
|
|
32651
|
+
},
|
|
32652
|
+
{ resolveUnreachable, projectRoot }
|
|
32653
|
+
);
|
|
32654
|
+
}
|
|
32655
|
+
} finally {
|
|
32656
|
+
extractionCacheDb.close();
|
|
32657
|
+
}
|
|
31520
32658
|
await mkdir6(outDir, { recursive: true });
|
|
31521
32659
|
const db = openPipelineDb();
|
|
31522
32660
|
const { sessionId: sessionId2 } = getOrCreateSession(db, void 0, void 0, {
|
|
@@ -31531,6 +32669,25 @@ function registerInternalExtractCommand(program) {
|
|
|
31531
32669
|
const stepId = createStep(db, sessionId2, "analyze extract", {
|
|
31532
32670
|
project: projectRoot
|
|
31533
32671
|
});
|
|
32672
|
+
if (extractionCacheHits === 0 && !noCache) {
|
|
32673
|
+
const cacheVersion = await getCliCacheVersion();
|
|
32674
|
+
const componentsBySourcePath = /* @__PURE__ */ new Map();
|
|
32675
|
+
for (const component of extraction.components) {
|
|
32676
|
+
if (!component.sourcePath) continue;
|
|
32677
|
+
const components = componentsBySourcePath.get(component.sourcePath) ?? [];
|
|
32678
|
+
components.push(component);
|
|
32679
|
+
componentsBySourcePath.set(component.sourcePath, components);
|
|
32680
|
+
}
|
|
32681
|
+
for (const filePath of sourceFiles) {
|
|
32682
|
+
storeExtractCache(
|
|
32683
|
+
db,
|
|
32684
|
+
filePath,
|
|
32685
|
+
await hashFile(filePath),
|
|
32686
|
+
cacheVersion,
|
|
32687
|
+
componentsBySourcePath.get(filePath) ?? []
|
|
32688
|
+
);
|
|
32689
|
+
}
|
|
32690
|
+
}
|
|
31534
32691
|
const classifiedComponents = extraction.components.map(preClassifyComponent);
|
|
31535
32692
|
for (const exclusion of extraction.exclusions ?? []) {
|
|
31536
32693
|
getDebugLogger().event("filter", "extract.excluded", { ...exclusion });
|
|
@@ -31554,9 +32711,28 @@ function registerInternalExtractCommand(program) {
|
|
|
31554
32711
|
storeRawComponents(db, sessionId2, validatedComponents);
|
|
31555
32712
|
process.stdout.write(`session=${sessionId2}
|
|
31556
32713
|
`);
|
|
31557
|
-
let sourceCallSiteEvidence = [];
|
|
31558
|
-
let sourceCallSiteRejections = [];
|
|
31559
32714
|
{
|
|
32715
|
+
const sources = resolveCompositionSources({
|
|
32716
|
+
...opts,
|
|
32717
|
+
noCache
|
|
32718
|
+
});
|
|
32719
|
+
const { overrides: promptOverrides, errors: promptErrors } = parsePromptOverrides(opts.prompt ?? []);
|
|
32720
|
+
for (const err of promptErrors) {
|
|
32721
|
+
process.stderr.write(`Error: ${err}
|
|
32722
|
+
`);
|
|
32723
|
+
process.exit(1);
|
|
32724
|
+
}
|
|
32725
|
+
let compositionPrompt;
|
|
32726
|
+
const compositionOverride = promptOverrides.get("composition");
|
|
32727
|
+
if (compositionOverride) {
|
|
32728
|
+
try {
|
|
32729
|
+
compositionPrompt = await resolvePromptOverride(compositionOverride);
|
|
32730
|
+
} catch (e) {
|
|
32731
|
+
process.stderr.write(`Error: ${e instanceof Error ? e.message : String(e)}
|
|
32732
|
+
`);
|
|
32733
|
+
process.exit(1);
|
|
32734
|
+
}
|
|
32735
|
+
}
|
|
31560
32736
|
{
|
|
31561
32737
|
const emitCompositionProgress = (phase) => {
|
|
31562
32738
|
if (!process.stdout.isTTY) process.stderr.write(`progress=composition:${phase}
|
|
@@ -31564,18 +32740,62 @@ function registerInternalExtractCommand(program) {
|
|
|
31564
32740
|
};
|
|
31565
32741
|
emitCompositionProgress("resolving");
|
|
31566
32742
|
const allFiles = await readCandidateFiles(validatedComponents, sourceFiles);
|
|
32743
|
+
const selectedCandidates = selectCandidateFiles(allFiles).map((c2) => ({ path: c2.path, content: c2.content }));
|
|
32744
|
+
const capped = capCandidatesToPromptBudget(selectedCandidates);
|
|
32745
|
+
const promptFiles = capped.kept;
|
|
32746
|
+
if (capped.dropped.length > 0) {
|
|
32747
|
+
process.stderr.write(
|
|
32748
|
+
`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.
|
|
32749
|
+
`
|
|
32750
|
+
);
|
|
32751
|
+
}
|
|
31567
32752
|
const runtimeFiles = allFiles.map((c2) => ({ path: c2.path, content: c2.content }));
|
|
32753
|
+
const resolverAgent = resolveCompositionAgentName(opts.agent);
|
|
31568
32754
|
const componentNameSet = new Set(validatedComponents.map((c2) => c2.name));
|
|
32755
|
+
const cacheVersion = await getCliCacheVersion();
|
|
32756
|
+
let lastAgentExitCode = 0;
|
|
32757
|
+
const spawnAgent = async (prompt) => {
|
|
32758
|
+
const res = await runAgent({
|
|
32759
|
+
agent: resolverAgent,
|
|
32760
|
+
prompt,
|
|
32761
|
+
timeoutMs: 12e4,
|
|
32762
|
+
promptViaStdin: true,
|
|
32763
|
+
onDebugEvent: (name, payload) => getDebugLogger().event("agent", name, payload)
|
|
32764
|
+
});
|
|
32765
|
+
lastAgentExitCode = res.exitCode;
|
|
32766
|
+
if (res.exitCode !== 0 && res.stderr.trim()) {
|
|
32767
|
+
process.stderr.write(`Warning: composition \u2014 agent exited ${res.exitCode}: ${res.stderr.trim()}
|
|
32768
|
+
`);
|
|
32769
|
+
}
|
|
32770
|
+
return res.stdout;
|
|
32771
|
+
};
|
|
31569
32772
|
const manifestDocEdges = collectManifestDocEdges(runtimeFiles, validatedComponents, componentNameSet);
|
|
31570
32773
|
const extraEdges = manifestDocEdges;
|
|
31571
|
-
const
|
|
31572
|
-
|
|
31573
|
-
|
|
31574
|
-
|
|
32774
|
+
const agentCacheKey = buildCompositionInputHash({
|
|
32775
|
+
files: promptFiles,
|
|
32776
|
+
agent: resolverAgent
|
|
32777
|
+
});
|
|
32778
|
+
const result = await resolveMapping({
|
|
31575
32779
|
components: validatedComponents,
|
|
31576
32780
|
...extraEdges.length > 0 ? { extraEdges } : {},
|
|
31577
|
-
|
|
31578
|
-
|
|
32781
|
+
forceAgent: sources.forceAgent,
|
|
32782
|
+
files: promptFiles,
|
|
32783
|
+
...compositionPrompt ? { promptOverride: compositionPrompt } : {},
|
|
32784
|
+
runAgentFn: async ({ prompt }) => {
|
|
32785
|
+
if (!noCache && !opts.compositionRefresh) {
|
|
32786
|
+
const cached = lookupCompositionCache(db, agentCacheKey, cacheVersion);
|
|
32787
|
+
if (cached !== null) {
|
|
32788
|
+
emitCompositionProgress("cache-hit");
|
|
32789
|
+
return cached;
|
|
32790
|
+
}
|
|
32791
|
+
}
|
|
32792
|
+
emitCompositionProgress(`agent:${resolverAgent}`);
|
|
32793
|
+
const stdout = await spawnAgent(prompt);
|
|
32794
|
+
if (lastAgentExitCode === 0) {
|
|
32795
|
+
storeCompositionCache(db, agentCacheKey, cacheVersion, stdout);
|
|
32796
|
+
}
|
|
32797
|
+
return stdout;
|
|
32798
|
+
}
|
|
31579
32799
|
});
|
|
31580
32800
|
emitCompositionProgress("done");
|
|
31581
32801
|
for (const w of result.warnings) process.stderr.write(`Warning: composition \u2014 ${w}
|
|
@@ -31605,13 +32825,7 @@ function registerInternalExtractCommand(program) {
|
|
|
31605
32825
|
sessionId2,
|
|
31606
32826
|
sourceFiles.map((f) => relative2(projectRoot, f))
|
|
31607
32827
|
);
|
|
31608
|
-
await retryDatabaseWrite(
|
|
31609
|
-
() => updateStep(db, stepId, "complete", {
|
|
31610
|
-
sessionId: sessionId2,
|
|
31611
|
-
compositionEvidence: JSON.stringify(sourceCallSiteEvidence),
|
|
31612
|
-
compositionRejections: JSON.stringify(sourceCallSiteRejections)
|
|
31613
|
-
})
|
|
31614
|
-
);
|
|
32828
|
+
await retryDatabaseWrite(() => updateStep(db, stepId, "complete", { sessionId: sessionId2 }));
|
|
31615
32829
|
enrichCommandResult({ extracted_component_count: validatedComponents.length });
|
|
31616
32830
|
db.close();
|
|
31617
32831
|
const allWarnings = [...extraction.warnings, ...filterWarnings];
|
|
@@ -31633,12 +32847,18 @@ var SCANNED_FILE_EXTENSIONS, DENYLIST_GATED_EXTENSIONS, DENYLISTED_EXACT_FILE_NA
|
|
|
31633
32847
|
var init_extract_command = __esm({
|
|
31634
32848
|
"packages/experience-design-system-cli-legacy/src/analyze/extract-command.ts"() {
|
|
31635
32849
|
"use strict";
|
|
32850
|
+
init_agent_model_options();
|
|
31636
32851
|
init_src2();
|
|
31637
32852
|
init_db();
|
|
32853
|
+
init_cache_keys();
|
|
31638
32854
|
init_cycle_detection();
|
|
31639
32855
|
init_resolve_mapping();
|
|
32856
|
+
init_resolve_mapping_cli();
|
|
32857
|
+
init_candidate_files();
|
|
32858
|
+
init_composition_cache_key();
|
|
31640
32859
|
init_manifest_doc_evidence();
|
|
31641
|
-
|
|
32860
|
+
init_prompt_overrides();
|
|
32861
|
+
init_src();
|
|
31642
32862
|
init_analytics();
|
|
31643
32863
|
init_debug_logger();
|
|
31644
32864
|
SCANNED_FILE_EXTENSIONS = /* @__PURE__ */ new Set([".astro", ".js", ".jsx", ".svelte", ".ts", ".tsx", ".vue"]);
|
|
@@ -31732,9 +32952,9 @@ __export(program_exports, {
|
|
|
31732
32952
|
runBuild: () => runBuild
|
|
31733
32953
|
});
|
|
31734
32954
|
import { spawn as spawn7 } from "node:child_process";
|
|
31735
|
-
import { fileURLToPath as
|
|
31736
|
-
import { dirname as
|
|
31737
|
-
import { readFileSync as
|
|
32955
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
32956
|
+
import { dirname as dirname19, join as join29, resolve as resolve21 } from "node:path";
|
|
32957
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
31738
32958
|
import { Command } from "commander";
|
|
31739
32959
|
async function runBuild(opts) {
|
|
31740
32960
|
return new Promise((resolvePromise) => {
|
|
@@ -31763,7 +32983,7 @@ function resolveBedrockFromAncestors(actionCommand) {
|
|
|
31763
32983
|
}
|
|
31764
32984
|
function registerBuildCommand(program) {
|
|
31765
32985
|
program.command("build").description("Rebuild from source and re-link exo/experiences binaries to this build").helpOption(false).action(async () => {
|
|
31766
|
-
const pkgRoot =
|
|
32986
|
+
const pkgRoot = resolve21(dirname19(fileURLToPath4(import.meta.url)), "..", "..");
|
|
31767
32987
|
process.stderr.write("\u2699 Building from source...\n");
|
|
31768
32988
|
const { exitCode } = await runBuild({
|
|
31769
32989
|
spawnFn: () => spawn7("pnpm", ["build"], { cwd: pkgRoot, stdio: "inherit" }),
|
|
@@ -31833,7 +33053,7 @@ var init_program = __esm({
|
|
|
31833
33053
|
init_analytics();
|
|
31834
33054
|
init_credentials_store();
|
|
31835
33055
|
init_cli_path();
|
|
31836
|
-
pkg3 = JSON.parse(
|
|
33056
|
+
pkg3 = JSON.parse(readFileSync11(join29(findPkgRoot(), "package.json"), "utf8"));
|
|
31837
33057
|
}
|
|
31838
33058
|
});
|
|
31839
33059
|
|