@contentful/experience-design-system-cli 2.12.0 → 2.12.1-dev-build-589b615.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/README.md +214 -357
- package/dist/package.json +1 -1
- package/dist/src/analyze/extract/astro.js +9 -0
- package/dist/src/analyze/extract/react.js +23 -0
- package/dist/src/analyze/extract/stencil.js +3 -0
- package/dist/src/analyze/extract/vue.js +6 -0
- package/dist/src/analyze/extract/web-components.js +10 -0
- package/dist/src/analyze/pre-classify.d.ts +1 -1
- package/dist/src/analyze/pre-classify.js +3 -3
- package/dist/src/analyze/select/persistence.d.ts +13 -0
- package/dist/src/analyze/select/persistence.js +38 -0
- package/dist/src/analyze/select/preview-annotations.d.ts +26 -0
- package/dist/src/analyze/select/preview-annotations.js +62 -0
- package/dist/src/analyze/select/tui/App.js +5 -2
- package/dist/src/analyze/select/tui/components/ComponentRationalePanel.d.ts +30 -0
- package/dist/src/analyze/select/tui/components/ComponentRationalePanel.js +137 -0
- package/dist/src/analyze/select/tui/components/FieldEditor.d.ts +58 -1
- package/dist/src/analyze/select/tui/components/FieldEditor.js +637 -161
- package/dist/src/analyze/select/tui/components/FinalizeDialog.js +1 -1
- package/dist/src/analyze/select/tui/components/JsonPanel.js +5 -1
- package/dist/src/analyze/select/tui/components/RationalePanel.d.ts +34 -0
- package/dist/src/analyze/select/tui/components/RationalePanel.js +92 -0
- package/dist/src/analyze/select/tui/components/Sidebar.d.ts +13 -1
- package/dist/src/analyze/select/tui/components/Sidebar.js +27 -3
- package/dist/src/analyze/select/tui/hooks/scroll-offset.d.ts +29 -0
- package/dist/src/analyze/select/tui/hooks/scroll-offset.js +26 -0
- package/dist/src/analyze/select-agent/command.d.ts +2 -0
- package/dist/src/analyze/select-agent/command.js +259 -45
- package/dist/src/analyze/select-agent/show-rationale.d.ts +35 -0
- package/dist/src/analyze/select-agent/show-rationale.js +92 -0
- package/dist/src/apply/command.js +7 -3
- package/dist/src/apply/tui/ServerApplyView.d.ts +3 -1
- package/dist/src/apply/tui/ServerApplyView.js +3 -2
- package/dist/src/credentials-store.d.ts +5 -0
- package/dist/src/credentials-store.js +7 -1
- package/dist/src/generate/agent-runner.d.ts +14 -0
- package/dist/src/generate/agent-runner.js +16 -0
- package/dist/src/generate/command.d.ts +6 -0
- package/dist/src/generate/command.js +45 -10
- package/dist/src/generate/progress.d.ts +9 -0
- package/dist/src/generate/progress.js +11 -0
- package/dist/src/generate/prompt-builder.d.ts +8 -0
- package/dist/src/generate/prompt-builder.js +22 -11
- package/dist/src/import/agent-model-resolve.d.ts +23 -0
- package/dist/src/import/agent-model-resolve.js +35 -0
- package/dist/src/import/auto-filter-resolve.d.ts +12 -0
- package/dist/src/import/auto-filter-resolve.js +16 -0
- package/dist/src/import/command.js +248 -8
- package/dist/src/import/orchestrator.d.ts +2 -0
- package/dist/src/import/orchestrator.js +11 -3
- package/dist/src/import/print-prompt.d.ts +35 -0
- package/dist/src/import/print-prompt.js +31 -0
- package/dist/src/import/tui/CustomPromptBanner.d.ts +11 -0
- package/dist/src/import/tui/CustomPromptBanner.js +7 -0
- package/dist/src/import/tui/WizardApp.d.ts +112 -8
- package/dist/src/import/tui/WizardApp.js +814 -333
- package/dist/src/import/tui/auto-filter-error.d.ts +2 -0
- package/dist/src/import/tui/auto-filter-error.js +29 -0
- package/dist/src/import/tui/final-review-host.d.ts +15 -0
- package/dist/src/import/tui/final-review-host.js +20 -0
- package/dist/src/import/tui/push-decision-gate-helpers.d.ts +8 -0
- package/dist/src/import/tui/push-decision-gate-helpers.js +8 -0
- package/dist/src/import/tui/push-progress.d.ts +23 -0
- package/dist/src/import/tui/push-progress.js +14 -0
- package/dist/src/import/tui/run-print-files-helpers.d.ts +26 -0
- package/dist/src/import/tui/run-print-files-helpers.js +8 -0
- package/dist/src/import/tui/run-teaser.d.ts +5 -0
- package/dist/src/import/tui/run-teaser.js +9 -0
- package/dist/src/import/tui/runLivePreview.d.ts +35 -0
- package/dist/src/import/tui/runLivePreview.js +73 -0
- package/dist/src/import/tui/runScopeGate.d.ts +22 -0
- package/dist/src/import/tui/runScopeGate.js +28 -0
- package/dist/src/import/tui/scope-gate-host.d.ts +21 -0
- package/dist/src/import/tui/scope-gate-host.js +20 -0
- package/dist/src/import/tui/spawn-generate.d.ts +33 -0
- package/dist/src/import/tui/spawn-generate.js +53 -0
- package/dist/src/import/tui/steps/CredentialsStep.d.ts +25 -1
- package/dist/src/import/tui/steps/CredentialsStep.js +31 -3
- package/dist/src/import/tui/steps/DoneStep.d.ts +6 -1
- package/dist/src/import/tui/steps/DoneStep.js +10 -4
- package/dist/src/import/tui/steps/GenerateReviewStep.d.ts +29 -2
- package/dist/src/import/tui/steps/GenerateReviewStep.js +412 -48
- package/dist/src/import/tui/steps/PushDecisionGateStep.d.ts +19 -0
- package/dist/src/import/tui/steps/PushDecisionGateStep.js +76 -0
- package/dist/src/import/tui/steps/PushingStep.d.ts +10 -0
- package/dist/src/import/tui/steps/PushingStep.js +40 -0
- package/dist/src/import/tui/steps/ScopeGateStep.d.ts +23 -0
- package/dist/src/import/tui/steps/ScopeGateStep.js +243 -0
- package/dist/src/import/tui/steps/TokenInputStep.js +20 -3
- package/dist/src/import/tui/useLivePreview.d.ts +35 -0
- package/dist/src/import/tui/useLivePreview.js +120 -0
- package/dist/src/import/tui/wizard-generate-progress.d.ts +21 -0
- package/dist/src/import/tui/wizard-generate-progress.js +25 -0
- package/dist/src/import/tui/wizard-save-flow.d.ts +37 -0
- package/dist/src/import/tui/wizard-save-flow.js +20 -0
- package/dist/src/import/tui/wizard-state-transitions.d.ts +80 -0
- package/dist/src/import/tui/wizard-state-transitions.js +79 -0
- package/dist/src/lib/contentful-urls.d.ts +34 -0
- package/dist/src/lib/contentful-urls.js +41 -0
- package/dist/src/program.js +2 -0
- package/dist/src/runs/export-helpers.d.ts +30 -0
- package/dist/src/runs/export-helpers.js +59 -0
- package/dist/src/runs/fingerprint.d.ts +47 -0
- package/dist/src/runs/fingerprint.js +75 -0
- package/dist/src/runs/ls-command.d.ts +12 -0
- package/dist/src/runs/ls-command.js +137 -0
- package/dist/src/runs/modify-launcher.d.ts +24 -0
- package/dist/src/runs/modify-launcher.js +36 -0
- package/dist/src/runs/path-prompt.d.ts +8 -0
- package/dist/src/runs/path-prompt.js +72 -0
- package/dist/src/runs/push-creds-prompt.d.ts +25 -0
- package/dist/src/runs/push-creds-prompt.js +39 -0
- package/dist/src/runs/push-helpers.d.ts +29 -0
- package/dist/src/runs/push-helpers.js +69 -0
- package/dist/src/runs/replay-helpers.d.ts +67 -0
- package/dist/src/runs/replay-helpers.js +148 -0
- package/dist/src/runs/resolve-run-target.d.ts +12 -0
- package/dist/src/runs/resolve-run-target.js +45 -0
- package/dist/src/runs/run-picker-mount.d.ts +46 -0
- package/dist/src/runs/run-picker-mount.js +72 -0
- package/dist/src/runs/run-picker.d.ts +17 -0
- package/dist/src/runs/run-picker.js +145 -0
- package/dist/src/runs/save-conflict.d.ts +8 -0
- package/dist/src/runs/save-conflict.js +56 -0
- package/dist/src/runs/save-path-resolver.d.ts +55 -0
- package/dist/src/runs/save-path-resolver.js +71 -0
- package/dist/src/runs/staleness.d.ts +38 -0
- package/dist/src/runs/staleness.js +140 -0
- package/dist/src/runs/store.d.ts +78 -0
- package/dist/src/runs/store.js +136 -0
- package/dist/src/session/cache-keys.d.ts +15 -0
- package/dist/src/session/cache-keys.js +38 -0
- package/dist/src/session/db.d.ts +89 -3
- package/dist/src/session/db.js +447 -104
- package/dist/src/setup/auto-filter-prompt.d.ts +13 -0
- package/dist/src/setup/auto-filter-prompt.js +24 -0
- package/dist/src/setup/command.d.ts +7 -0
- package/dist/src/setup/command.js +58 -2
- package/dist/src/types.d.ts +6 -0
- package/package.json +2 -2
- package/skills/generate-components.md +54 -6
- package/skills/select-components.md +13 -4
|
@@ -1,16 +1,30 @@
|
|
|
1
|
-
import { openPipelineDb, loadRawComponents, loadScannedFiles, createStep, updateStep } from '../../session/db.js';
|
|
1
|
+
import { openPipelineDb, loadRawComponents, loadScannedFiles, createStep, updateStep, computeComponentInputHash, lookupSelectCache, storeSelectCache, getCliCacheVersion, } from '../../session/db.js';
|
|
2
|
+
import { hashPromptForSkill } from '../../session/cache-keys.js';
|
|
2
3
|
import { appendReviewEvent, getRefineArtifactsRoot, ensureRefineSession, getRefineSessionPaths, saveReviewState, } from '../select/persistence.js';
|
|
3
4
|
import { loadReviewInput } from '../select/parser.js';
|
|
4
5
|
import { buildPrompt } from '../../generate/prompt-builder.js';
|
|
6
|
+
import { formatCustomPromptBanner } from '../../generate/command.js';
|
|
5
7
|
import { parseSelectToolCallLines, runAgent } from '../../generate/agent-runner.js';
|
|
8
|
+
import { access } from 'node:fs/promises';
|
|
6
9
|
import { readExperiencesCredentials } from '../../credentials-store.js';
|
|
7
10
|
import { OutputFormatter, c } from '../../output/format.js';
|
|
8
11
|
import { buildRepoContextIndex, buildSelectionContext } from './context-builder.js';
|
|
12
|
+
import { runShowRationale } from './show-rationale.js';
|
|
9
13
|
import { isAbsolute, resolve } from 'node:path';
|
|
10
14
|
import { validateExtractedComponents, shouldExcludeDueToValidation, formatExclusionWarning, } from '../extract/validate.js';
|
|
11
15
|
const VALID_AGENTS = new Set(['claude', 'codex', 'opencode', 'cursor']);
|
|
12
16
|
const DEFAULT_TIMEOUT_MS = Number(process.env.EDS_AGENT_TIMEOUT_MS ?? 3 * 60 * 1000);
|
|
13
|
-
const DEFAULT_CONCURRENCY =
|
|
17
|
+
export const DEFAULT_CONCURRENCY = 10;
|
|
18
|
+
export const DEFAULT_BATCH_SIZE = 5;
|
|
19
|
+
function resolveBatchSize() {
|
|
20
|
+
const raw = process.env.EDS_SELECT_BATCH_SIZE;
|
|
21
|
+
if (!raw)
|
|
22
|
+
return DEFAULT_BATCH_SIZE;
|
|
23
|
+
const n = Number(raw);
|
|
24
|
+
if (!Number.isFinite(n) || n < 1)
|
|
25
|
+
return DEFAULT_BATCH_SIZE;
|
|
26
|
+
return Math.floor(n);
|
|
27
|
+
}
|
|
14
28
|
function resolveSessionId(sessionFlag) {
|
|
15
29
|
if (sessionFlag)
|
|
16
30
|
return sessionFlag;
|
|
@@ -83,15 +97,14 @@ function resolveProjectRoot(sessionId, projectRootFlag) {
|
|
|
83
97
|
db.close();
|
|
84
98
|
}
|
|
85
99
|
}
|
|
86
|
-
async function
|
|
87
|
-
const { component } = candidate;
|
|
100
|
+
async function selectBatch(agent, model, batch, total, verbose, skillPathOverride) {
|
|
88
101
|
const prompt = await buildPrompt({
|
|
89
102
|
skill: 'select',
|
|
90
103
|
mode: 'autonomous',
|
|
91
|
-
rawComponentsInline: JSON.stringify(
|
|
104
|
+
rawComponentsInline: JSON.stringify(batch.map((b) => buildComponentData(b.candidate)), null, 2),
|
|
92
105
|
outDir: process.cwd(),
|
|
106
|
+
skillPathOverride,
|
|
93
107
|
});
|
|
94
|
-
const pos = c.dim(`[${index + 1}/${total}]`);
|
|
95
108
|
let outputBuf = '';
|
|
96
109
|
const formatter = new OutputFormatter(verbose, (s) => {
|
|
97
110
|
outputBuf += s;
|
|
@@ -106,67 +119,183 @@ async function selectOneComponent(agent, model, candidate, index, total, verbose
|
|
|
106
119
|
});
|
|
107
120
|
formatter.flush();
|
|
108
121
|
if (verbose) {
|
|
109
|
-
|
|
122
|
+
const names = batch.map((b) => b.candidate.component.name).join(', ');
|
|
123
|
+
process.stderr.write(` ${c.bold(`batch: ${names}`)}\n${outputBuf}`);
|
|
110
124
|
}
|
|
125
|
+
// Feature 3: emit one progress= line per component (in input order) regardless
|
|
126
|
+
// of batch outcome. The wizard's runAutoFilter parser depends on this contract.
|
|
127
|
+
const emitProgress = (item, decision, reason) => {
|
|
128
|
+
const reasonEncoded = reason ? encodeURIComponent(reason) : '';
|
|
129
|
+
process.stderr.write(`progress=select-agent:${item.index + 1}/${total}:${decision}:${item.candidate.component.name}:${reasonEncoded}\n`);
|
|
130
|
+
};
|
|
131
|
+
// Whole-batch failure: timeout or non-zero exit. Mark every item failed and
|
|
132
|
+
// do NOT emit progress lines (no decision was made).
|
|
111
133
|
if (result.timedOut) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
134
|
+
for (const item of batch) {
|
|
135
|
+
const pos = c.dim(`[${item.index + 1}/${total}]`);
|
|
136
|
+
process.stderr.write(` ${pos} ${c.bold(item.candidate.component.name)} ${c.yellow('timed out')}\n`);
|
|
137
|
+
}
|
|
138
|
+
return batch.map((item) => ({
|
|
139
|
+
componentKey: componentKey(item.candidate.component),
|
|
140
|
+
componentName: item.candidate.component.name,
|
|
116
141
|
decision: null,
|
|
117
142
|
failed: true,
|
|
118
|
-
};
|
|
143
|
+
}));
|
|
119
144
|
}
|
|
120
145
|
if (result.exitCode !== 0) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
146
|
+
for (const item of batch) {
|
|
147
|
+
const pos = c.dim(`[${item.index + 1}/${total}]`);
|
|
148
|
+
process.stderr.write(` ${pos} ${c.bold(item.candidate.component.name)} ${c.red(`agent exited with code ${result.exitCode}`)}\n`);
|
|
149
|
+
}
|
|
150
|
+
return batch.map((item) => ({
|
|
151
|
+
componentKey: componentKey(item.candidate.component),
|
|
152
|
+
componentName: item.candidate.component.name,
|
|
125
153
|
decision: null,
|
|
126
154
|
failed: true,
|
|
127
|
-
};
|
|
155
|
+
}));
|
|
128
156
|
}
|
|
129
157
|
const { calls, warnings } = parseSelectToolCallLines(result.stdout);
|
|
130
158
|
if (warnings.length > 0) {
|
|
131
159
|
for (const warning of warnings) {
|
|
132
|
-
process.stderr.write(` ${c.yellow('⚠')}
|
|
160
|
+
process.stderr.write(` ${c.yellow('⚠')} batch: ${warning}\n`);
|
|
133
161
|
}
|
|
134
162
|
}
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
163
|
+
const results = [];
|
|
164
|
+
for (const item of batch) {
|
|
165
|
+
const { component } = item.candidate;
|
|
166
|
+
const pos = c.dim(`[${item.index + 1}/${total}]`);
|
|
167
|
+
const call = calls.find((toolCall) => toolCall.name === component.name);
|
|
168
|
+
if (!call) {
|
|
169
|
+
process.stderr.write(` ${pos} ${c.bold(component.name)} ${c.yellow('no tool call')}\n`);
|
|
170
|
+
results.push({
|
|
171
|
+
componentKey: componentKey(component),
|
|
172
|
+
componentName: component.name,
|
|
173
|
+
decision: null,
|
|
174
|
+
failed: true,
|
|
175
|
+
});
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const decision = call.tool === 'select_component' ? 'accepted' : 'rejected';
|
|
179
|
+
const finalColor = decision === 'accepted' ? c.green : c.red;
|
|
180
|
+
process.stderr.write(` ${pos} ${c.bold(component.name)} ${finalColor(decision)}${call.reason ? ` ${c.dim(call.reason)}` : ''}\n`);
|
|
181
|
+
emitProgress(item, decision, call.reason);
|
|
182
|
+
results.push({
|
|
139
183
|
componentKey: componentKey(component),
|
|
140
184
|
componentName: component.name,
|
|
141
|
-
decision
|
|
142
|
-
|
|
143
|
-
|
|
185
|
+
decision,
|
|
186
|
+
reason: call.reason,
|
|
187
|
+
failed: false,
|
|
188
|
+
});
|
|
144
189
|
}
|
|
145
|
-
|
|
146
|
-
const finalColor = decision === 'accepted' ? c.green : c.red;
|
|
147
|
-
process.stderr.write(` ${pos} ${c.bold(component.name)} ${finalColor(decision)}${call.reason ? ` ${c.dim(call.reason)}` : ''}\n`);
|
|
148
|
-
return {
|
|
149
|
-
componentKey: componentKey(component),
|
|
150
|
-
componentName: component.name,
|
|
151
|
-
decision,
|
|
152
|
-
reason: call.reason,
|
|
153
|
-
failed: false,
|
|
154
|
-
};
|
|
190
|
+
return results;
|
|
155
191
|
}
|
|
156
|
-
async function selectAllComponents(agent, model, components, verbose) {
|
|
192
|
+
async function selectAllComponents(agent, model, components, verbose, skillPathOverride, cacheConfig = { noCache: true }) {
|
|
157
193
|
const concurrency = Number(process.env.EDS_GENERATE_CONCURRENCY ?? DEFAULT_CONCURRENCY);
|
|
158
|
-
|
|
159
|
-
|
|
194
|
+
const batchSize = resolveBatchSize();
|
|
195
|
+
const total = components.length;
|
|
196
|
+
// ── Fine-grained select cache: replay decisions for components whose
|
|
197
|
+
// (component_hash, prompt_hash, cli_version) triple already has a row. Only
|
|
198
|
+
// uncached components are forwarded to the LLM batches.
|
|
199
|
+
const cachedResults = new Map();
|
|
200
|
+
let promptHash = '';
|
|
201
|
+
let cliVersion = '';
|
|
202
|
+
if (!cacheConfig.noCache) {
|
|
203
|
+
try {
|
|
204
|
+
promptHash = await hashPromptForSkill('select', skillPathOverride);
|
|
205
|
+
cliVersion = await getCliCacheVersion();
|
|
206
|
+
const db = openPipelineDb(cacheConfig.dbPath);
|
|
207
|
+
try {
|
|
208
|
+
for (let i = 0; i < components.length; i++) {
|
|
209
|
+
const candidate = components[i];
|
|
210
|
+
const compHash = computeComponentInputHash(candidate.component);
|
|
211
|
+
const hit = lookupSelectCache(db, compHash, promptHash, cliVersion);
|
|
212
|
+
if (hit) {
|
|
213
|
+
const finalColor = hit.decision === 'accepted' ? c.green : c.red;
|
|
214
|
+
process.stderr.write(` ${c.dim(`[${i + 1}/${total}]`)} ${c.bold(candidate.component.name)} ${finalColor(hit.decision)} ${c.dim('(cached)')}` +
|
|
215
|
+
(hit.reason ? ` ${c.dim(hit.reason)}` : '') +
|
|
216
|
+
'\n');
|
|
217
|
+
// Mirror the progress= line that selectBatch emits for live LLM
|
|
218
|
+
// calls so the wizard's parser sees a uniform stream.
|
|
219
|
+
const reasonEncoded = hit.reason ? encodeURIComponent(hit.reason) : '';
|
|
220
|
+
process.stderr.write(`progress=select-agent:${i + 1}/${total}:${hit.decision}:${candidate.component.name}:${reasonEncoded}\n`);
|
|
221
|
+
cachedResults.set(i, {
|
|
222
|
+
componentKey: componentKey(candidate.component),
|
|
223
|
+
componentName: candidate.component.name,
|
|
224
|
+
decision: hit.decision,
|
|
225
|
+
reason: hit.reason ?? undefined,
|
|
226
|
+
failed: false,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
finally {
|
|
232
|
+
db.close();
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
// Cache prefill is best-effort. On any error, fall through and run the
|
|
237
|
+
// full LLM batch path.
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
// Build the work-set of components we still need to ask the LLM about.
|
|
241
|
+
const uncached = [];
|
|
242
|
+
const uncachedIndices = [];
|
|
243
|
+
for (let i = 0; i < components.length; i++) {
|
|
244
|
+
if (!cachedResults.has(i)) {
|
|
245
|
+
uncached.push(components[i]);
|
|
246
|
+
uncachedIndices.push(i);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
// Chunk into batches of `batchSize`, preserving original indices for the
|
|
250
|
+
// per-component progress=select-agent: lines.
|
|
251
|
+
const batches = [];
|
|
252
|
+
for (let i = 0; i < uncached.length; i += batchSize) {
|
|
253
|
+
const slice = uncached.slice(i, i + batchSize);
|
|
254
|
+
batches.push(slice.map((candidate, j) => ({ candidate, index: uncachedIndices[i + j] })));
|
|
255
|
+
}
|
|
256
|
+
process.stderr.write(`Validating ${c.bold(String(uncached.length))} component${uncached.length === 1 ? '' : 's'}` +
|
|
257
|
+
(cachedResults.size > 0 ? c.dim(` (${cachedResults.size} cached)`) : '') +
|
|
258
|
+
c.dim(` (concurrency: ${concurrency}, batch: ${batchSize}, batches: ${batches.length})`) +
|
|
160
259
|
'\n');
|
|
161
|
-
const results = new Array(
|
|
162
|
-
|
|
260
|
+
const results = new Array(total);
|
|
261
|
+
for (const [i, r] of cachedResults)
|
|
262
|
+
results[i] = r;
|
|
263
|
+
let nextBatch = 0;
|
|
163
264
|
async function worker() {
|
|
164
|
-
while (
|
|
165
|
-
const
|
|
166
|
-
|
|
265
|
+
while (nextBatch < batches.length) {
|
|
266
|
+
const b = nextBatch++;
|
|
267
|
+
const batch = batches[b];
|
|
268
|
+
const batchResults = await selectBatch(agent, model, batch, total, verbose, skillPathOverride);
|
|
269
|
+
for (let k = 0; k < batch.length; k++) {
|
|
270
|
+
results[batch[k].index] = batchResults[k];
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
await Promise.all(Array.from({ length: Math.min(concurrency, batches.length) }, worker));
|
|
275
|
+
// Persist fresh decisions (skip cached + failed ones).
|
|
276
|
+
if (!cacheConfig.noCache && promptHash) {
|
|
277
|
+
try {
|
|
278
|
+
const db = openPipelineDb(cacheConfig.dbPath);
|
|
279
|
+
try {
|
|
280
|
+
for (let i = 0; i < results.length; i++) {
|
|
281
|
+
if (cachedResults.has(i))
|
|
282
|
+
continue;
|
|
283
|
+
const r = results[i];
|
|
284
|
+
if (!r || r.failed || !r.decision)
|
|
285
|
+
continue;
|
|
286
|
+
const candidate = components[i];
|
|
287
|
+
const compHash = computeComponentInputHash(candidate.component);
|
|
288
|
+
storeSelectCache(db, compHash, promptHash, cliVersion, r.decision, r.reason ?? null);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
finally {
|
|
292
|
+
db.close();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
// Best-effort.
|
|
167
297
|
}
|
|
168
298
|
}
|
|
169
|
-
await Promise.all(Array.from({ length: Math.min(concurrency, components.length) }, worker));
|
|
170
299
|
return results;
|
|
171
300
|
}
|
|
172
301
|
export function registerAnalyzeSelectAgentCommand(program) {
|
|
@@ -180,7 +309,29 @@ export function registerAnalyzeSelectAgentCommand(program) {
|
|
|
180
309
|
.option('--verbose', 'Show full agent output including reasoning text')
|
|
181
310
|
.option('--dry-run', 'Print the prompt for the first component without invoking the agent')
|
|
182
311
|
.option('--exclude-invalid', 'Auto-reject components with validation errors instead of failing loud (LLM cannot fix structural issues)')
|
|
312
|
+
.option('--select-prompt-path <path>', 'Path to a custom .md skill prompt for select-agent (bypasses bundled prompt invariants)')
|
|
313
|
+
.option('--no-select-cache', 'Skip the per-component select cache and re-LLM every component')
|
|
314
|
+
.option('--no-cache', 'Skip ALL fine-grained caches (extract, select, generate)')
|
|
315
|
+
.option('--show-rationale', 'Read-only: print the AI rejection rationale persisted by a prior select-agent run and exit. ' +
|
|
316
|
+
'No LLM call. Combine with --json for machine-readable output.')
|
|
317
|
+
.option('--json', 'When used with --show-rationale, emit a JSON array instead of a human-readable table')
|
|
183
318
|
.action(async (opts) => {
|
|
319
|
+
// --show-rationale is a read-only branch that short-circuits the normal
|
|
320
|
+
// select-agent flow. It re-reads the rationale columns persisted by a
|
|
321
|
+
// prior run (raw_components.status + reject_reason) and prints them.
|
|
322
|
+
// No LLM call, no agent resolution, no validation gates.
|
|
323
|
+
if (opts.showRationale) {
|
|
324
|
+
try {
|
|
325
|
+
runShowRationale({ session: opts.session, json: opts.json });
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
catch (err) {
|
|
329
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
330
|
+
process.stderr.write(`Error: ${message}\n`);
|
|
331
|
+
process.exit(1);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
184
335
|
const savedCreds = await readExperiencesCredentials();
|
|
185
336
|
const agentName = opts.agent ?? savedCreds.agent;
|
|
186
337
|
const model = opts.model ?? savedCreds.agentModel;
|
|
@@ -190,6 +341,24 @@ export function registerAnalyzeSelectAgentCommand(program) {
|
|
|
190
341
|
return;
|
|
191
342
|
}
|
|
192
343
|
const agent = agentName;
|
|
344
|
+
// Feature 8: validate + announce custom prompt path before any heavy
|
|
345
|
+
// work. Flag wins over saved credentials.
|
|
346
|
+
const selectPromptPath = opts.selectPromptPath ?? savedCreds.selectPromptPath;
|
|
347
|
+
if (selectPromptPath) {
|
|
348
|
+
const resolvedPath = resolve(selectPromptPath);
|
|
349
|
+
const exists = await access(resolvedPath)
|
|
350
|
+
.then(() => true)
|
|
351
|
+
.catch(() => false);
|
|
352
|
+
if (!exists) {
|
|
353
|
+
process.stderr.write(`Error: custom prompt path not found: ${resolvedPath}\n`);
|
|
354
|
+
process.exit(1);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (!selectPromptPath.toLowerCase().endsWith('.md')) {
|
|
358
|
+
process.stderr.write(`WARNING: custom prompt path does not end in .md (${selectPromptPath}) — proceeding anyway.\n`);
|
|
359
|
+
}
|
|
360
|
+
process.stderr.write(formatCustomPromptBanner('select', resolvedPath));
|
|
361
|
+
}
|
|
193
362
|
const sessionId = resolveSessionId(opts.session);
|
|
194
363
|
const selectionRoot = resolveProjectRoot(sessionId, opts.projectRoot);
|
|
195
364
|
const db = openPipelineDb();
|
|
@@ -265,19 +434,64 @@ export function registerAnalyzeSelectAgentCommand(program) {
|
|
|
265
434
|
mode: 'autonomous',
|
|
266
435
|
rawComponentsInline: JSON.stringify([buildComponentData(first)], null, 2),
|
|
267
436
|
outDir: process.cwd(),
|
|
437
|
+
skillPathOverride: selectPromptPath ? resolve(selectPromptPath) : undefined,
|
|
268
438
|
});
|
|
269
439
|
process.stdout.write(prompt + '\n');
|
|
270
440
|
process.exit(0);
|
|
271
441
|
return;
|
|
272
442
|
}
|
|
273
|
-
|
|
443
|
+
// --no-cache is the global kill-switch; --no-select-cache is the stage-
|
|
444
|
+
// specific opt-out. Both Commander negation flags arrive as `false` when
|
|
445
|
+
// the user passed --no-*; default (undefined) means cache stays on.
|
|
446
|
+
const noCache = opts.cache === false || opts.selectCache === false || process.env.EDS_NO_CACHE === '1';
|
|
447
|
+
const selectResults = await selectAllComponents(agent, model, selectionCandidates, opts.verbose ?? false, selectPromptPath ? resolve(selectPromptPath) : undefined, { noCache });
|
|
274
448
|
// Build decision map from results. Seed auto-rejections from validation exclusions first.
|
|
275
449
|
const decisions = new Map();
|
|
450
|
+
// Track per-component reasons (for raw_components.reject_reason persistence).
|
|
451
|
+
// Validation auto-rejections get a synthesized "validation error: <codes>" reason
|
|
452
|
+
// so the scope-gate UI can distinguish wizard- vs LLM-driven exclusions.
|
|
453
|
+
const reasons = new Map();
|
|
276
454
|
for (const comp of invalidComponents) {
|
|
277
455
|
decisions.set(componentKey(comp), 'rejected');
|
|
456
|
+
const codes = (comp.validationIssues ?? [])
|
|
457
|
+
.filter((i) => i.severity === 'error')
|
|
458
|
+
.map((i) => i.code)
|
|
459
|
+
.join(', ');
|
|
460
|
+
reasons.set(componentKey(comp), `validation error: ${codes}`);
|
|
278
461
|
}
|
|
279
462
|
for (const r of selectResults) {
|
|
280
463
|
decisions.set(r.componentKey, r.decision);
|
|
464
|
+
if (r.decision === 'rejected' && r.reason) {
|
|
465
|
+
reasons.set(r.componentKey, r.reason);
|
|
466
|
+
}
|
|
467
|
+
else if (r.decision === 'accepted') {
|
|
468
|
+
// Defensive: clear any previously-stored reason on re-runs that flip a
|
|
469
|
+
// rejected component to accepted.
|
|
470
|
+
reasons.set(r.componentKey, null);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
// Feature 3: persist decisions to raw_components (status + reject_reason)
|
|
474
|
+
// so the wizard can render LLM exclusions in the scope-gate without re-reading
|
|
475
|
+
// the snapshot file. We open a fresh DB handle here (the earlier one was closed
|
|
476
|
+
// after loading raw components above) and reuse it for the step-recording below.
|
|
477
|
+
const persistDb = openPipelineDb();
|
|
478
|
+
try {
|
|
479
|
+
const updateStmt = persistDb.prepare(`UPDATE raw_components
|
|
480
|
+
SET status = ?, reject_reason = ?
|
|
481
|
+
WHERE session_id = ? AND component_id = ?`);
|
|
482
|
+
for (const comp of validatedComponents) {
|
|
483
|
+
const key = componentKey(comp);
|
|
484
|
+
const decision = decisions.get(key);
|
|
485
|
+
if (!decision)
|
|
486
|
+
continue;
|
|
487
|
+
if (!comp.component_id)
|
|
488
|
+
continue;
|
|
489
|
+
const reason = reasons.get(key) ?? null;
|
|
490
|
+
updateStmt.run(decision, decision === 'accepted' ? null : reason, sessionId, comp.component_id);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
finally {
|
|
494
|
+
persistDb.close();
|
|
281
495
|
}
|
|
282
496
|
const artifactsRoot = getRefineArtifactsRoot();
|
|
283
497
|
let snapshot;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only rationale view for the `analyze select-agent --show-rationale` flag.
|
|
3
|
+
*
|
|
4
|
+
* Reads the rationale data already persisted by a previous `analyze select-agent`
|
|
5
|
+
* run (component-level decision + reject reason on raw_components; per-prop
|
|
6
|
+
* rationale on raw_props — both populated by the writer path in command.ts and
|
|
7
|
+
* the rationale columns added in the schema migration for PR #52). No LLM
|
|
8
|
+
* invocation, no schema changes.
|
|
9
|
+
*
|
|
10
|
+
* Schema-version assertion: if the rationale columns are absent (older DB),
|
|
11
|
+
* throw with a clear message pointing at the remediation step.
|
|
12
|
+
*/
|
|
13
|
+
export interface RationaleRow {
|
|
14
|
+
name: string;
|
|
15
|
+
decision: 'accepted' | 'rejected' | 'needs-review' | 'extracted';
|
|
16
|
+
reason: string | null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolves which session to read from. If `sessionFlag` is provided, asserts
|
|
20
|
+
* the session exists and has at least one raw component; otherwise falls back
|
|
21
|
+
* to the most recent completed `analyze select` step.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveRationaleSession(sessionFlag: string | undefined, dbPath?: string): string;
|
|
24
|
+
export declare function loadRationaleRows(sessionId: string, dbPath?: string): RationaleRow[];
|
|
25
|
+
export declare function formatRationaleTable(rows: RationaleRow[]): string;
|
|
26
|
+
export declare function formatRationaleJson(rows: RationaleRow[]): string;
|
|
27
|
+
/**
|
|
28
|
+
* Top-level dispatch for `analyze select-agent --show-rationale`. Pure I/O
|
|
29
|
+
* boundary: reads DB, writes formatted output to stdout, throws on error.
|
|
30
|
+
*/
|
|
31
|
+
export declare function runShowRationale(opts: {
|
|
32
|
+
session?: string;
|
|
33
|
+
json?: boolean;
|
|
34
|
+
dbPath?: string;
|
|
35
|
+
}): void;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { openPipelineDb, findLatestSessionForCommand } from '../../session/db.js';
|
|
2
|
+
const REQUIRED_COLUMNS = ['status', 'reject_reason'];
|
|
3
|
+
function assertSchema(dbPath) {
|
|
4
|
+
const db = openPipelineDb(dbPath);
|
|
5
|
+
try {
|
|
6
|
+
const cols = db.prepare('PRAGMA table_info(raw_components)').all();
|
|
7
|
+
const have = new Set(cols.map((c) => c.name));
|
|
8
|
+
const missing = REQUIRED_COLUMNS.filter((c) => !have.has(c));
|
|
9
|
+
if (missing.length > 0) {
|
|
10
|
+
throw new Error(`Rationale data missing — run a fresh 'experiences import' on this session first. ` +
|
|
11
|
+
`(raw_components is missing column(s): ${missing.join(', ')})`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
finally {
|
|
15
|
+
db.close();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolves which session to read from. If `sessionFlag` is provided, asserts
|
|
20
|
+
* the session exists and has at least one raw component; otherwise falls back
|
|
21
|
+
* to the most recent completed `analyze select` step.
|
|
22
|
+
*/
|
|
23
|
+
export function resolveRationaleSession(sessionFlag, dbPath) {
|
|
24
|
+
const db = openPipelineDb(dbPath);
|
|
25
|
+
try {
|
|
26
|
+
if (sessionFlag) {
|
|
27
|
+
const row = db.prepare('SELECT 1 AS ok FROM raw_components WHERE session_id = ? LIMIT 1').get(sessionFlag);
|
|
28
|
+
if (!row) {
|
|
29
|
+
throw new Error(`Session not found or has no components: '${sessionFlag}'. ` +
|
|
30
|
+
`Run 'analyze extract' + 'analyze select-agent' on this session first.`);
|
|
31
|
+
}
|
|
32
|
+
return sessionFlag;
|
|
33
|
+
}
|
|
34
|
+
const latest = findLatestSessionForCommand(db, 'analyze select');
|
|
35
|
+
if (!latest) {
|
|
36
|
+
throw new Error(`No completed 'analyze select' session found. Run 'analyze select-agent' first, or pass --session <id>.`);
|
|
37
|
+
}
|
|
38
|
+
return latest;
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
db.close();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
export function loadRationaleRows(sessionId, dbPath) {
|
|
45
|
+
const db = openPipelineDb(dbPath);
|
|
46
|
+
try {
|
|
47
|
+
const rows = db
|
|
48
|
+
.prepare(`SELECT name, status, reject_reason FROM raw_components
|
|
49
|
+
WHERE session_id = ?
|
|
50
|
+
ORDER BY name`)
|
|
51
|
+
.all(sessionId);
|
|
52
|
+
return rows.map((r) => ({
|
|
53
|
+
name: r.name,
|
|
54
|
+
decision: r.status ?? 'extracted',
|
|
55
|
+
reason: r.reject_reason,
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
db.close();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export function formatRationaleTable(rows) {
|
|
63
|
+
if (rows.length === 0) {
|
|
64
|
+
return 'No rationale rows found for this session.\n';
|
|
65
|
+
}
|
|
66
|
+
const header = { name: 'Component', decision: 'Decision', reason: 'Reason' };
|
|
67
|
+
const all = [header, ...rows.map((r) => ({ name: r.name, decision: r.decision, reason: r.reason ?? '' }))];
|
|
68
|
+
const nameWidth = Math.max(...all.map((r) => r.name.length));
|
|
69
|
+
const decisionWidth = Math.max(...all.map((r) => r.decision.length));
|
|
70
|
+
const lines = [];
|
|
71
|
+
const fmt = (n, d, r) => `${n.padEnd(nameWidth)} ${d.padEnd(decisionWidth)} ${r}`;
|
|
72
|
+
lines.push(fmt(header.name, header.decision, header.reason));
|
|
73
|
+
lines.push(fmt('-'.repeat(nameWidth), '-'.repeat(decisionWidth), '-'.repeat(Math.max(6, header.reason.length))));
|
|
74
|
+
for (const row of rows) {
|
|
75
|
+
lines.push(fmt(row.name, row.decision, row.reason ?? ''));
|
|
76
|
+
}
|
|
77
|
+
return lines.join('\n') + '\n';
|
|
78
|
+
}
|
|
79
|
+
export function formatRationaleJson(rows) {
|
|
80
|
+
return (JSON.stringify(rows.map((r) => ({ name: r.name, decision: r.decision, reason: r.reason })), null, 2) + '\n');
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Top-level dispatch for `analyze select-agent --show-rationale`. Pure I/O
|
|
84
|
+
* boundary: reads DB, writes formatted output to stdout, throws on error.
|
|
85
|
+
*/
|
|
86
|
+
export function runShowRationale(opts) {
|
|
87
|
+
assertSchema(opts.dbPath);
|
|
88
|
+
const sessionId = resolveRationaleSession(opts.session, opts.dbPath);
|
|
89
|
+
const rows = loadRationaleRows(sessionId, opts.dbPath);
|
|
90
|
+
const output = opts.json ? formatRationaleJson(rows) : formatRationaleTable(rows);
|
|
91
|
+
process.stdout.write(output);
|
|
92
|
+
}
|
|
@@ -7,6 +7,7 @@ import { ApiError, ImportApiClient } from './api-client.js';
|
|
|
7
7
|
import { openPipelineDb, loadCDFComponents } from '../session/db.js';
|
|
8
8
|
import { ServerPreviewApp, ServerPreviewConfirm, ServerApplyProgress, ServerApplyDone } from './tui/ServerApplyView.js';
|
|
9
9
|
import { SelectView, makeSelectKey } from './tui/SelectView.js';
|
|
10
|
+
import { buildPostPushUrl } from '../lib/contentful-urls.js';
|
|
10
11
|
function die(message) {
|
|
11
12
|
process.stderr.write(`${message}\n`);
|
|
12
13
|
process.exit(1);
|
|
@@ -214,7 +215,7 @@ function buildPreviewOutput(preview, spaceId, environmentId) {
|
|
|
214
215
|
},
|
|
215
216
|
};
|
|
216
217
|
}
|
|
217
|
-
function buildApplyOutput(operation, spaceId, environmentId) {
|
|
218
|
+
function buildApplyOutput(operation, spaceId, environmentId, host) {
|
|
218
219
|
const items = operation.items ?? [];
|
|
219
220
|
const componentItems = items.filter((i) => i.entityType === 'ComponentType');
|
|
220
221
|
const tokenItems = items.filter((i) => i.entityType === 'DesignToken');
|
|
@@ -233,6 +234,7 @@ function buildApplyOutput(operation, spaceId, environmentId) {
|
|
|
233
234
|
summary: operation.summary,
|
|
234
235
|
componentTypes: countByAction(componentItems),
|
|
235
236
|
designTokens: countByAction(tokenItems),
|
|
237
|
+
viewUrl: buildPostPushUrl({ host: host ?? 'api.contentful.com', spaceId, environmentId }),
|
|
236
238
|
failures: items
|
|
237
239
|
.filter((item) => item.status === 'failed')
|
|
238
240
|
.map((item) => ({
|
|
@@ -529,7 +531,7 @@ export function registerApplyCommand(program) {
|
|
|
529
531
|
die(`Error: ${e.message}`);
|
|
530
532
|
throw e;
|
|
531
533
|
}
|
|
532
|
-
const summary = buildApplyOutput(operation, spaceId, environmentId);
|
|
534
|
+
const summary = buildApplyOutput(operation, spaceId, environmentId, opts.host);
|
|
533
535
|
process.stdout.write(JSON.stringify(summary, null, 2) + '\n');
|
|
534
536
|
process.exit(operation.sys.status === 'succeeded' ? 0 : 1);
|
|
535
537
|
return;
|
|
@@ -583,6 +585,7 @@ export function registerApplyCommand(program) {
|
|
|
583
585
|
operation,
|
|
584
586
|
spaceId,
|
|
585
587
|
environmentId,
|
|
588
|
+
host: opts.host,
|
|
586
589
|
}));
|
|
587
590
|
resolvePromise();
|
|
588
591
|
};
|
|
@@ -696,7 +699,7 @@ export function registerApplyCommand(program) {
|
|
|
696
699
|
die(`Error: ${e.message}`);
|
|
697
700
|
throw e;
|
|
698
701
|
}
|
|
699
|
-
const summary = buildApplyOutput(operation, spaceId, environmentId);
|
|
702
|
+
const summary = buildApplyOutput(operation, spaceId, environmentId, opts.host);
|
|
700
703
|
process.stdout.write(JSON.stringify(summary, null, 2) + '\n');
|
|
701
704
|
process.exit(operation.sys.status === 'succeeded' ? 0 : 1);
|
|
702
705
|
return;
|
|
@@ -762,6 +765,7 @@ export function registerApplyCommand(program) {
|
|
|
762
765
|
operation,
|
|
763
766
|
spaceId,
|
|
764
767
|
environmentId,
|
|
768
|
+
host: opts.host,
|
|
765
769
|
}));
|
|
766
770
|
resolvePromise();
|
|
767
771
|
};
|
|
@@ -27,6 +27,8 @@ interface ServerApplyDoneProps {
|
|
|
27
27
|
operation: ApplyOperationResponse;
|
|
28
28
|
spaceId: string;
|
|
29
29
|
environmentId: string;
|
|
30
|
+
/** Configured API host (e.g. `api.contentful.com`). Used to derive the post-push webapp URL. */
|
|
31
|
+
host?: string;
|
|
30
32
|
}
|
|
31
|
-
export declare function ServerApplyDone({ operation, spaceId, environmentId }: ServerApplyDoneProps): React.ReactElement;
|
|
33
|
+
export declare function ServerApplyDone({ operation, spaceId, environmentId, host }: ServerApplyDoneProps): React.ReactElement;
|
|
32
34
|
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text, useInput } from 'ink';
|
|
3
3
|
import { ServerPreviewView } from './ServerPreviewView.js';
|
|
4
|
+
import { buildPostPushUrl } from '../../lib/contentful-urls.js';
|
|
4
5
|
export function ServerPreviewConfirm({ preview, spaceId, environmentId, breakingWithImpact, onConfirm, onCancel, }) {
|
|
5
6
|
useInput((input, key) => {
|
|
6
7
|
if (key.return)
|
|
@@ -24,14 +25,14 @@ export function ServerApplyProgress({ spaceId, environmentId, status, operationI
|
|
|
24
25
|
});
|
|
25
26
|
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsxs(Text, { bold: true, children: ["Import \u2014 ", environmentId, " @ ", spaceId] }), _jsx(Text, { children: " " }), status === 'applying' && _jsx(Text, { children: " Submitting apply request..." }), status === 'polling' && _jsxs(Text, { children: [" Operation ", operationId, " in progress..."] }), status === 'error' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: "red", children: [" \u2717 Error: ", error] }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: " Press Q to exit." })] }))] }));
|
|
26
27
|
}
|
|
27
|
-
export function ServerApplyDone({ operation, spaceId, environmentId }) {
|
|
28
|
+
export function ServerApplyDone({ operation, spaceId, environmentId, host }) {
|
|
28
29
|
useInput((input, key) => {
|
|
29
30
|
if (key.escape || input === 'q') {
|
|
30
31
|
process.exit(operation.sys.status === 'succeeded' ? 0 : 1);
|
|
31
32
|
}
|
|
32
33
|
});
|
|
33
34
|
const failures = (operation.items ?? []).filter((item) => item.status === 'failed');
|
|
34
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsxs(Text, { bold: true, children: ["Import complete \u2014 ", environmentId, " @ ", spaceId] }), _jsx(Text, { children: " " }), _jsxs(Text, { color: "green", children: [" \u2713 ", operation.summary.succeeded, " succeeded"] }), operation.summary.failed > 0 && _jsxs(Text, { color: "red", children: [" \u2717 ", operation.summary.failed, " failed"] }), operation.summary.failed === 0 && _jsx(Text, { dimColor: true, children: " All entities imported successfully." }), failures.length > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: " Failures:" }), failures.map((item, i) => (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: "red", children: [' ', "\u2717 ", item.entityType, ": ", item.id] }), item.error && _jsxs(Text, { dimColor: true, children: [" ", formatItemError(item.error)] })] }, i)))] })), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: " Press Q to exit." })] }));
|
|
35
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsxs(Text, { bold: true, children: ["Import complete \u2014 ", environmentId, " @ ", spaceId] }), _jsx(Text, { children: " " }), _jsxs(Text, { color: "green", children: [" \u2713 ", operation.summary.succeeded, " succeeded"] }), operation.summary.failed > 0 && _jsxs(Text, { color: "red", children: [" \u2717 ", operation.summary.failed, " failed"] }), operation.summary.failed === 0 && _jsx(Text, { dimColor: true, children: " All entities imported successfully." }), failures.length > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: " Failures:" }), failures.map((item, i) => (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: "red", children: [' ', "\u2717 ", item.entityType, ": ", item.id] }), item.error && _jsxs(Text, { dimColor: true, children: [" ", formatItemError(item.error)] })] }, i)))] })), operation.sys.status === 'succeeded' && operation.summary.succeeded > 0 && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: " View your design system:" }), _jsxs(Text, { color: "cyan", children: [" ", buildPostPushUrl({ host: host ?? 'api.contentful.com', spaceId, environmentId })] })] })), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: " Press Q to exit." })] }));
|
|
35
36
|
}
|
|
36
37
|
function formatItemError(error) {
|
|
37
38
|
if (!error)
|
|
@@ -5,6 +5,11 @@ export type ExperiencesCredentials = {
|
|
|
5
5
|
host?: string;
|
|
6
6
|
agent?: string;
|
|
7
7
|
agentModel?: string;
|
|
8
|
+
/** Feature 8: persisted custom prompt path for `analyze select-agent`. */
|
|
9
|
+
selectPromptPath?: string;
|
|
10
|
+
/** Feature 8: persisted custom prompt path for `generate components`. */
|
|
11
|
+
generatePromptPath?: string;
|
|
12
|
+
autoFilter?: boolean;
|
|
8
13
|
};
|
|
9
14
|
export declare function readExperiencesCredentials(): Promise<ExperiencesCredentials>;
|
|
10
15
|
export declare function writeExperiencesCredentials(creds: ExperiencesCredentials): Promise<void>;
|