@contentful/experience-design-system-cli 2.32.1-dev-build-b78fe18.0 → 2.32.1-dev-build-d28a6f8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +1 -1
- package/dist/src/helpers/build-contentful-management-client.d.ts +7 -0
- package/dist/src/helpers/fetch-and-persist-existing-contentful-entities.d.ts +29 -0
- package/dist/src/helpers/fetch-existing-contentful-entities.d.ts +11 -0
- package/dist/src/helpers/find-nearly-matching-component.d.ts +7 -0
- package/dist/src/helpers/read-existing-contentful-entities-from-session.d.ts +7 -0
- package/dist/src/helpers/summarize-existing-contentful-entities.d.ts +50 -0
- package/dist/src/import/orchestrator.d.ts +0 -1
- package/dist/src/import/tui/WizardApp.d.ts +3 -0
- package/dist/src/index.js +826 -445
- package/dist/src/session/cache-keys.d.ts +1 -1
- package/dist/src/session/core/cdf/server-type-map.d.ts +3 -0
- package/dist/src/session/core/components/component-id.d.ts +1 -0
- package/dist/src/session/core/components/input-hash.d.ts +5 -0
- package/dist/src/session/core/shared/group-by.d.ts +1 -0
- package/dist/src/session/core/tokens/input-hash.d.ts +1 -0
- package/dist/src/session/db.d.ts +9 -13
- package/dist/src/session/repositories/sessions/read.d.ts +11 -0
- package/dist/src/session/repositories/sessions/write.d.ts +3 -0
- package/dist/src/session/repositories/steps/read.d.ts +2 -0
- package/dist/src/session/repositories/steps/write.d.ts +5 -0
- package/dist/src/session/services/session-resolver.d.ts +21 -0
- package/package.json +6 -6
- package/skills/generate-components.md +27 -0
- package/skills/map-tokens.md +12 -0
- package/skills/select-components.md +11 -0
- package/dist/src/helpers/cma-client.d.ts +0 -17
- package/dist/src/helpers/fetch-existing-entities.d.ts +0 -16
- /package/dist/src/session/{command.d.ts → cli.d.ts} +0 -0
|
@@ -19,4 +19,4 @@ export declare function hashFile(filePath: string): Promise<string>;
|
|
|
19
19
|
* @param model — resolved model for this run (undefined resolves to the agent's default)
|
|
20
20
|
* @param skillPathOverride — optional absolute/relative path to a custom prompt
|
|
21
21
|
*/
|
|
22
|
-
export declare function hashPromptForSkill(skill: Skill, agent: string, model: string | undefined, skillPathOverride?: string): Promise<string>;
|
|
22
|
+
export declare function hashPromptForSkill(skill: Skill, agent: string, model: string | undefined, skillPathOverride?: string, extraInputs?: string[]): Promise<string>;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type CdfCategory = 'content' | 'design' | 'state';
|
|
2
|
+
export declare function mapServerTypeToCdfType(serverType: string): string;
|
|
3
|
+
export declare function resolveCdfCategory(serverCategory: string | null | undefined, propName: string, contentProps: Set<string>, designProps: Set<string>): CdfCategory;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function deriveComponentId(name: string, source: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function groupBy<T>(items: T[], key: (item: T) => string): Map<string, T[]>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function computeTokenInputHash(rawTokenContent: string): string;
|
package/dist/src/session/db.d.ts
CHANGED
|
@@ -4,6 +4,12 @@ import type { CDFComponentEntry, DTCGTokenEntry, DTCGTokenGroup } from '@content
|
|
|
4
4
|
import type { ToolCall, TokenToolCall, ComponentSourceRef } from '@contentful/experience-design-system-generation';
|
|
5
5
|
import type { ComponentTypeSummary } from '@contentful/experience-design-system-types';
|
|
6
6
|
import type { SlotCycle, SlotEdge } from '../analyze/cycle-detection.js';
|
|
7
|
+
import { type MatchHints as SessionMatchHints } from './repositories/sessions/read.js';
|
|
8
|
+
import { type SessionResolution } from './services/session-resolver.js';
|
|
9
|
+
export { deriveComponentId } from './core/components/component-id.js';
|
|
10
|
+
export { computeComponentInputHash } from './core/components/input-hash.js';
|
|
11
|
+
export { computeTokenInputHash } from './core/tokens/input-hash.js';
|
|
12
|
+
export { mapServerTypeToCdfType, resolveCdfCategory } from './core/cdf/server-type-map.js';
|
|
7
13
|
export type StepStatus = 'pending' | 'complete' | 'failed' | 'interrupted';
|
|
8
14
|
export type CommandName = 'analyze extract' | 'analyze select' | 'generate components' | 'generate tokens' | 'generate edit' | 'apply preview' | 'apply select' | 'apply push' | 'print components' | 'print tokens' | 'map tokens' | 'fetch existing entities' | 'import';
|
|
9
15
|
export interface SessionRow {
|
|
@@ -86,17 +92,9 @@ export interface ComponentRationale {
|
|
|
86
92
|
}
|
|
87
93
|
export declare function loadComponentRationale(db: DatabaseSync, sessionId: string, componentName: string): ComponentRationale | null;
|
|
88
94
|
export declare function applyToolCalls(db: DatabaseSync, sessionId: string, componentId: string, componentName: string, calls: ToolCall[], incomingWarnings: string[]): ApplyToolCallsResult;
|
|
89
|
-
export
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
outDir?: string;
|
|
93
|
-
}
|
|
94
|
-
export interface SessionResolution {
|
|
95
|
-
sessionId: string;
|
|
96
|
-
isNew: boolean;
|
|
97
|
-
isResumed: boolean;
|
|
98
|
-
}
|
|
99
|
-
export declare function getOrCreateSession(db: DatabaseSync, sessionFlag: string | undefined, sessionName: string | undefined, _hints: MatchHints): SessionResolution;
|
|
95
|
+
export type MatchHints = SessionMatchHints;
|
|
96
|
+
export type { SessionResolution };
|
|
97
|
+
export declare function getOrCreateSession(db: DatabaseSync, sessionFlag: string | undefined, sessionName: string | undefined, hints: MatchHints): SessionResolution;
|
|
100
98
|
export declare function createStep(db: DatabaseSync, sessionId: string, command: CommandName, inputs: Record<string, string>): number;
|
|
101
99
|
export declare function updateStep(db: DatabaseSync, stepId: number, status: 'complete' | 'failed', outputs: Record<string, string>, error?: string): void;
|
|
102
100
|
export declare function storeRawComponents(db: DatabaseSync, sessionId: string, components: RawComponentDefinition[], options?: {
|
|
@@ -170,8 +168,6 @@ export interface CacheEntry {
|
|
|
170
168
|
createdAt: string;
|
|
171
169
|
updatedAt: string;
|
|
172
170
|
}
|
|
173
|
-
export declare function computeComponentInputHash(component: RawComponentWithId): string;
|
|
174
|
-
export declare function computeTokenInputHash(rawTokenContent: string): string;
|
|
175
171
|
export declare function computeMapTokensInputHash(db: DatabaseSync, sessionId: string, componentSourceRefs?: readonly ComponentSourceRef[]): string;
|
|
176
172
|
export declare function lookupCache(db: DatabaseSync, inputHash: string, entityType: CacheEntityType, entityId: string, promptHash?: string): CacheEntry | null;
|
|
177
173
|
export declare function lookupCacheByEntity(db: DatabaseSync, entityType: CacheEntityType, entityId: string): CacheEntry | null;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import type { CommandName } from '../../db.js';
|
|
3
|
+
export interface MatchHints {
|
|
4
|
+
command: CommandName;
|
|
5
|
+
inputPath?: string;
|
|
6
|
+
outDir?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function findSession(db: DatabaseSync, sessionId: string): {
|
|
9
|
+
id: string;
|
|
10
|
+
} | null;
|
|
11
|
+
export declare function findLatestSessionForCommand(db: DatabaseSync, command: CommandName): string | null;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import type { CommandName } from '../../db.js';
|
|
3
|
+
export declare function markPendingStepsInterrupted(db: DatabaseSync, sessionId: string, command: CommandName, timestamp: string): void;
|
|
4
|
+
export declare function insertPendingStep(db: DatabaseSync, sessionId: string, command: CommandName, inputs: Record<string, string>, timestamp: string): number;
|
|
5
|
+
export declare function updateStepResult(db: DatabaseSync, stepId: number, status: 'complete' | 'failed', outputs: Record<string, string>, error: string | null, timestamp: string): void;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import type { CommandName } from '../db.js';
|
|
3
|
+
export interface MatchHints {
|
|
4
|
+
command: CommandName;
|
|
5
|
+
inputPath?: string;
|
|
6
|
+
outDir?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface SessionResolution {
|
|
9
|
+
sessionId: string;
|
|
10
|
+
isNew: boolean;
|
|
11
|
+
isResumed: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Resolve which session the caller should operate on:
|
|
15
|
+
* - `sessionFlag === 'new'` or undefined → create a new session
|
|
16
|
+
* - explicit id → verify it exists and reuse it (throws if missing)
|
|
17
|
+
*
|
|
18
|
+
* `MatchHints` is accepted for signature stability (callers pass it today) but
|
|
19
|
+
* is not currently used — hint-based session resumption was removed upstream.
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveSession(db: DatabaseSync, sessionFlag: string | undefined, sessionName: string | undefined, _hints: MatchHints): SessionResolution;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentful/experience-design-system-cli",
|
|
3
|
-
"version": "2.32.1-dev-build-
|
|
3
|
+
"version": "2.32.1-dev-build-d28a6f8.0",
|
|
4
4
|
"description": "Contentful Experiences design system import CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"svelte": "^5.56.4",
|
|
41
41
|
"ts-morph": "^27.0.2",
|
|
42
42
|
"typescript": "^5.9.3",
|
|
43
|
-
"@contentful/experience-design-system-cli-v2": "2.32.1-dev-build-
|
|
44
|
-
"@contentful/experience-design-system-types": "2.32.1-dev-build-
|
|
43
|
+
"@contentful/experience-design-system-cli-v2": "2.32.1-dev-build-d28a6f8.0",
|
|
44
|
+
"@contentful/experience-design-system-types": "2.32.1-dev-build-d28a6f8.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@tsconfig/node24": "^24.0.4",
|
|
@@ -53,9 +53,9 @@
|
|
|
53
53
|
"ink-testing-library": "^4.0.0",
|
|
54
54
|
"typescript-eslint": "^8.67.0",
|
|
55
55
|
"vitest": "^4.0.16",
|
|
56
|
-
"@contentful/experience-design-system-
|
|
57
|
-
"@contentful/experience-design-system-generation": "2.32.1-dev-build-
|
|
58
|
-
"@contentful/experience-design-system-
|
|
56
|
+
"@contentful/experience-design-system-client": "2.32.1-dev-build-d28a6f8.0",
|
|
57
|
+
"@contentful/experience-design-system-generation": "2.32.1-dev-build-d28a6f8.0",
|
|
58
|
+
"@contentful/experience-design-system-extraction": "2.32.1-dev-build-d28a6f8.0"
|
|
59
59
|
},
|
|
60
60
|
"repository": {
|
|
61
61
|
"type": "git",
|
|
@@ -549,3 +549,30 @@ If you are genuinely uncertain about every prop, classify each as:
|
|
|
549
549
|
An imperfect classification is infinitely better than no classification. That is
|
|
550
550
|
about **classifying a prop rather than dropping it** — it is not a licence to
|
|
551
551
|
invent a `values` list. The uncertain answer is `cdf_type: "string"`, every time.
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
## Existing entities in the target space
|
|
556
|
+
|
|
557
|
+
The preamble may include an "Existing components in the target Contentful space" JSON block with a `likelyMatch` (a fuzzy-matched space component that likely corresponds to the codebase component you're classifying), an `otherComponents` list, and a rolled-up token summary. Use it to align your classifications with what the customer already has.
|
|
558
|
+
|
|
559
|
+
### When `likelyMatch` is present — align rename intent + categories + slot names
|
|
560
|
+
|
|
561
|
+
Your goal is **consistency**: the customer will see the diff between what you propose and what already exists, and every unnecessary category flip or slot-shape mismatch becomes review friction.
|
|
562
|
+
|
|
563
|
+
1. **Prop names**: `classify_prop.prop` MUST always be the codebase prop name — that's the DB lookup key. When a codebase prop looks like it corresponds to an existing space prop (e.g. codebase `kind` ↔ space `variant`, codebase `text` ↔ space `label`), keep `prop` as the codebase name and put the alignment note in `reason`, e.g. `"looks like existing space prop 'variant' — customer may want to reconcile at review"`. Never rewrite `prop` itself; reconciliation happens downstream, not in this tool call.
|
|
564
|
+
2. **Categories**: match the space's category (`design` / `content`) for equivalent props, even if you'd normally categorize differently. Note the alignment in `reason`.
|
|
565
|
+
3. **Slot names**: match slot IDs / names when the shape is equivalent.
|
|
566
|
+
4. **Enum values**: never invent new values to bridge a mismatch. If the codebase's enum diverges from the space's, classify against your best-effort mapping and cite the divergence in `reason` — this is a signal for human review, not a green light to rewrite the space's enum.
|
|
567
|
+
5. **Never realign silently.** Every classification influenced by the `likelyMatch` MUST cite it in `reason`.
|
|
568
|
+
|
|
569
|
+
### When only `otherComponents` is present (no direct match)
|
|
570
|
+
|
|
571
|
+
Use the list to constrain slot `allowed_components` — do not propose a slot that accepts component types the space doesn't have.
|
|
572
|
+
|
|
573
|
+
### Token binding
|
|
574
|
+
|
|
575
|
+
The preamble's "Existing design tokens" section lists tokens (by name + DTCG type) already in the space.
|
|
576
|
+
|
|
577
|
+
1. When classifying a `design`-category, `token`-typed prop, prefer binding to an existing token name over inventing a new one. Cite the target token in `reason`.
|
|
578
|
+
2. If no existing token semantically matches, proceed with the current rules — propose a new token. The diff surfaces this for review.
|
package/skills/map-tokens.md
CHANGED
|
@@ -88,3 +88,15 @@ Before emitting any tool calls, verify:
|
|
|
88
88
|
3. `token_allowed` is never empty.
|
|
89
89
|
4. Every emitted list includes the prop's own default token when it has one.
|
|
90
90
|
5. No list was emitted on the strength of a default alone, and none targets a prop whose type is a union of variant names.
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Existing entities in the target space
|
|
95
|
+
|
|
96
|
+
The preamble may include an "Existing design tokens in the target Contentful space" JSON block listing tokens already present in the target space (by name + DTCG type).
|
|
97
|
+
|
|
98
|
+
Prefer restricting to existing tokens over proposing new ones:
|
|
99
|
+
|
|
100
|
+
1. When the source has restriction evidence AND a candidate maps semantically to an existing token by name/type, favor the existing token in the emitted `token_allowed` list.
|
|
101
|
+
2. Never emit a `token_allowed` entry that contradicts the "path exists verbatim" rule above — the existing-tokens block is guidance, not a substitute for the token path index. If a token appears in the existing-entities list but not in the token path index, do not use it.
|
|
102
|
+
3. If none of the existing tokens fit and the source's evidence is specific, proceed as usual — the diff will surface the new proposal.
|
|
@@ -222,3 +222,14 @@ TextImageCard — card with rich text and background image
|
|
|
222
222
|
SearchInput — search field with dropdown
|
|
223
223
|
{"tool":"select_component","name":"SearchInput","reason":"search UI — configurable placeholder and state"}
|
|
224
224
|
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Existing entities in the target space
|
|
229
|
+
|
|
230
|
+
The preamble may include an "Existing components in the target Contentful space" JSON block and a rolled-up token summary. Use them as **signal, not as a filter**. Rules:
|
|
231
|
+
|
|
232
|
+
1. Never let a name overlap force a decision. Acceptance is still driven purely by "does the codebase component render visible, authorable UI?" — a name match does not auto-accept, and a name conflict does not auto-reject.
|
|
233
|
+
2. When a codebase component appears to correspond to an existing space component (name overlap, semantic overlap in the description), note it in your `reason` — e.g. `"accepted; likely maps to existing space component 'Button'"`. This surfaces the mapping for downstream review.
|
|
234
|
+
3. When the space is mature (many existing components, dozens of tokens) and the codebase has thin wrappers with no visible UI difference, lean harder toward rejecting the wrappers. Extra noise in a mature space is more costly than in an empty one.
|
|
235
|
+
4. When no overlap exists, the acceptance decision is unchanged from the rules above.
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { type PlainClientAPI } from 'contentful-management';
|
|
2
|
-
interface CreateCmaClientOptions {
|
|
3
|
-
cmaToken: string;
|
|
4
|
-
/**
|
|
5
|
-
* Optional CMA host override. Accepts either a full URL
|
|
6
|
-
* (`https://api.contentful.com`) or a bare hostname (`api.contentful.com`);
|
|
7
|
-
* contentful-management wants the bare form so we normalize here.
|
|
8
|
-
*/
|
|
9
|
-
host?: string;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Build a plain contentful-management client. Single place that picks the
|
|
13
|
-
* `{ type: 'plain' }` overload so callers never have to think about it,
|
|
14
|
-
* and normalizes host into the bare-hostname shape the SDK expects.
|
|
15
|
-
*/
|
|
16
|
-
export declare function createCmaClient(opts: CreateCmaClientOptions): PlainClientAPI;
|
|
17
|
-
export {};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { type ComponentProps, type DesignTokenProps, type PlainClientAPI } from 'contentful-management';
|
|
2
|
-
export interface ExistingEntities {
|
|
3
|
-
components: ComponentProps[];
|
|
4
|
-
tokens: DesignTokenProps[];
|
|
5
|
-
}
|
|
6
|
-
interface FetchExistingEntitiesParams {
|
|
7
|
-
spaceId: string;
|
|
8
|
-
environmentId: string;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Fetch all existing Components + DesignTokens for a space+env. Pagination
|
|
12
|
-
* is delegated to the SDK's `fetchAll()` helper. Caller supplies the
|
|
13
|
-
* pre-built plain client (see `createCmaClient()`).
|
|
14
|
-
*/
|
|
15
|
-
export declare function fetchExistingEntities(client: PlainClientAPI, params: FetchExistingEntitiesParams): Promise<ExistingEntities>;
|
|
16
|
-
export {};
|
|
File without changes
|