mirror of
https://github.com/bergside/typeui.git
synced 2026-09-19 07:24:37 +08:00
update: remove redundant commands and component families
This commit is contained in:
@@ -42,16 +42,6 @@ One paragraph describing the system objective and target product experience.
|
||||
- Spacing scale: [token list]
|
||||
- Radius/shadow/motion tokens: [if applicable]
|
||||
|
||||
## Component Families
|
||||
- buttons
|
||||
- inputs
|
||||
- forms
|
||||
- navigation
|
||||
- overlays
|
||||
- feedback
|
||||
- data display
|
||||
- etc.
|
||||
|
||||
## Accessibility
|
||||
- Target: WCAG 2.2 AA
|
||||
- Keyboard-first interactions required
|
||||
@@ -107,7 +97,6 @@ concise, confident, implementation-focused
|
||||
- `[brand-or-scope]` in `name`
|
||||
- System name and mission
|
||||
- Token values (typography, colors, spacing, motion)
|
||||
- Component family list based on product scope
|
||||
- Any framework-specific implementation notes
|
||||
|
||||
## Optional Extensions
|
||||
@@ -31,9 +31,6 @@ Check out all [design systems](https://typeui.sh/design-skills) that can be pull
|
||||
| `update` | Update existing managed skill content in generated files. |
|
||||
| `pull <slug>` | Pull a registry skill from `bergside/awesome-design-skills` and write it to selected provider paths. |
|
||||
| `list` | Show available registry specs from `bergside/awesome-design-skills` (with typeui.sh preview links), then pull one automatically. |
|
||||
| `verify` | Verify your license key (pro version) and cache local license status. |
|
||||
| `license` | Show local cached license status. |
|
||||
| `clear-cache` | Remove local cache state (`~/.typeui-sh`). |
|
||||
|
||||
Shared options for `generate` and `update`:
|
||||
|
||||
@@ -50,6 +47,31 @@ Shared options for `list`:
|
||||
- `-p, --providers <providers>` (comma-separated providers passed through to auto-pull)
|
||||
- `--dry-run` (preview pull file changes without writing)
|
||||
|
||||
## Design Skill File Structure
|
||||
|
||||
Generated files include YAML frontmatter plus a managed content block between:
|
||||
|
||||
- `<!-- TYPEUI_SH_MANAGED_START -->`
|
||||
- `<!-- TYPEUI_SH_MANAGED_END -->`
|
||||
|
||||
Within the managed block, sections are structured like this:
|
||||
|
||||
| Section | What it does |
|
||||
| --- | --- |
|
||||
| `Mission` | Defines the design-system objective and expected output quality for the agent. |
|
||||
| `Brand` | Captures product context and brand direction to anchor decisions. |
|
||||
| `Style Foundations` | Defines core visual tokens and constraints (visual style, typography, color palette, spacing). |
|
||||
| `Accessibility` | States accessibility standards and non-negotiable requirements. |
|
||||
| `Writing Tone` | Sets tone/style for generated guidance language. |
|
||||
| `Rules: Do` | Lists required implementation practices to follow. |
|
||||
| `Rules: Don't` | Lists anti-patterns and prohibited behaviors. |
|
||||
| `Expected Behavior` | Sets expectations for decision-making and trade-off handling. |
|
||||
| `Guideline Authoring Workflow` | Gives the ordered process the agent should follow when producing guidelines. |
|
||||
| `Required Output Structure` | Enforces the final response format for consistency and completeness. |
|
||||
| `Component Rule Expectations` | Defines required interaction/state details in component guidance. |
|
||||
| `Quality Gates` | Adds validation criteria for clarity, testability, and consistency. |
|
||||
| `Example Constraint Language` | Standardizes wording strength (`must` vs `should`) and constraint style. |
|
||||
|
||||
For local development:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -37,12 +37,6 @@ Use `typeui.sh` to generate, update, list, and pull design-system skill files fo
|
||||
- Pull a specific registry skill and write it to selected provider paths.
|
||||
- `npx typeui.sh list`
|
||||
- List available registry slugs, show preview links, and pull one selection.
|
||||
- `npx typeui.sh verify`
|
||||
- Verify and cache license state for license-aware workflows.
|
||||
- `npx typeui.sh license`
|
||||
- Show local cached license summary.
|
||||
- `npx typeui.sh clear-cache`
|
||||
- Clear local `~/.typeui-sh` cache state.
|
||||
|
||||
## Local Dev Invocation (This Repo)
|
||||
|
||||
|
||||
-28
@@ -1,11 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
import path from "node:path";
|
||||
import { Command } from "commander";
|
||||
import {
|
||||
clearCachedLicenseState,
|
||||
getCachedLicenseSummary,
|
||||
verifyAndCacheLicenseFromPrompt
|
||||
} from "./licensing/licenseService";
|
||||
import {
|
||||
promptDesignSystem,
|
||||
promptDesignSystemFields,
|
||||
@@ -184,29 +179,6 @@ program
|
||||
await listLike(options);
|
||||
});
|
||||
|
||||
program
|
||||
.command("verify")
|
||||
.description("Verify your license key and cache local license status.")
|
||||
.action(async () => {
|
||||
const record = await verifyAndCacheLicenseFromPrompt();
|
||||
console.log(`License cached (${record.licenseKeyFingerprint}) until ${record.expiresAt}`);
|
||||
});
|
||||
|
||||
program
|
||||
.command("license")
|
||||
.description("Show local cached license status.")
|
||||
.action(async () => {
|
||||
console.log(await getCachedLicenseSummary());
|
||||
});
|
||||
|
||||
program
|
||||
.command("clear-cache")
|
||||
.description("Clear all local typeui.sh cache state.")
|
||||
.action(async () => {
|
||||
await clearCachedLicenseState();
|
||||
console.log("Cleared local cache state.");
|
||||
});
|
||||
|
||||
program.parseAsync().catch((error: unknown) => {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
console.error(`typeui.sh error: ${message}`);
|
||||
|
||||
@@ -1,24 +1,11 @@
|
||||
import path from "node:path";
|
||||
import os from "node:os";
|
||||
|
||||
export const PRODUCT_ID = "typeui.sh";
|
||||
export const MANAGED_BLOCK_START = "<!-- TYPEUI_SH_MANAGED_START -->";
|
||||
export const MANAGED_BLOCK_END = "<!-- TYPEUI_SH_MANAGED_END -->";
|
||||
export const API_DOMAIN = "https://www.typeui.sh";
|
||||
export const GITHUB_REGISTRY_REPO_URL = "https://github.com/bergside/awesome-design-skills";
|
||||
export const GITHUB_REGISTRY_RAW_BASE_URL =
|
||||
"https://raw.githubusercontent.com/bergside/awesome-design-skills/main";
|
||||
export const PRICING_URL = "https://www.typeui.sh/#pricing";
|
||||
export const POLAR_VERIFY_URL = `${API_DOMAIN}/api/license/verify`;
|
||||
export const REGISTRY_SPECS_URL = `${GITHUB_REGISTRY_RAW_BASE_URL}/skills/index.json`;
|
||||
|
||||
export const LICENSE_CACHE_DIR = path.join(os.homedir(), ".typeui-sh");
|
||||
export const LICENSE_CACHE_PATH = path.join(LICENSE_CACHE_DIR, "license.json");
|
||||
|
||||
export function getPolarVerifyUrl(): string {
|
||||
return POLAR_VERIFY_URL;
|
||||
}
|
||||
|
||||
export function getRegistryPullUrl(skillPath: string): string {
|
||||
const encodedPath = skillPath
|
||||
.split("/")
|
||||
|
||||
@@ -28,7 +28,6 @@ export const DesignSystemSchema = z.object({
|
||||
typographyScale: z.string().min(3),
|
||||
colorPalette: z.string().min(3),
|
||||
spacingScale: z.string().min(3),
|
||||
componentFamilies: z.array(z.string().min(1)).min(1),
|
||||
accessibilityRequirements: z.string().min(3),
|
||||
writingTone: z.string().min(3),
|
||||
doRules: z.array(z.string().min(1)).min(1),
|
||||
@@ -60,7 +59,6 @@ export const FlatDesignSystemPromptSchema = z.object({
|
||||
typographyScale: z.string().min(3),
|
||||
colorPalette: z.string().min(3),
|
||||
spacingScale: z.string().min(3),
|
||||
componentFamilies: nonEmptyList,
|
||||
accessibilityRequirements: z.string().min(3),
|
||||
writingTone: z.string().min(3),
|
||||
doRules: nonEmptyList,
|
||||
|
||||
@@ -78,7 +78,6 @@ export function parseManagedDesignSystem(content: string): DesignSystemInput | n
|
||||
const typographyScale = extractStyleValue(managed, "Typography scale");
|
||||
const colorPalette = extractStyleValue(managed, "Color palette");
|
||||
const spacingScale = extractStyleValue(managed, "Spacing scale");
|
||||
const componentFamilies = extractListSection(managed, "## Component Families", "## Accessibility");
|
||||
const accessibilityRequirements = extractSection(managed, "## Accessibility", "## Writing Tone");
|
||||
const writingTone = extractSection(managed, "## Writing Tone", "## Rules: Do");
|
||||
const doRules = extractListSection(managed, "## Rules: Do", "## Rules: Don't");
|
||||
@@ -91,7 +90,6 @@ export function parseManagedDesignSystem(content: string): DesignSystemInput | n
|
||||
!typographyScale ||
|
||||
!colorPalette ||
|
||||
!spacingScale ||
|
||||
!componentFamilies ||
|
||||
!accessibilityRequirements ||
|
||||
!writingTone ||
|
||||
!doRules ||
|
||||
@@ -107,7 +105,6 @@ export function parseManagedDesignSystem(content: string): DesignSystemInput | n
|
||||
typographyScale,
|
||||
colorPalette,
|
||||
spacingScale,
|
||||
componentFamilies,
|
||||
accessibilityRequirements,
|
||||
writingTone,
|
||||
doRules,
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import crypto from "node:crypto";
|
||||
import fs from "node:fs/promises";
|
||||
import { LICENSE_CACHE_DIR, LICENSE_CACHE_PATH, PRODUCT_ID } from "../config";
|
||||
import { LicenseCacheRecord } from "../types";
|
||||
|
||||
export async function readLicenseCache(): Promise<LicenseCacheRecord | null> {
|
||||
try {
|
||||
const raw = await fs.readFile(LICENSE_CACHE_PATH, "utf8");
|
||||
const parsed = JSON.parse(raw) as Partial<LicenseCacheRecord>;
|
||||
if (!parsed.productId || !parsed.expiresAt || !parsed.licenseKeyFingerprint) {
|
||||
return null;
|
||||
}
|
||||
if (parsed.productId !== PRODUCT_ID) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
productId: parsed.productId,
|
||||
verifiedAt: parsed.verifiedAt ?? new Date().toISOString(),
|
||||
expiresAt: parsed.expiresAt,
|
||||
licenseKeyFingerprint: parsed.licenseKeyFingerprint,
|
||||
licenseKey: typeof parsed.licenseKey === "string" ? parsed.licenseKey : undefined
|
||||
};
|
||||
} catch (error) {
|
||||
const e = error as NodeJS.ErrnoException;
|
||||
if (e.code === "ENOENT") {
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
export async function writeLicenseCache(record: LicenseCacheRecord): Promise<void> {
|
||||
await fs.mkdir(LICENSE_CACHE_DIR, { recursive: true });
|
||||
await fs.writeFile(LICENSE_CACHE_PATH, JSON.stringify(record, null, 2), "utf8");
|
||||
}
|
||||
|
||||
export function isCacheRecordValid(record: LicenseCacheRecord): boolean {
|
||||
const expires = new Date(record.expiresAt).getTime();
|
||||
return Number.isFinite(expires) && expires > Date.now();
|
||||
}
|
||||
|
||||
export function fingerprintToken(token: string): string {
|
||||
return crypto.createHash("sha256").update(token).digest("hex").slice(0, 16);
|
||||
}
|
||||
|
||||
export async function clearLocalLicenseState(): Promise<void> {
|
||||
await fs.rm(LICENSE_CACHE_DIR, { recursive: true, force: true });
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
import { PRICING_URL, PRODUCT_ID } from "../config";
|
||||
import { promptLicenseCredentials } from "../prompts/license";
|
||||
import { LicenseCacheRecord } from "../types";
|
||||
import {
|
||||
clearLocalLicenseState,
|
||||
fingerprintToken,
|
||||
isCacheRecordValid,
|
||||
readLicenseCache,
|
||||
writeLicenseCache
|
||||
} from "./licenseCache";
|
||||
import { verifyPurchaseWithPolar } from "./polarClient";
|
||||
|
||||
function buildCacheRecord(licenseKey: string, expiresAt: string): LicenseCacheRecord {
|
||||
return {
|
||||
productId: PRODUCT_ID,
|
||||
verifiedAt: new Date().toISOString(),
|
||||
expiresAt,
|
||||
licenseKeyFingerprint: fingerprintToken(licenseKey),
|
||||
licenseKey
|
||||
};
|
||||
}
|
||||
|
||||
function isInvalidLicenseReason(reason: string): boolean {
|
||||
const normalized = reason.toLowerCase();
|
||||
return (
|
||||
normalized === "not_found" ||
|
||||
normalized.includes("license_invalid") ||
|
||||
normalized.includes("license key is not valid") ||
|
||||
normalized.includes("invalid license")
|
||||
);
|
||||
}
|
||||
|
||||
function withLicensePurchaseHelp(reason: string): string {
|
||||
if (!isInvalidLicenseReason(reason)) {
|
||||
return reason;
|
||||
}
|
||||
return `${reason} You can get a license key at ${PRICING_URL}.`;
|
||||
}
|
||||
|
||||
export async function ensureVerifiedAccess(): Promise<void> {
|
||||
const cached = await readLicenseCache();
|
||||
if (cached && isCacheRecordValid(cached)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { licenseKey } = await promptLicenseCredentials();
|
||||
const verifyResult = await verifyPurchaseWithPolar(licenseKey);
|
||||
|
||||
if (!verifyResult.ok) {
|
||||
throw new Error(`License verification failed: ${withLicensePurchaseHelp(verifyResult.reason)}`);
|
||||
}
|
||||
|
||||
await writeLicenseCache(buildCacheRecord(licenseKey, verifyResult.expiresAt));
|
||||
}
|
||||
|
||||
export async function getVerifiedLicenseKey(): Promise<string> {
|
||||
const cached = await readLicenseCache();
|
||||
if (cached && isCacheRecordValid(cached) && cached.licenseKey) {
|
||||
return cached.licenseKey;
|
||||
}
|
||||
|
||||
const { licenseKey } = await promptLicenseCredentials();
|
||||
const verifyResult = await verifyPurchaseWithPolar(licenseKey);
|
||||
|
||||
if (!verifyResult.ok) {
|
||||
throw new Error(`License verification failed: ${withLicensePurchaseHelp(verifyResult.reason)}`);
|
||||
}
|
||||
|
||||
await writeLicenseCache(buildCacheRecord(licenseKey, verifyResult.expiresAt));
|
||||
return licenseKey;
|
||||
}
|
||||
|
||||
export async function verifyAndCacheLicenseFromPrompt(): Promise<LicenseCacheRecord> {
|
||||
const { licenseKey } = await promptLicenseCredentials();
|
||||
const verifyResult = await verifyPurchaseWithPolar(licenseKey);
|
||||
|
||||
if (!verifyResult.ok) {
|
||||
throw new Error(`License verification failed: ${withLicensePurchaseHelp(verifyResult.reason)}`);
|
||||
}
|
||||
|
||||
const cacheRecord = buildCacheRecord(licenseKey, verifyResult.expiresAt);
|
||||
await writeLicenseCache(cacheRecord);
|
||||
return cacheRecord;
|
||||
}
|
||||
|
||||
export async function getCachedLicenseSummary(): Promise<string> {
|
||||
const cached = await readLicenseCache();
|
||||
if (!cached) {
|
||||
return "No cached license.";
|
||||
}
|
||||
const status = isCacheRecordValid(cached) ? "valid" : "expired";
|
||||
return `Cached license (${cached.licenseKeyFingerprint}) is ${status} until ${cached.expiresAt}.`;
|
||||
}
|
||||
|
||||
export async function clearCachedLicenseState(): Promise<void> {
|
||||
await clearLocalLicenseState();
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
import { getPolarVerifyUrl } from "../config";
|
||||
|
||||
export interface PolarVerifySuccess {
|
||||
ok: true;
|
||||
expiresAt: string;
|
||||
}
|
||||
|
||||
export interface PolarVerifyFailure {
|
||||
ok: false;
|
||||
reason: string;
|
||||
}
|
||||
|
||||
export type PolarVerifyResult = PolarVerifySuccess | PolarVerifyFailure;
|
||||
|
||||
interface PolarResponseShape {
|
||||
valid?: boolean;
|
||||
reason?: string;
|
||||
status?: string;
|
||||
expires_at?: string;
|
||||
expiresAt?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
const VERIFY_CACHE_TTL_DAYS = 31;
|
||||
|
||||
export async function verifyPurchaseWithPolar(licenseKey: string): Promise<PolarVerifyResult> {
|
||||
const verifyUrl = getPolarVerifyUrl();
|
||||
let response: Response;
|
||||
try {
|
||||
response = await fetch(verifyUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
licenseKey
|
||||
})
|
||||
});
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
return {
|
||||
ok: false,
|
||||
reason: `Could not reach license server at ${verifyUrl}: ${message}. Please ensure your network connection is available and try again.`
|
||||
};
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
let serverReason: string | undefined;
|
||||
try {
|
||||
const errorData = (await response.json()) as PolarResponseShape;
|
||||
serverReason = errorData.reason || errorData.error;
|
||||
} catch {
|
||||
// Ignore JSON parse failures and fall back to status-only message.
|
||||
}
|
||||
return {
|
||||
ok: false,
|
||||
reason: serverReason
|
||||
? `License verification failed (${response.status}): ${serverReason}.`
|
||||
: `License verification failed (${response.status}).`
|
||||
};
|
||||
}
|
||||
|
||||
const data = (await response.json()) as PolarResponseShape;
|
||||
if (!data.valid || data.reason !== "active" || data.status !== "granted") {
|
||||
return { ok: false, reason: data.reason || data.error || "License key is not valid." };
|
||||
}
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
// Local cache is fixed to 31 days from verification.
|
||||
expiresAt: new Date(Date.now() + VERIFY_CACHE_TTL_DAYS * 24 * 60 * 60 * 1000).toISOString()
|
||||
};
|
||||
}
|
||||
@@ -52,7 +52,6 @@ const designFieldChoices: { name: string; value: DesignSystemField }[] = [
|
||||
{ name: "Typography scale", value: "typographyScale" },
|
||||
{ name: "Color palette", value: "colorPalette" },
|
||||
{ name: "Spacing scale", value: "spacingScale" },
|
||||
{ name: "Component families", value: "componentFamilies" },
|
||||
{ name: "Accessibility requirements", value: "accessibilityRequirements" },
|
||||
{ name: "Writing tone", value: "writingTone" },
|
||||
{ name: "DO rules", value: "doRules" },
|
||||
@@ -344,52 +343,6 @@ const SPACING_SCALE_OPTIONS = [
|
||||
"comfortable density mode"
|
||||
];
|
||||
|
||||
const COMPONENT_FAMILY_OPTIONS = [
|
||||
"buttons",
|
||||
"inputs",
|
||||
"forms",
|
||||
"selects/comboboxes",
|
||||
"checkboxes/radios/switches",
|
||||
"textareas",
|
||||
"date/time pickers",
|
||||
"file uploaders",
|
||||
"cards",
|
||||
"tables",
|
||||
"data lists",
|
||||
"data grids",
|
||||
"charts",
|
||||
"stats/metrics",
|
||||
"badges/chips",
|
||||
"avatars",
|
||||
"breadcrumbs",
|
||||
"pagination",
|
||||
"steppers",
|
||||
"modals",
|
||||
"drawers/sheets",
|
||||
"tooltips",
|
||||
"popovers/menus",
|
||||
"navigation",
|
||||
"sidebars",
|
||||
"top bars/headers",
|
||||
"command palette",
|
||||
"tabs",
|
||||
"accordions",
|
||||
"carousels",
|
||||
"progress indicators",
|
||||
"skeletons",
|
||||
"alerts/toasts",
|
||||
"notifications center",
|
||||
"search",
|
||||
"empty states",
|
||||
"onboarding",
|
||||
"authentication screens",
|
||||
"settings pages",
|
||||
"documentation layouts",
|
||||
"feedback components",
|
||||
"pricing blocks",
|
||||
"data visualization wrappers"
|
||||
];
|
||||
|
||||
const ACCESSIBILITY_OPTIONS = [
|
||||
"WCAG 2.2 AA",
|
||||
"keyboard-first interactions",
|
||||
@@ -597,11 +550,6 @@ export async function promptDesignSystem(defaultProductName = "typeui.sh"): Prom
|
||||
presets: SPACING_SCALE_OPTIONS,
|
||||
defaultChoice: "4/8/12/16/24/32"
|
||||
});
|
||||
const componentFamilies = await promptPresetSelection({
|
||||
message: "Select component families to prioritize:",
|
||||
presets: COMPONENT_FAMILY_OPTIONS,
|
||||
defaultSelected: COMPONENT_FAMILY_OPTIONS
|
||||
});
|
||||
const accessibilityRequirements = await promptPresetSelection({
|
||||
message: "Select accessibility requirements:",
|
||||
presets: ACCESSIBILITY_OPTIONS,
|
||||
@@ -638,7 +586,6 @@ export async function promptDesignSystem(defaultProductName = "typeui.sh"): Prom
|
||||
typographyScale,
|
||||
colorPalette,
|
||||
spacingScale,
|
||||
componentFamilies,
|
||||
accessibilityRequirements: accessibilityRequirements.join(", "),
|
||||
writingTone: writingTone.join(", "),
|
||||
doRules,
|
||||
@@ -720,16 +667,6 @@ export async function promptDesignSystemUpdates(
|
||||
updates.spacingScale = value;
|
||||
break;
|
||||
}
|
||||
case "componentFamilies": {
|
||||
const defaults = matchPresetDefaults(current.componentFamilies.join(", "), COMPONENT_FAMILY_OPTIONS);
|
||||
updates.componentFamilies = await promptPresetSelection({
|
||||
message: "Select component families to prioritize:",
|
||||
presets: COMPONENT_FAMILY_OPTIONS,
|
||||
defaultSelected: defaults.selected.length > 0 ? defaults.selected : COMPONENT_FAMILY_OPTIONS,
|
||||
defaultCustom: defaults.custom
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "accessibilityRequirements": {
|
||||
const defaults = matchPresetDefaults(current.accessibilityRequirements, ACCESSIBILITY_OPTIONS);
|
||||
const values = await promptPresetSelection({
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
type InquirerModule = typeof import("inquirer");
|
||||
|
||||
async function loadInquirer(): Promise<InquirerModule["default"]> {
|
||||
const dynamicImport = new Function(
|
||||
"specifier",
|
||||
"return import(specifier)"
|
||||
) as (specifier: string) => Promise<InquirerModule>;
|
||||
const inquirerModule = await dynamicImport("inquirer");
|
||||
return inquirerModule.default;
|
||||
}
|
||||
|
||||
async function prompt<T>(questions: unknown): Promise<T> {
|
||||
const inquirer = await loadInquirer();
|
||||
return (await inquirer.prompt(questions as never)) as T;
|
||||
}
|
||||
|
||||
export interface LicensePromptAnswers {
|
||||
licenseKey: string;
|
||||
}
|
||||
|
||||
export async function promptLicenseCredentials(): Promise<LicensePromptAnswers> {
|
||||
const answers = await prompt<LicensePromptAnswers>([
|
||||
{
|
||||
type: "password",
|
||||
name: "licenseKey",
|
||||
message: "License key:",
|
||||
mask: "*",
|
||||
validate: (value: string) => value.trim().length > 5 || "License key is required."
|
||||
}
|
||||
]);
|
||||
|
||||
return {
|
||||
licenseKey: answers.licenseKey.trim()
|
||||
};
|
||||
}
|
||||
@@ -24,9 +24,6 @@ export function createManagedSkillBody(providerTitle: string, design: DesignSyst
|
||||
`- Color palette: ${design.colorPalette}`,
|
||||
`- Spacing scale: ${design.spacingScale}`,
|
||||
"",
|
||||
"## Component Families",
|
||||
list(design.componentFamilies),
|
||||
"",
|
||||
"## Accessibility",
|
||||
design.accessibilityRequirements,
|
||||
"",
|
||||
|
||||
@@ -158,7 +158,6 @@ export interface DesignSystemInput {
|
||||
typographyScale: string;
|
||||
colorPalette: string;
|
||||
spacingScale: string;
|
||||
componentFamilies: string[];
|
||||
accessibilityRequirements: string;
|
||||
writingTone: string;
|
||||
doRules: string[];
|
||||
@@ -177,7 +176,6 @@ export const DESIGN_SYSTEM_FIELDS = [
|
||||
"typographyScale",
|
||||
"colorPalette",
|
||||
"spacingScale",
|
||||
"componentFamilies",
|
||||
"accessibilityRequirements",
|
||||
"writingTone",
|
||||
"doRules",
|
||||
@@ -191,11 +189,3 @@ export interface ProviderFile {
|
||||
relativePath: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export interface LicenseCacheRecord {
|
||||
productId: string;
|
||||
verifiedAt: string;
|
||||
expiresAt: string;
|
||||
licenseKeyFingerprint: string;
|
||||
licenseKey?: string;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ const sampleDesign: DesignSystemInput = {
|
||||
typographyScale: "12/14/16/20/24/32",
|
||||
colorPalette: "primary, neutral, semantic",
|
||||
spacingScale: "4/8/12/16/24/32",
|
||||
componentFamilies: ["buttons", "inputs", "cards"],
|
||||
accessibilityRequirements: "WCAG 2.2 AA",
|
||||
writingTone: "clear and direct",
|
||||
doRules: ["use semantic tokens", "preserve hierarchy"],
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { isCacheRecordValid } from "../src/licensing/licenseCache";
|
||||
|
||||
describe("isCacheRecordValid", () => {
|
||||
it("returns true for future expiry", () => {
|
||||
const valid = isCacheRecordValid({
|
||||
productId: "typeui.sh",
|
||||
verifiedAt: new Date().toISOString(),
|
||||
expiresAt: new Date(Date.now() + 60_000).toISOString(),
|
||||
licenseKeyFingerprint: "abcd",
|
||||
licenseKey: "license_valid_123"
|
||||
});
|
||||
expect(valid).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false for expired cache", () => {
|
||||
const valid = isCacheRecordValid({
|
||||
productId: "typeui.sh",
|
||||
verifiedAt: new Date().toISOString(),
|
||||
expiresAt: new Date(Date.now() - 60_000).toISOString(),
|
||||
licenseKeyFingerprint: "abcd"
|
||||
});
|
||||
expect(valid).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -9,7 +9,6 @@ const sampleDesign: DesignSystemInput = {
|
||||
typographyScale: "12/14/16/20/24/32",
|
||||
colorPalette: "primary, neutral, semantic",
|
||||
spacingScale: "4/8/12/16/24/32",
|
||||
componentFamilies: ["buttons", "inputs", "cards"],
|
||||
accessibilityRequirements: "WCAG 2.2 AA",
|
||||
writingTone: "clear and direct",
|
||||
doRules: ["use semantic tokens", "preserve hierarchy"],
|
||||
|
||||
Reference in New Issue
Block a user