@contentful/experience-design-system-cli 2.26.1-dev-build-a852362.0 → 2.26.1-dev-build-f03f014.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 +14 -10
- package/dist/src/index.js +34937 -9
- package/dist/src/lib/cli-path.d.ts +4 -0
- package/dist/src/runs/export-helpers.d.ts +1 -12
- package/dist/src/runs/push-helpers.d.ts +1 -6
- package/package.json +12 -7
- package/skills/generate-components.md +427 -0
- package/skills/generate-tokens.md +194 -0
- package/skills/select-components.md +224 -0
- package/dist/src/analytics/apply.js +0 -30
- package/dist/src/analytics/client.js +0 -81
- package/dist/src/analytics/constants.js +0 -4
- package/dist/src/analytics/env.js +0 -14
- package/dist/src/analytics/exit.js +0 -24
- package/dist/src/analytics/index.js +0 -9
- package/dist/src/analytics/normalize.js +0 -18
- package/dist/src/analytics/os.js +0 -13
- package/dist/src/analytics/session.js +0 -15
- package/dist/src/analytics/tracker.js +0 -126
- package/dist/src/analytics/types.js +0 -1
- package/dist/src/analyze/build-analyze-view-rows.js +0 -63
- package/dist/src/analyze/command.js +0 -599
- package/dist/src/analyze/composite-closure.js +0 -0
- package/dist/src/analyze/composition/agent-parser/author-prompt.js +0 -22
- package/dist/src/analyze/composition/agent-parser/extract-parser.js +0 -44
- package/dist/src/analyze/composition/agent-parser/load-prompt.js +0 -31
- package/dist/src/analyze/composition/agent-parser/resolve-via-parser.js +0 -88
- package/dist/src/analyze/composition/agent-parser/sandbox.js +0 -187
- package/dist/src/analyze/composition/apply-mapping.js +0 -67
- package/dist/src/analyze/composition/candidate-critic-agent.js +0 -39
- package/dist/src/analyze/composition/candidate-critic.js +0 -63
- package/dist/src/analyze/composition/candidate-files.js +0 -131
- package/dist/src/analyze/composition/composition-cache-key.js +0 -19
- package/dist/src/analyze/composition/interchange-schema.js +0 -61
- package/dist/src/analyze/composition/manifest-doc-evidence.js +0 -136
- package/dist/src/analyze/composition/merge-edges.js +0 -70
- package/dist/src/analyze/composition/parse-map-edges.js +0 -55
- package/dist/src/analyze/composition/resolve-mapping-cli.js +0 -29
- package/dist/src/analyze/composition/resolve-mapping.js +0 -111
- package/dist/src/analyze/cycle-detection.js +0 -234
- package/dist/src/analyze/cycle-view.js +0 -28
- package/dist/src/analyze/fuzzy-search.js +0 -55
- package/dist/src/analyze/issue-inheritance.js +0 -108
- package/dist/src/analyze/lineage.js +0 -0
- package/dist/src/analyze/scope-gate-cascade.js +0 -170
- package/dist/src/analyze/search-neighborhood.js +0 -56
- package/dist/src/analyze/select/command.js +0 -484
- package/dist/src/analyze/select/index.js +0 -5
- package/dist/src/analyze/select/parser.js +0 -53
- package/dist/src/analyze/select/persistence.js +0 -80
- package/dist/src/analyze/select/preview-annotations.js +0 -62
- package/dist/src/analyze/select/stdout.js +0 -3
- package/dist/src/analyze/select/tui/App.js +0 -483
- package/dist/src/analyze/select/tui/components/ComponentDetail.js +0 -48
- package/dist/src/analyze/select/tui/components/ComponentRationalePanel.js +0 -125
- package/dist/src/analyze/select/tui/components/FieldEditor.js +0 -1131
- package/dist/src/analyze/select/tui/components/FinalizeDialog.js +0 -36
- package/dist/src/analyze/select/tui/components/GotoBanner.js +0 -30
- package/dist/src/analyze/select/tui/components/GroupedSidebar.js +0 -517
- package/dist/src/analyze/select/tui/components/HelpOverlay.js +0 -17
- package/dist/src/analyze/select/tui/components/JsonEditor.js +0 -131
- package/dist/src/analyze/select/tui/components/JsonPanel.js +0 -66
- package/dist/src/analyze/select/tui/components/LineagePanel.js +0 -22
- package/dist/src/analyze/select/tui/components/PreviewSummaryBar.js +0 -29
- package/dist/src/analyze/select/tui/components/QuitDialog.js +0 -14
- package/dist/src/analyze/select/tui/components/RationalePanel.js +0 -80
- package/dist/src/analyze/select/tui/components/Sidebar.js +0 -92
- package/dist/src/analyze/select/tui/components/SourcePanel.js +0 -52
- package/dist/src/analyze/select/tui/components/StatusBar.js +0 -7
- package/dist/src/analyze/select/tui/components/TopBar.js +0 -10
- package/dist/src/analyze/select/tui/components/removed-components-text.js +0 -11
- package/dist/src/analyze/select/tui/hooks/scroll-offset.js +0 -26
- package/dist/src/analyze/select/tui/hooks/useImmediateInput.js +0 -66
- package/dist/src/analyze/select/tui/hooks/useKeymap.js +0 -67
- package/dist/src/analyze/select/tui/hooks/useSession.js +0 -52
- package/dist/src/analyze/select/tui/hooks/useUndo.js +0 -26
- package/dist/src/analyze/select/tui/theme.js +0 -28
- package/dist/src/analyze/select/types.js +0 -39
- package/dist/src/analyze/select-agent/command.js +0 -558
- package/dist/src/analyze/select-agent/context-builder.js +0 -197
- package/dist/src/analyze/select-agent/show-rationale.js +0 -92
- package/dist/src/analyze/selection-cascade.js +0 -19
- package/dist/src/analyze/slot-graph.js +0 -17
- package/dist/src/analyze/tui/AnalyzeView.js +0 -64
- package/dist/src/apply/api-client.js +0 -440
- package/dist/src/apply/command.js +0 -845
- package/dist/src/apply/manifest.js +0 -1
- package/dist/src/apply/preview-utils.js +0 -26
- package/dist/src/apply/tui/SelectView.js +0 -34
- package/dist/src/apply/tui/ServerApplyView.js +0 -49
- package/dist/src/apply/tui/ServerPreviewView.js +0 -23
- package/dist/src/credentials-store.js +0 -74
- package/dist/src/generate/command.js +0 -597
- package/dist/src/generate/edit/command.js +0 -127
- package/dist/src/generate/tui/GenerateView.js +0 -10
- package/dist/src/host-utils.js +0 -26
- package/dist/src/import/agent-model-resolve.js +0 -35
- package/dist/src/import/auto-filter-resolve.js +0 -16
- package/dist/src/import/command.js +0 -380
- package/dist/src/import/cycle-auto-reject.js +0 -14
- package/dist/src/import/orchestrator.js +0 -603
- package/dist/src/import/path-utils.js +0 -30
- package/dist/src/import/picker-dispatch.js +0 -44
- package/dist/src/import/print-prompt.js +0 -31
- package/dist/src/import/strip-allowed-components.js +0 -22
- package/dist/src/import/tui/CustomPromptBanner.js +0 -8
- package/dist/src/import/tui/WizardApp.js +0 -1670
- package/dist/src/import/tui/ai-flag.js +0 -6
- package/dist/src/import/tui/auto-filter-error.js +0 -29
- package/dist/src/import/tui/autocomplete.js +0 -32
- package/dist/src/import/tui/components/AutoFilterBanner.js +0 -19
- package/dist/src/import/tui/components/CounterStrip.js +0 -12
- package/dist/src/import/tui/components/LegendEntry.js +0 -6
- package/dist/src/import/tui/cycle-panel-scroll.js +0 -33
- package/dist/src/import/tui/final-review-host.js +0 -25
- package/dist/src/import/tui/group-collapse.js +0 -11
- package/dist/src/import/tui/history.js +0 -53
- package/dist/src/import/tui/hooks/useLineage.js +0 -50
- package/dist/src/import/tui/hooks/useOverlayPanel.js +0 -27
- package/dist/src/import/tui/lineage-layout.js +0 -82
- package/dist/src/import/tui/merge-ai-decisions.js +0 -22
- package/dist/src/import/tui/push-decision-gate-helpers.js +0 -8
- package/dist/src/import/tui/push-progress.js +0 -1
- package/dist/src/import/tui/run-print-files-helpers.js +0 -8
- package/dist/src/import/tui/run-teaser.js +0 -9
- package/dist/src/import/tui/runLivePreview.js +0 -82
- package/dist/src/import/tui/runScopeGate.js +0 -28
- package/dist/src/import/tui/scope-gate-columns.js +0 -94
- package/dist/src/import/tui/scope-gate-host.js +0 -28
- package/dist/src/import/tui/sidebar-width.js +0 -3
- package/dist/src/import/tui/spawn-generate.js +0 -53
- package/dist/src/import/tui/step-filters.js +0 -42
- package/dist/src/import/tui/steps/AtomicGenerateReviewStep.js +0 -726
- package/dist/src/import/tui/steps/AtomicScopeGateStep.js +0 -210
- package/dist/src/import/tui/steps/CredentialsStep.js +0 -108
- package/dist/src/import/tui/steps/DoneStep.js +0 -24
- package/dist/src/import/tui/steps/ErrorStep.js +0 -16
- package/dist/src/import/tui/steps/GateStep.js +0 -22
- package/dist/src/import/tui/steps/GenerateReviewStep.js +0 -1618
- package/dist/src/import/tui/steps/PathValidationStep.js +0 -152
- package/dist/src/import/tui/steps/PreviewStep.js +0 -37
- package/dist/src/import/tui/steps/PreviewValidationErrorStep.js +0 -23
- package/dist/src/import/tui/steps/PushDecisionGateStep.js +0 -73
- package/dist/src/import/tui/steps/PushingStep.js +0 -24
- package/dist/src/import/tui/steps/RunningStep.js +0 -21
- package/dist/src/import/tui/steps/ScopeGateStep.js +0 -907
- package/dist/src/import/tui/steps/TokenInputStep.js +0 -88
- package/dist/src/import/tui/steps/WelcomeStep.js +0 -34
- package/dist/src/import/tui/steps/WizardPreviewStep.js +0 -169
- package/dist/src/import/tui/steps/auto-reject-decision.js +0 -9
- package/dist/src/import/tui/steps/breaking-change-format.js +0 -24
- package/dist/src/import/tui/steps/enumerate-cycle-breaks.js +0 -0
- package/dist/src/import/tui/steps/preview-diff.js +0 -175
- package/dist/src/import/tui/useFinalizePreview.js +0 -0
- package/dist/src/import/tui/useLivePreview.js +0 -122
- package/dist/src/import/tui/wizard-422-helpers.js +0 -60
- package/dist/src/import/tui/wizard-generate-progress.js +0 -25
- package/dist/src/import/tui/wizard-save-flow.js +0 -20
- package/dist/src/import/tui/wizard-state-transitions.js +0 -32
- package/dist/src/lib/agent-model-options.js +0 -15
- package/dist/src/lib/command-options.js +0 -30
- package/dist/src/lib/composition-mode.js +0 -39
- package/dist/src/lib/contentful-urls.js +0 -27
- package/dist/src/lib/debug-logger.js +0 -229
- package/dist/src/lib/debug-preamble.js +0 -33
- package/dist/src/lib/error-parser.js +0 -269
- package/dist/src/lib/prompt-overrides.js +0 -69
- package/dist/src/lib/terminal-capabilities.js +0 -51
- package/dist/src/lib/user-agent.js +0 -29
- package/dist/src/output/format.js +0 -110
- package/dist/src/print/command.js +0 -221
- package/dist/src/print/validate/tui/ValidateView.js +0 -37
- package/dist/src/print/validate/validators/cdf-validator.js +0 -104
- package/dist/src/print/validate/validators/dtcg-validator.js +0 -110
- package/dist/src/print/validate/validators/format-errors.js +0 -18
- package/dist/src/program.js +0 -105
- package/dist/src/runs/export-helpers.js +0 -59
- package/dist/src/runs/fingerprint.js +0 -75
- package/dist/src/runs/ls-command.js +0 -137
- package/dist/src/runs/modify-launcher.js +0 -42
- package/dist/src/runs/path-prompt.js +0 -72
- package/dist/src/runs/push-creds-prompt.js +0 -39
- package/dist/src/runs/push-helpers.js +0 -72
- package/dist/src/runs/push-launcher.js +0 -77
- package/dist/src/runs/replay-helpers.js +0 -164
- package/dist/src/runs/resolve-run-target.js +0 -45
- package/dist/src/runs/run-picker-mount.js +0 -72
- package/dist/src/runs/run-picker.js +0 -129
- package/dist/src/runs/save-conflict.js +0 -56
- package/dist/src/runs/save-path-resolver.js +0 -75
- package/dist/src/runs/staleness.js +0 -140
- package/dist/src/runs/store.js +0 -136
- package/dist/src/session/cache-keys.js +0 -44
- package/dist/src/session/command.js +0 -261
- package/dist/src/session/db.js +0 -1538
- package/dist/src/session/migration.js +0 -117
- package/dist/src/session/session-id.js +0 -212
- package/dist/src/session/stats.js +0 -89
- package/dist/src/setup/analytics-prompt.js +0 -24
- package/dist/src/setup/auto-filter-prompt.js +0 -24
- package/dist/src/setup/command.js +0 -966
- package/dist/src/setup/composition-mode-prompt.js +0 -37
- package/dist/src/setup/debug-mode-prompt.js +0 -22
- package/dist/src/types.js +0 -1
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
|
-
import { readFile, stat } from 'node:fs/promises';
|
|
3
|
-
import { resolve } from 'node:path';
|
|
4
|
-
function rowField(row, key) {
|
|
5
|
-
const v = row[key];
|
|
6
|
-
return typeof v === 'string' ? v : null;
|
|
7
|
-
}
|
|
8
|
-
export function sha256Hex(buf) {
|
|
9
|
-
return createHash('sha256').update(buf).digest('hex');
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Build a per-file fingerprint of every source file that contributed to a
|
|
13
|
-
* run. Stats each unique source_path once (first-seen component name wins),
|
|
14
|
-
* and (optionally) hashes the raw tokens file too.
|
|
15
|
-
*
|
|
16
|
-
* Missing files do NOT throw — they're simply omitted. The read-side
|
|
17
|
-
* staleness check re-stats from disk and surfaces missing files there so we
|
|
18
|
-
* can report which one disappeared.
|
|
19
|
-
*/
|
|
20
|
-
export async function buildSourceFingerprint(opts) {
|
|
21
|
-
const rows = opts.db
|
|
22
|
-
.prepare('SELECT name, source_path FROM raw_components WHERE session_id = ?')
|
|
23
|
-
.all(opts.extractSessionId);
|
|
24
|
-
const files = {};
|
|
25
|
-
const seen = new Set();
|
|
26
|
-
for (const row of rows) {
|
|
27
|
-
const sourcePath = rowField(row, 'source_path');
|
|
28
|
-
const name = rowField(row, 'name');
|
|
29
|
-
if (!sourcePath)
|
|
30
|
-
continue;
|
|
31
|
-
const abs = resolve(sourcePath);
|
|
32
|
-
if (seen.has(abs))
|
|
33
|
-
continue;
|
|
34
|
-
seen.add(abs);
|
|
35
|
-
try {
|
|
36
|
-
const st = await stat(abs);
|
|
37
|
-
const entry = { mtime: st.mtime.toISOString() };
|
|
38
|
-
if (name)
|
|
39
|
-
entry.componentName = name;
|
|
40
|
-
files[abs] = entry;
|
|
41
|
-
}
|
|
42
|
-
catch {
|
|
43
|
-
// Source file missing at fingerprint time — skip silently. Staleness
|
|
44
|
-
// can only fire on files we recorded; a file removed before save
|
|
45
|
-
// simply isn't tracked. Operators usually re-extract in that case.
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
let rawTokensPath = null;
|
|
49
|
-
let rawTokensMtime = null;
|
|
50
|
-
let rawTokensContentHash = null;
|
|
51
|
-
if (opts.rawTokensPath) {
|
|
52
|
-
const abs = resolve(opts.rawTokensPath);
|
|
53
|
-
rawTokensPath = abs;
|
|
54
|
-
try {
|
|
55
|
-
const [st, buf] = await Promise.all([stat(abs), readFile(abs)]);
|
|
56
|
-
rawTokensMtime = st.mtime.toISOString();
|
|
57
|
-
rawTokensContentHash = sha256Hex(buf);
|
|
58
|
-
}
|
|
59
|
-
catch {
|
|
60
|
-
// Missing raw tokens — record the path but leave mtime/hash null so
|
|
61
|
-
// the staleness check can detect it as missing on read.
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return { files, rawTokensPath, rawTokensMtime, rawTokensContentHash };
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Hash the saved JSON contents the wizard just wrote. Caller passes the raw
|
|
68
|
-
* bytes (or strings) so we hash exactly what landed on disk.
|
|
69
|
-
*/
|
|
70
|
-
export function buildSavedFingerprint(input) {
|
|
71
|
-
return {
|
|
72
|
-
componentsJsonHash: input.componentsJson != null ? sha256Hex(input.componentsJson) : null,
|
|
73
|
-
tokensJsonHash: input.tokensJson != null ? sha256Hex(input.tokensJson) : null,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
import { listRuns } from './store.js';
|
|
2
|
-
import { resolveRunTarget } from './resolve-run-target.js';
|
|
3
|
-
import { checkRunStaleness, shortStalenessSummary, formatStalenessDetail } from './staleness.js';
|
|
4
|
-
function pad(value, width) {
|
|
5
|
-
if (value.length >= width)
|
|
6
|
-
return value;
|
|
7
|
-
return value + ' '.repeat(width - value.length);
|
|
8
|
-
}
|
|
9
|
-
function formatCreated(iso) {
|
|
10
|
-
// Drop ms + Z, render as `YYYY-MM-DD HH:MM`.
|
|
11
|
-
const m = /^(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2})/.exec(iso);
|
|
12
|
-
return m ? `${m[1]} ${m[2]}` : iso;
|
|
13
|
-
}
|
|
14
|
-
function formatPushed(record) {
|
|
15
|
-
if (!record.pushedTo)
|
|
16
|
-
return '(not pushed)';
|
|
17
|
-
return `${record.pushedTo.spaceId}/${record.pushedTo.environmentId}`;
|
|
18
|
-
}
|
|
19
|
-
function makeColumns(staleness) {
|
|
20
|
-
return [
|
|
21
|
-
{ header: 'ID', get: (r) => r.id },
|
|
22
|
-
{ header: 'CREATED', get: (r) => formatCreated(r.createdAt) },
|
|
23
|
-
{ header: 'PROJECT', get: (r) => r.projectPath },
|
|
24
|
-
{ header: 'SAVED TO', get: (r) => r.savePath },
|
|
25
|
-
{ header: 'COMPONENTS', get: (r) => String(r.componentCount) },
|
|
26
|
-
{ header: 'PUSHED', get: formatPushed },
|
|
27
|
-
{ header: 'STALE', get: (_r, i) => shortStalenessSummary(staleness[i]) },
|
|
28
|
-
];
|
|
29
|
-
}
|
|
30
|
-
function renderFooter(runs, write) {
|
|
31
|
-
if (runs.length === 0)
|
|
32
|
-
return;
|
|
33
|
-
const id = runs[0].id;
|
|
34
|
-
write('\n');
|
|
35
|
-
write(`Push run ${id}: experiences import --push-from-run ${id}\n`);
|
|
36
|
-
write(`Modify run ${id}: experiences import --modify ${id}\n`);
|
|
37
|
-
}
|
|
38
|
-
async function renderDetail(run, write) {
|
|
39
|
-
const lines = [
|
|
40
|
-
`Run ${run.id}`,
|
|
41
|
-
`Created: ${formatCreated(run.createdAt)}`,
|
|
42
|
-
`Project: ${run.projectPath}`,
|
|
43
|
-
`Saved: ${run.savePath}`,
|
|
44
|
-
`Components: ${run.componentCount}`,
|
|
45
|
-
`Tokens: ${run.tokenCount}`,
|
|
46
|
-
];
|
|
47
|
-
if (run.tokensPath) {
|
|
48
|
-
lines.push(`Tokens saved: ${run.tokensPath}`);
|
|
49
|
-
}
|
|
50
|
-
lines.push(`Agent: ${run.agent}`, `Pushed: ${formatPushed(run)}`, '');
|
|
51
|
-
// Staleness status block. v2/v1 records (no sourceFingerprint) render as
|
|
52
|
-
// UNKNOWN — the operator can re-extract for a fresh run.
|
|
53
|
-
if (!run.sourceFingerprint) {
|
|
54
|
-
lines.push('Status: UNKNOWN (run pre-dates the staleness fingerprint).');
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
const staleness = await checkRunStaleness(run);
|
|
58
|
-
lines.push(...formatStalenessDetail(staleness));
|
|
59
|
-
}
|
|
60
|
-
lines.push('', `Push to Contentful: experiences import --push-from-run ${run.id}`, `Modify in wizard: experiences import --modify ${run.id}`, '');
|
|
61
|
-
write(lines.join('\n'));
|
|
62
|
-
}
|
|
63
|
-
export async function runLsCommand(opts = {}) {
|
|
64
|
-
const write = opts.write ?? ((s) => process.stdout.write(s));
|
|
65
|
-
if (opts.pushed && opts.notPushed) {
|
|
66
|
-
throw new Error('--pushed and --not-pushed are mutually exclusive');
|
|
67
|
-
}
|
|
68
|
-
if (opts.target) {
|
|
69
|
-
const run = await resolveRunTarget(opts.target);
|
|
70
|
-
if (opts.json) {
|
|
71
|
-
write(JSON.stringify(run, null, 2) + '\n');
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
await renderDetail(run, write);
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
let runs = await listRuns({
|
|
78
|
-
...(opts.projectPath ? { projectPath: opts.projectPath } : {}),
|
|
79
|
-
...(typeof opts.limit === 'number' ? { limit: opts.limit } : {}),
|
|
80
|
-
});
|
|
81
|
-
if (opts.pushed)
|
|
82
|
-
runs = runs.filter((r) => r.pushedTo !== null);
|
|
83
|
-
if (opts.notPushed)
|
|
84
|
-
runs = runs.filter((r) => r.pushedTo === null);
|
|
85
|
-
if (opts.json) {
|
|
86
|
-
write(JSON.stringify(runs, null, 2) + '\n');
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
if (runs.length === 0) {
|
|
90
|
-
write('No runs recorded yet. Run `experiences import` to create one.\n');
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
// Compute staleness once per row so the table is consistent across the
|
|
94
|
-
// STALE column and any future detail-equivalent surfaces.
|
|
95
|
-
const stalenessByIdx = await Promise.all(runs.map(async (r) => (r.sourceFingerprint ? checkRunStaleness(r) : null)));
|
|
96
|
-
const stalenessForCol = stalenessByIdx.map((s) => s ?? {
|
|
97
|
-
stale: false,
|
|
98
|
-
staleComponents: [],
|
|
99
|
-
staleTokens: false,
|
|
100
|
-
savedComponentsEdited: false,
|
|
101
|
-
savedTokensEdited: false,
|
|
102
|
-
missingSourceFiles: [],
|
|
103
|
-
});
|
|
104
|
-
const columns = makeColumns(stalenessForCol);
|
|
105
|
-
// Auto-expand each column to max(header, max(row value)) so long paths
|
|
106
|
-
// aren't silently truncated.
|
|
107
|
-
const widths = columns.map((c) => Math.max(c.header.length, ...runs.map((r, i) => c.get(r, i).length)));
|
|
108
|
-
const headerRow = columns.map((c, i) => pad(c.header, widths[i])).join(' ');
|
|
109
|
-
write(headerRow + '\n');
|
|
110
|
-
for (let i = 0; i < runs.length; i++) {
|
|
111
|
-
const r = runs[i];
|
|
112
|
-
const row = columns.map((c, ci) => pad(c.get(r, i), widths[ci])).join(' ');
|
|
113
|
-
write(row + '\n');
|
|
114
|
-
}
|
|
115
|
-
renderFooter(runs, write);
|
|
116
|
-
}
|
|
117
|
-
export function registerRunsCommand(program) {
|
|
118
|
-
program
|
|
119
|
-
.command('runs [target]')
|
|
120
|
-
.alias('ls')
|
|
121
|
-
.description('List recorded import runs from ~/.config/experiences/runs.json, or show one run when [target] (id or path) is given')
|
|
122
|
-
.option('--project <path>', 'Filter by source project path (absolute)')
|
|
123
|
-
.option('--limit <n>', 'Limit the number of rows', (v) => parseInt(v, 10))
|
|
124
|
-
.option('--json', 'Emit RunRecord JSON to stdout (array, or single object with [target])')
|
|
125
|
-
.option('--pushed', 'Only show runs that have been pushed to Contentful')
|
|
126
|
-
.option('--not-pushed', 'Only show runs that have not been pushed')
|
|
127
|
-
.action(async (target, options) => {
|
|
128
|
-
await runLsCommand({
|
|
129
|
-
...(target ? { target } : {}),
|
|
130
|
-
...(options.project ? { projectPath: options.project } : {}),
|
|
131
|
-
...(typeof options.limit === 'number' && !Number.isNaN(options.limit) ? { limit: options.limit } : {}),
|
|
132
|
-
...(options.json ? { json: true } : {}),
|
|
133
|
-
...(options.pushed ? { pushed: true } : {}),
|
|
134
|
-
...(options.notPushed ? { notPushed: true } : {}),
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Thin indirection so `runModifyCommand` can be unit-tested without spinning
|
|
3
|
-
* up the real Ink wizard. The production implementation lives here.
|
|
4
|
-
*/
|
|
5
|
-
export async function launchModifyWizard(input) {
|
|
6
|
-
const { render } = await import('ink');
|
|
7
|
-
const { createElement } = await import('react');
|
|
8
|
-
const { WizardApp } = await import('../import/tui/WizardApp.js');
|
|
9
|
-
// Modify entry: re-open the wizard with the prior run's sessions seeded so
|
|
10
|
-
// extract + generate are skipped. The wizard short-circuits to `initialStep`
|
|
11
|
-
// (typically `final-review`) using state derived from the seed IDs. Saved
|
|
12
|
-
// credentials from the run record's `pushedTo` pre-fill the credentials
|
|
13
|
-
// step (CMA token is never persisted, so it still falls through to the
|
|
14
|
-
// env/credentials.json/prompt resolution path).
|
|
15
|
-
const props = {
|
|
16
|
-
initialProjectPath: input.projectPath,
|
|
17
|
-
seedExtractSessionId: input.extractSessionId,
|
|
18
|
-
initialStep: input.entryStep,
|
|
19
|
-
};
|
|
20
|
-
if (input.generateSessionId)
|
|
21
|
-
props.seedGenerateSessionId = input.generateSessionId;
|
|
22
|
-
if (input.tokenSessionId)
|
|
23
|
-
props.seedTokenSessionId = input.tokenSessionId;
|
|
24
|
-
if (input.compositionMode)
|
|
25
|
-
props.compositionMode = input.compositionMode;
|
|
26
|
-
if (input.saveMode === 'overwrite')
|
|
27
|
-
props.outDirOverride = input.savePath;
|
|
28
|
-
if (input.outDirOverride)
|
|
29
|
-
props.outDirOverride = input.outDirOverride;
|
|
30
|
-
if (input.initialSpaceId)
|
|
31
|
-
props.initialSpaceId = input.initialSpaceId;
|
|
32
|
-
if (input.initialEnvironmentId)
|
|
33
|
-
props.initialEnvironmentId = input.initialEnvironmentId;
|
|
34
|
-
if (input.initialHost)
|
|
35
|
-
props.initialHost = input.initialHost;
|
|
36
|
-
if (input.initialCmaToken)
|
|
37
|
-
props.initialCmaToken = input.initialCmaToken;
|
|
38
|
-
if (input.allowDeletions !== undefined)
|
|
39
|
-
props.allowDeletions = input.allowDeletions;
|
|
40
|
-
const { waitUntilExit } = render(createElement(WizardApp, props));
|
|
41
|
-
await waitUntilExit();
|
|
42
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useEffect } from 'react';
|
|
3
|
-
import { Box, Text } from 'ink';
|
|
4
|
-
import { readdirSync } from 'node:fs';
|
|
5
|
-
import { dirname, basename, join } from 'node:path';
|
|
6
|
-
import { useImmediateInput } from '../analyze/select/tui/hooks/useImmediateInput.js';
|
|
7
|
-
import { normalizePath } from '../import/path-utils.js';
|
|
8
|
-
function autocomplete(partial) {
|
|
9
|
-
if (!partial)
|
|
10
|
-
return null;
|
|
11
|
-
const normalized = normalizePath(partial);
|
|
12
|
-
const dir = dirname(normalized);
|
|
13
|
-
const base = basename(normalized);
|
|
14
|
-
let entries;
|
|
15
|
-
try {
|
|
16
|
-
entries = readdirSync(dir);
|
|
17
|
-
}
|
|
18
|
-
catch {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
const matches = entries.filter((e) => e.startsWith(base));
|
|
22
|
-
if (matches.length === 0)
|
|
23
|
-
return null;
|
|
24
|
-
if (matches.length === 1)
|
|
25
|
-
return join(dir, matches[0]);
|
|
26
|
-
// Common prefix
|
|
27
|
-
let prefix = matches[0];
|
|
28
|
-
for (const m of matches) {
|
|
29
|
-
while (!m.startsWith(prefix))
|
|
30
|
-
prefix = prefix.slice(0, -1);
|
|
31
|
-
if (!prefix)
|
|
32
|
-
break;
|
|
33
|
-
}
|
|
34
|
-
return prefix.length > base.length ? join(dir, prefix) : null;
|
|
35
|
-
}
|
|
36
|
-
export function PathPrompt({ defaultPath, onSubmit, onCancel, label = 'Save to', }) {
|
|
37
|
-
const [input, setInput] = useState('');
|
|
38
|
-
const [cursorVisible, setCursorVisible] = useState(true);
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
const interval = setInterval(() => setCursorVisible((v) => !v), 500);
|
|
41
|
-
return () => clearInterval(interval);
|
|
42
|
-
}, []);
|
|
43
|
-
useImmediateInput((rawInput, key) => {
|
|
44
|
-
if (key.return) {
|
|
45
|
-
const trimmed = input.trim();
|
|
46
|
-
onSubmit(trimmed === '' ? defaultPath : normalizePath(trimmed));
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
if (key.escape) {
|
|
50
|
-
onCancel();
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
if (key.tab) {
|
|
54
|
-
const target = input.trim() || defaultPath;
|
|
55
|
-
const completed = autocomplete(target);
|
|
56
|
-
if (completed)
|
|
57
|
-
setInput(completed);
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
if (key.backspace || key.delete) {
|
|
61
|
-
setInput((v) => v.slice(0, -1));
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
if (rawInput && !key.ctrl && !key.meta) {
|
|
65
|
-
setInput((v) => v + rawInput);
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
const shown = input || defaultPath;
|
|
69
|
-
const isPlaceholder = input === '';
|
|
70
|
-
const cursor = cursorVisible ? '█' : ' ';
|
|
71
|
-
return (_jsxs(Box, { flexDirection: "column", gap: 1, paddingX: 2, paddingY: 1, children: [_jsxs(Box, { gap: 1, children: [_jsx(Text, { color: "cyan", children: "?" }), _jsxs(Text, { bold: true, children: [label, ":"] }), _jsx(Text, { dimColor: isPlaceholder, children: shown }), _jsx(Text, { children: cursor })] }), _jsxs(Box, { gap: 3, children: [_jsx(Text, { dimColor: true, children: "[Enter] Confirm" }), _jsx(Text, { dimColor: true, children: "[Tab] Autocomplete" }), _jsx(Text, { dimColor: true, children: "[Esc] Cancel" })] })] }));
|
|
72
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
export async function promptForPushCredentials(opts = {}) {
|
|
3
|
-
const { render, Box, Text } = await import('ink');
|
|
4
|
-
const { useState } = await import('react');
|
|
5
|
-
const { CredentialsStep } = await import('../import/tui/steps/CredentialsStep.js');
|
|
6
|
-
return new Promise((resolve, reject) => {
|
|
7
|
-
let app = null;
|
|
8
|
-
function App() {
|
|
9
|
-
const [done, setDone] = useState(false);
|
|
10
|
-
const handle = (spaceId, environmentId, cmaToken, host) => {
|
|
11
|
-
if (done)
|
|
12
|
-
return;
|
|
13
|
-
setDone(true);
|
|
14
|
-
// Defer unmount so Ink flushes the final render.
|
|
15
|
-
queueMicrotask(() => {
|
|
16
|
-
app?.unmount();
|
|
17
|
-
resolve({ spaceId, environmentId, cmaToken, host });
|
|
18
|
-
});
|
|
19
|
-
};
|
|
20
|
-
if (done) {
|
|
21
|
-
return React.createElement(Box, null, React.createElement(Text, null, ''));
|
|
22
|
-
}
|
|
23
|
-
return React.createElement(CredentialsStep, {
|
|
24
|
-
summary: opts.summary ?? 'Enter Contentful credentials to push this run. Press Enter on each field to advance.',
|
|
25
|
-
...(opts.initialSpaceId !== undefined ? { initialSpaceId: opts.initialSpaceId } : {}),
|
|
26
|
-
...(opts.initialEnvironmentId !== undefined ? { initialEnvironmentId: opts.initialEnvironmentId } : {}),
|
|
27
|
-
...(opts.initialCmaToken !== undefined ? { initialCmaToken: opts.initialCmaToken } : {}),
|
|
28
|
-
...(opts.initialHost !== undefined ? { initialHost: opts.initialHost } : {}),
|
|
29
|
-
onConfirm: handle,
|
|
30
|
-
onContinue: handle,
|
|
31
|
-
onQuit: () => {
|
|
32
|
-
app?.unmount();
|
|
33
|
-
reject(new Error('Credentials entry cancelled.'));
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
app = render(React.createElement(App));
|
|
38
|
-
});
|
|
39
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { execFile } from 'node:child_process';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
|
-
import { dirname, join } from 'node:path';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
-
/**
|
|
6
|
-
* Resolve the package's CLI binary. Duplicates the walk from export-helpers
|
|
7
|
-
* so push-helpers can be imported independently.
|
|
8
|
-
*/
|
|
9
|
-
function findCliPath() {
|
|
10
|
-
let dir = dirname(fileURLToPath(import.meta.url));
|
|
11
|
-
for (let i = 0; i < 8; i++) {
|
|
12
|
-
const candidate = join(dir, 'bin', 'cli.js');
|
|
13
|
-
if (existsSync(candidate))
|
|
14
|
-
return candidate;
|
|
15
|
-
const parent = dirname(dir);
|
|
16
|
-
if (parent === dir)
|
|
17
|
-
break;
|
|
18
|
-
dir = parent;
|
|
19
|
-
}
|
|
20
|
-
return join(fileURLToPath(import.meta.url), '..', '..', '..', '..', 'bin', 'cli.js');
|
|
21
|
-
}
|
|
22
|
-
function runCli(args) {
|
|
23
|
-
const cliPath = findCliPath();
|
|
24
|
-
if (!existsSync(cliPath)) {
|
|
25
|
-
return Promise.resolve({
|
|
26
|
-
exitCode: 1,
|
|
27
|
-
stdout: '',
|
|
28
|
-
stderr: `Cannot find CLI binary at ${cliPath}`,
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
return new Promise((res) => {
|
|
32
|
-
execFile('node', [cliPath, ...args], (err, stdout, stderr) => {
|
|
33
|
-
res({
|
|
34
|
-
exitCode: err && 'code' in err && typeof err.code === 'number' ? err.code : err ? 1 : 0,
|
|
35
|
-
stdout,
|
|
36
|
-
stderr,
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Push a recorded pipeline.db session's components + tokens to Contentful by
|
|
43
|
-
* shelling out to `experiences apply push --session <id>`. Does no local
|
|
44
|
-
* file I/O — that is the whole point of --push-from-run.
|
|
45
|
-
*/
|
|
46
|
-
export async function pushRunSession(opts) {
|
|
47
|
-
const args = [
|
|
48
|
-
'apply',
|
|
49
|
-
'push',
|
|
50
|
-
'--session',
|
|
51
|
-
opts.sessionId,
|
|
52
|
-
'--space-id',
|
|
53
|
-
opts.spaceId,
|
|
54
|
-
'--environment-id',
|
|
55
|
-
opts.environmentId,
|
|
56
|
-
'--cma-token',
|
|
57
|
-
opts.cmaToken,
|
|
58
|
-
'--yes',
|
|
59
|
-
];
|
|
60
|
-
if (opts.host) {
|
|
61
|
-
args.push('--host', opts.host);
|
|
62
|
-
}
|
|
63
|
-
if (opts.allowDeletions) {
|
|
64
|
-
args.push('--allow-deletions');
|
|
65
|
-
}
|
|
66
|
-
const r = await runCli(args);
|
|
67
|
-
if (r.exitCode === 0)
|
|
68
|
-
return { ok: true };
|
|
69
|
-
return { ok: false, error: r.stderr.trim() || r.stdout.trim() || `exit ${r.exitCode}` };
|
|
70
|
-
}
|
|
71
|
-
/** Internal test surface. Not part of the public API. */
|
|
72
|
-
export const __testing = { findCliPath };
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Push-from-picker launcher. When the operator selects "Push" from the
|
|
3
|
-
* interactive run-picker, we mount the wizard with seeded session IDs and
|
|
4
|
-
* `initialStep: 'push-from-picker'` so they see the same preview + push UX
|
|
5
|
-
* as a fresh `experiences import` (preview → diff review → pushing progress
|
|
6
|
-
* bars → done with view URL).
|
|
7
|
-
*
|
|
8
|
-
* This is deliberately parallel to `modify-launcher.ts`. The `--push-from-run`
|
|
9
|
-
* CLI flag path (headless shell-out via `replayRun`) is preserved for
|
|
10
|
-
* scripted / non-TTY use.
|
|
11
|
-
*/
|
|
12
|
-
export async function launchPushWizard(input) {
|
|
13
|
-
const { render } = await import('ink');
|
|
14
|
-
const { createElement } = await import('react');
|
|
15
|
-
const { WizardApp } = await import('../import/tui/WizardApp.js');
|
|
16
|
-
const props = {
|
|
17
|
-
initialProjectPath: input.projectPath,
|
|
18
|
-
seedExtractSessionId: input.extractSessionId,
|
|
19
|
-
initialStep: 'push-from-picker',
|
|
20
|
-
};
|
|
21
|
-
if (input.generateSessionId)
|
|
22
|
-
props.seedGenerateSessionId = input.generateSessionId;
|
|
23
|
-
if (input.tokenSessionId)
|
|
24
|
-
props.seedTokenSessionId = input.tokenSessionId;
|
|
25
|
-
if (input.tokensPath)
|
|
26
|
-
props.seedTokensPath = input.tokensPath;
|
|
27
|
-
if (input.initialSpaceId)
|
|
28
|
-
props.initialSpaceId = input.initialSpaceId;
|
|
29
|
-
if (input.initialEnvironmentId)
|
|
30
|
-
props.initialEnvironmentId = input.initialEnvironmentId;
|
|
31
|
-
if (input.initialHost)
|
|
32
|
-
props.initialHost = input.initialHost;
|
|
33
|
-
if (input.initialCmaToken)
|
|
34
|
-
props.initialCmaToken = input.initialCmaToken;
|
|
35
|
-
const { waitUntilExit } = render(createElement(WizardApp, props));
|
|
36
|
-
await waitUntilExit();
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Interactive picker-Push entry point. Resolves the run record, applies the
|
|
40
|
-
* staleness gate, layers credentials (flag → pushedTo → credentials.json),
|
|
41
|
-
* and mounts the wizard via `launchPushWizard`.
|
|
42
|
-
*/
|
|
43
|
-
export async function pickerPushRun(opts) {
|
|
44
|
-
const { resolveRunTarget } = await import('./resolve-run-target.js');
|
|
45
|
-
const { readExperiencesCredentials } = await import('../credentials-store.js');
|
|
46
|
-
const { checkRunStaleness, formatStalenessDetail } = await import('./staleness.js');
|
|
47
|
-
const run = await resolveRunTarget(opts.runIdOrPath);
|
|
48
|
-
if (!opts.force) {
|
|
49
|
-
const staleness = await checkRunStaleness(run);
|
|
50
|
-
if (staleness.stale) {
|
|
51
|
-
const detail = formatStalenessDetail(staleness);
|
|
52
|
-
throw new Error([
|
|
53
|
-
`Refusing to push run ${run.id} — source or saved files have drifted since the run was recorded.`,
|
|
54
|
-
...detail,
|
|
55
|
-
'',
|
|
56
|
-
'Re-extract with `experiences import --project <path>` for a fresh run, or pass --force to bypass.',
|
|
57
|
-
].join('\n'));
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
const stored = await readExperiencesCredentials();
|
|
61
|
-
const spaceId = opts.spaceId || run.pushedTo?.spaceId || stored.spaceId || '';
|
|
62
|
-
const environmentId = opts.environmentId || run.pushedTo?.environmentId || stored.environmentId || '';
|
|
63
|
-
const cmaToken = opts.cmaToken || stored.cmaToken || '';
|
|
64
|
-
const host = opts.host || run.pushedTo?.host || stored.host || '';
|
|
65
|
-
await launchPushWizard({
|
|
66
|
-
extractSessionId: run.extractSessionId,
|
|
67
|
-
generateSessionId: run.generateSessionId,
|
|
68
|
-
tokenSessionId: run.tokenSessionId,
|
|
69
|
-
projectPath: run.projectPath,
|
|
70
|
-
savePath: run.savePath,
|
|
71
|
-
tokensPath: run.tokensPath,
|
|
72
|
-
...(spaceId ? { initialSpaceId: spaceId } : {}),
|
|
73
|
-
...(environmentId ? { initialEnvironmentId: environmentId } : {}),
|
|
74
|
-
...(host ? { initialHost: host } : {}),
|
|
75
|
-
...(cmaToken ? { initialCmaToken: cmaToken } : {}),
|
|
76
|
-
});
|
|
77
|
-
}
|