Files
open-design/src/types.ts
T
pftom af3f96379a Refactor project name from "Open Claude Design" to "Open Design"
- Updated project name in package.json, package-lock.json, and README files.
- Changed CLI commands and references from "ocd" to "od".
- Adjusted file structure references in documentation and code to reflect new naming conventions.
- Enhanced .gitignore to include new runtime data files.
- Updated metadata in LICENSE file to match new project name.
2026-04-28 14:48:45 +08:00

211 lines
6.8 KiB
TypeScript

export type ExecMode = 'daemon' | 'api';
export interface AppConfig {
mode: ExecMode;
apiKey: string;
baseUrl: string;
model: string;
agentId: string | null;
skillId: string | null;
designSystemId: string | null;
// True once the user has been through the welcome onboarding modal at
// least once (saved or skipped). Bootstrap skips the auto-popup when
// this is set so refreshing the page doesn't re-prompt.
onboardingCompleted?: boolean;
}
export type AgentEvent =
| { kind: 'status'; label: string; detail?: string | undefined }
| { kind: 'text'; text: string }
| { kind: 'thinking'; text: string }
| { kind: 'tool_use'; id: string; name: string; input: unknown }
| { kind: 'tool_result'; toolUseId: string; content: string; isError: boolean }
| { kind: 'usage'; inputTokens?: number; outputTokens?: number; costUsd?: number; durationMs?: number }
| { kind: 'raw'; line: string };
export interface ChatMessage {
id: string;
role: 'user' | 'assistant';
content: string;
events?: AgentEvent[];
startedAt?: number;
endedAt?: number;
// Files staged by the user on this turn (uploaded into the project
// folder). Persisted on the message so re-renders show the same chips.
attachments?: ChatAttachment[];
// Files that appeared in the project folder during this assistant turn.
// Rendered as download / open chips at the end of the message so the
// user can grab a generated artifact (.pptx, .zip, etc.) in one click.
producedFiles?: ProjectFile[];
}
// Reference to a file that lives in the active project folder. The user
// stages these by paste / drop / picker / @-mention; the daemon receives
// `path` on the chat call and the agent reads them from cwd.
export interface ChatAttachment {
path: string;
name: string;
kind: 'image' | 'file';
size?: number;
}
export interface Artifact {
identifier: string;
title: string;
html: string;
savedUrl?: string;
}
export interface ExamplePreview {
source: 'skill' | 'design-system';
id: string;
title: string;
html: string;
}
export interface AgentInfo {
id: string;
name: string;
bin: string;
available: boolean;
path?: string;
version?: string | null;
}
export interface SkillSummary {
id: string;
name: string;
description: string;
triggers: string[];
mode: 'prototype' | 'deck' | 'template' | 'design-system';
platform?: 'desktop' | 'mobile' | null;
scenario?: string | null;
previewType: string;
designSystemRequired: boolean;
defaultFor: string[];
upstream: string | null;
/** Lower number = higher priority in the Examples gallery. `null` keeps
* the skill in its natural alphabetical position below all featured
* entries. Set via `od.featured` in the SKILL.md frontmatter. */
featured?: number | null;
hasBody: boolean;
examplePrompt: string;
}
export interface SkillDetail extends SkillSummary {
body: string;
}
export interface DesignSystemSummary {
id: string;
title: string;
category: string;
summary: string;
/** 4 representative hex strings extracted from DESIGN.md: [bg, support, fg, accent].
* Empty when DESIGN.md doesn't expose its tokens in the bold-and-hex format. */
swatches?: string[];
}
export interface DesignSystemDetail extends DesignSystemSummary {
body: string;
}
export type ProjectFileKind =
| 'html'
| 'image'
| 'sketch'
| 'text'
| 'code'
| 'binary';
export interface ProjectFile {
name: string;
// Project-relative path. Today the project folder is flat so `path`
// equals `name` for every file — but components that want to think in
// path terms (the @-mention picker, the staged-attachment chips) can
// read this without caring whether subdirs exist.
path?: string;
// Discriminator for code that wants to filter files vs dirs in a tree
// listing. The current listing is files-only; we always set this to
// 'file' so the discriminator is meaningful.
type?: 'file' | 'dir';
size: number;
mtime: number;
kind: ProjectFileKind;
mime: string;
}
// Per-project metadata captured at creation time. The agent reads this
// during chat (via the system prompt) and the question-form re-asks for
// any field that's missing. Each `kind` carries a different shape.
export type ProjectKind = 'prototype' | 'deck' | 'template' | 'other';
export interface ProjectMetadata {
kind: ProjectKind;
// Prototype: 'wireframe' | 'high-fidelity'. Drives the visual ambition.
fidelity?: 'wireframe' | 'high-fidelity';
// Slide deck: whether the user wants speaker notes (less text per slide).
speakerNotes?: boolean;
// Template: whether motion/animation should be part of the design.
// Defaults `false` so a static template stays static unless asked.
animations?: boolean;
// Template: id of the user-saved template chosen at creation time.
// Only set on `kind === 'template'` projects (the other kinds dropped
// template selection entirely). The built-in 'animation' starter no
// longer ships — every template here is user-created via Share menu.
templateId?: string;
// Template: human-readable label of the source template, kept separate
// from `templateId` so the agent surface can name it without re-fetching.
templateLabel?: string;
// Multi-select design-system "inspirations". The first pick still goes to
// `Project.designSystemId` (the primary system that controls tokens); any
// additional ids land here and are passed to the agent as references the
// generated artifact should *also* draw from. Empty / undefined when the
// user stayed in single-select mode.
inspirationDesignSystemIds?: string[];
}
export interface Project {
id: string;
name: string;
skillId: string | null;
designSystemId: string | null;
createdAt: number;
updatedAt: number;
// The prompt that should be prefilled into the chat composer when the
// project is opened. Cleared the first time the project is opened so it
// doesn't keep re-populating on subsequent visits.
pendingPrompt?: string;
// Optional structured metadata captured by the new-project panel. The
// shape varies by `kind`. Older projects created before this field
// existed will have it `undefined`.
metadata?: ProjectMetadata;
}
export interface ProjectTemplate {
id: string;
name: string;
// Source project the template was captured from (so we can show "based
// on …" in the picker). Optional because some templates are seeded.
sourceProjectId?: string;
// Snapshot of HTML files at the moment the template was saved. Each
// entry is a basename → text content pair.
files: Array<{ name: string; content: string }>;
// Free-form description shown in the picker.
description?: string;
createdAt: number;
}
export interface Conversation {
id: string;
projectId: string;
title: string | null;
createdAt: number;
updatedAt: number;
}
export interface OpenTabsState {
tabs: string[];
active: string | null;
}