diff --git a/demo-snapshots/CHANGELOG-DEMO.md b/demo-snapshots/CHANGELOG-DEMO.md new file mode 100644 index 000000000..cfbe38c4a --- /dev/null +++ b/demo-snapshots/CHANGELOG-DEMO.md @@ -0,0 +1,49 @@ +## v1.30.2 (2025-11-01) + +Comparing v1.29.0 → v1.30.2. This changelog documents changes to the public API surface that third-party extensions and custom nodes depend on. + +### ✨ Additions + +**Type Aliases** + +- `WorkflowId` + +**Interfaces** + +- `ExtensionMetadata` + - Members: `id`, `name`, `version`, `description` + +### 🔄 Modifications + +> **Note**: Some modifications may be breaking changes. + +**Interfaces** + +- `ComfyApi` + - ✨ Added member: `queuePromptAsync` + - ✨ Added member: `cancelPrompt` + - ✨ Added member: `getQueueStatus` + - ⚠️ **Breaking**: Removed member: `queuePrompt` +- `NodeDef` + - ✨ Added member: `input` + - ✨ Added member: `output` + - ✨ Added member: `output_name` +- `WorkflowMetadata` + - ✨ Added member: `tags` + - ✨ Added member: `thumbnail` + +**Enums** + +- `NodeStatus` + - ✨ Added enum value: `ERROR` + - ✨ Added enum value: `COMPLETED` + +**Classes** + +- `WorkflowManager` + - ✨ Added member: `cache` + - ✨ Added method: `deleteWorkflow()` + - ✨ Added method: `searchWorkflows()` + +--- + diff --git a/demo-snapshots/README.md b/demo-snapshots/README.md new file mode 100644 index 000000000..5de4442ee --- /dev/null +++ b/demo-snapshots/README.md @@ -0,0 +1,188 @@ +# API Changelog Generation Demo + +This demo showcases the automated API changelog generation system comparing two versions of the ComfyUI Frontend public API. + +## Overview + +The demo compares **v1.29.0** → **v1.30.2** to demonstrate: +- Breaking change detection +- API additions tracking +- Non-breaking modifications +- Human-readable changelog generation + +## Demo Files + +### Input Files +- **`v1.29.0.d.ts`** - TypeScript definitions representing the v1.29.0 API surface +- **`v1.30.2.d.ts`** - TypeScript definitions representing the v1.30.2 API surface + +### Generated Files +- **`v1.29.0.json`** - Structured API snapshot from v1.29.0 +- **`v1.30.2.json`** - Structured API snapshot from v1.30.2 +- **`CHANGELOG-DEMO.md`** - Generated changelog comparing the two versions + +## Running the Demo + +```bash +# Generate API snapshots +node scripts/snapshot-api.js demo-snapshots/v1.29.0.d.ts > demo-snapshots/v1.29.0.json +node scripts/snapshot-api.js demo-snapshots/v1.30.2.d.ts > demo-snapshots/v1.30.2.json + +# Compare snapshots and generate changelog +node scripts/compare-api-snapshots.js \ + demo-snapshots/v1.29.0.json \ + demo-snapshots/v1.30.2.json \ + 1.29.0 \ + 1.30.2 \ + > demo-snapshots/CHANGELOG-DEMO.md +``` + +## Key Changes Detected + +### ⚠️ Breaking Changes + +1. **`ComfyApi.queuePrompt()` removed** + - Replaced with `queuePromptAsync()` which includes additional options + - Extension developers need to update their code to use the new async method + +### ✨ New Additions + +1. **New Interface: `ExtensionMetadata`** + - Provides metadata for extensions + - Fields: `id`, `name`, `version`, `description` + +2. **New Type: `WorkflowId`** + - Type alias for workflow identifiers + +3. **Enhanced `ComfyApi` Interface** + - `queuePromptAsync()` - Async queue with priority support + - `cancelPrompt()` - Cancel queued prompts + - `getQueueStatus()` - Query queue state + +4. **Extended `NodeDef` Interface** + - `input` - Input specification + - `output` - Output types + - `output_name` - Output names + +5. **Enhanced `NodeStatus` Enum** + - Added `ERROR` state + - Added `COMPLETED` state + +6. **Extended `WorkflowManager` Class** + - `cache` property for workflow caching + - `deleteWorkflow()` method + - `searchWorkflows()` method + +### 🔄 Non-Breaking Modifications + +1. **`WorkflowMetadata` enhancements** + - Added optional `tags` field + - Added optional `thumbnail` field + +## Real-World Usage + +In production, this system will: + +1. **Automatic Triggering**: Run after each NPM types release +2. **Version Detection**: Automatically detect current and previous versions from git tags +3. **Build Integration**: Build actual TypeScript types from the repository +4. **PR Creation**: Generate draft pull requests with the changelog +5. **Human Review**: Allow maintainers to review and enhance before merging + +## Benefits for Extension Developers + +### Clear Breaking Change Visibility +Extension developers can immediately see: +- What APIs were removed +- What signatures changed +- How to migrate their code + +### Migration Planning +With clear documentation of additions and changes, developers can: +- Plan updates around breaking changes +- Adopt new features when ready +- Understand version compatibility + +### Historical Reference +The cumulative `docs/API-CHANGELOG.md` provides: +- Complete API evolution history +- Context for design decisions +- Migration guides for major versions + +## Example Extension Migration + +### Before (v1.29.0) +```typescript +// Old code using queuePrompt +const result = await api.queuePrompt(workflow); +console.log('Queued:', result.prompt_id); +``` + +### After (v1.30.2) +```typescript +// New code using queuePromptAsync with priority +const result = await api.queuePromptAsync(workflow, { priority: 1 }); +console.log('Queued:', result.prompt_id, 'Position:', result.number); +``` + +## Snapshot Structure + +The JSON snapshots contain structured representations of: + +```json +{ + "types": { /* Type aliases */ }, + "interfaces": { /* Interface definitions with members */ }, + "enums": { /* Enum values */ }, + "functions": { /* Exported functions */ }, + "classes": { /* Class definitions with methods */ }, + "constants": { /* Exported constants */ } +} +``` + +Each entry includes: +- **Name**: Identifier +- **Kind**: Type of declaration +- **Members/Methods**: Properties and functions +- **Types**: Parameter and return types +- **Visibility**: Public/private/protected modifiers +- **Optional**: Whether parameters/properties are optional + +## Comparison Algorithm + +The comparison script: + +1. **Categorizes changes** into breaking, additions, and modifications +2. **Detects breaking changes**: + - Removed interfaces, classes, functions + - Removed methods or properties + - Changed method signatures + - Changed return types + - Removed enum values +3. **Tracks additions**: + - New interfaces, classes, types + - New methods and properties + - New enum values +4. **Identifies modifications**: + - Type changes + - Optionality changes + - Signature changes + +## Future Enhancements + +Planned improvements include: + +- **LLM Enhancement**: Use AI to generate better descriptions and migration guides +- **Email Notifications**: Alert developers on mailing list for major changes +- **Release Notes Integration**: Auto-include in GitHub releases +- **Deprecation Tracking**: Mark APIs as deprecated before removal +- **Example Code**: Generate migration code snippets automatically + +## Conclusion + +This automated system ensures: +- ✅ Zero manual effort for changelog generation +- ✅ Consistent documentation format +- ✅ Clear breaking change visibility +- ✅ Historical API evolution tracking +- ✅ Better extension developer experience diff --git a/demo-snapshots/v1.29.0.d.ts b/demo-snapshots/v1.29.0.d.ts new file mode 100644 index 000000000..50dc58c26 --- /dev/null +++ b/demo-snapshots/v1.29.0.d.ts @@ -0,0 +1,58 @@ +/** + * Mock TypeScript definitions representing v1.29.0 API surface + * This represents the public API as it existed in version 1.29.0 + */ + +export interface ComfyApi { + /** + * Get API URL for backend calls + */ + apiURL(path: string): string + + /** + * Get file URL for static resources + */ + fileURL(path: string): string + + /** + * Queue a prompt for execution + */ + queuePrompt(prompt: object): Promise<{ prompt_id: string }> + + /** + * Interrupt current execution + */ + interrupt(): Promise +} + +export interface NodeDef { + name: string + category: string + display_name?: string + description?: string + python_module: string +} + +export enum NodeStatus { + IDLE = 'idle', + QUEUED = 'queued', + RUNNING = 'running' +} + +export interface WorkflowMetadata { + title?: string + description?: string + author?: string + version?: string +} + +export class WorkflowManager { + workflows: Map + + constructor() + + loadWorkflow(id: string): Promise + saveWorkflow(id: string, data: object): Promise +} + +export type NodeId = string diff --git a/demo-snapshots/v1.29.0.json b/demo-snapshots/v1.29.0.json new file mode 100644 index 000000000..232567bad --- /dev/null +++ b/demo-snapshots/v1.29.0.json @@ -0,0 +1,192 @@ +{ + "types": { + "NodeId": { + "kind": "type", + "name": "NodeId", + "text": "export type NodeId = string;", + "exported": true + } + }, + "interfaces": { + "ComfyApi": { + "kind": "interface", + "name": "ComfyApi", + "members": [ + { + "name": "apiURL", + "kind": "method", + "parameters": [ + { + "name": "path", + "type": "string", + "optional": false + } + ], + "returnType": "string" + }, + { + "name": "fileURL", + "kind": "method", + "parameters": [ + { + "name": "path", + "type": "string", + "optional": false + } + ], + "returnType": "string" + }, + { + "name": "queuePrompt", + "kind": "method", + "parameters": [ + { + "name": "prompt", + "type": "object", + "optional": false + } + ], + "returnType": "Promise<{ prompt_id: string }>" + }, + { + "name": "interrupt", + "kind": "method", + "parameters": [], + "returnType": "Promise" + } + ], + "exported": true, + "heritage": [] + }, + "NodeDef": { + "kind": "interface", + "name": "NodeDef", + "members": [ + { + "name": "name", + "type": "string", + "optional": false + }, + { + "name": "category", + "type": "string", + "optional": false + }, + { + "name": "display_name", + "type": "string", + "optional": true + }, + { + "name": "description", + "type": "string", + "optional": true + }, + { + "name": "python_module", + "type": "string", + "optional": false + } + ], + "exported": true, + "heritage": [] + }, + "WorkflowMetadata": { + "kind": "interface", + "name": "WorkflowMetadata", + "members": [ + { + "name": "title", + "type": "string", + "optional": true + }, + { + "name": "description", + "type": "string", + "optional": true + }, + { + "name": "author", + "type": "string", + "optional": true + }, + { + "name": "version", + "type": "string", + "optional": true + } + ], + "exported": true, + "heritage": [] + } + }, + "enums": { + "NodeStatus": { + "kind": "enum", + "name": "NodeStatus", + "members": [ + { + "name": "IDLE", + "value": "\"idle\"" + }, + { + "name": "QUEUED", + "value": "\"queued\"" + }, + { + "name": "RUNNING", + "value": "\"running\"" + } + ], + "exported": true + } + }, + "functions": {}, + "classes": { + "WorkflowManager": { + "kind": "class", + "name": "WorkflowManager", + "members": [ + { + "name": "workflows", + "type": "Map", + "visibility": "public" + } + ], + "methods": [ + { + "name": "loadWorkflow", + "parameters": [ + { + "name": "id", + "type": "string", + "optional": false + } + ], + "returnType": "Promise", + "visibility": "public" + }, + { + "name": "saveWorkflow", + "parameters": [ + { + "name": "id", + "type": "string", + "optional": false + }, + { + "name": "data", + "type": "object", + "optional": false + } + ], + "returnType": "Promise", + "visibility": "public" + } + ], + "exported": true, + "heritage": [] + } + }, + "constants": {} +} diff --git a/demo-snapshots/v1.30.2.d.ts b/demo-snapshots/v1.30.2.d.ts new file mode 100644 index 000000000..da0cf0a16 --- /dev/null +++ b/demo-snapshots/v1.30.2.d.ts @@ -0,0 +1,92 @@ +/** + * Mock TypeScript definitions representing v1.30.2 API surface + * This represents the public API with several breaking changes and additions + */ + +export interface ComfyApi { + /** + * Get API URL for backend calls + */ + apiURL(path: string): string + + /** + * Get file URL for static resources + */ + fileURL(path: string): string + + /** + * Queue a prompt for execution (async version) + */ + queuePromptAsync( + prompt: object, + options?: { priority?: number } + ): Promise<{ prompt_id: string; number: number }> + + /** + * Cancel a queued prompt + */ + cancelPrompt(prompt_id: string): Promise + + /** + * Interrupt current execution + */ + interrupt(): Promise + + /** + * Get queue status + */ + getQueueStatus(): Promise<{ queue_running: any[]; queue_pending: any[] }> +} + +export interface NodeDef { + name: string + category: string + display_name?: string + description?: string + python_module: string + input: { + required?: Record + optional?: Record + } + output: string[] + output_name: string[] +} + +export enum NodeStatus { + IDLE = 'idle', + QUEUED = 'queued', + RUNNING = 'running', + ERROR = 'error', + COMPLETED = 'completed' +} + +export interface WorkflowMetadata { + title?: string + description?: string + author?: string + version?: string + tags?: string[] + thumbnail?: string +} + +export interface ExtensionMetadata { + id: string + name: string + version: string + description?: string +} + +export class WorkflowManager { + workflows: Map + cache: Map + + constructor() + + loadWorkflow(id: string): Promise + saveWorkflow(id: string, data: object): Promise + deleteWorkflow(id: string): Promise + searchWorkflows(query: string): Promise +} + +export type NodeId = string +export type WorkflowId = string diff --git a/demo-snapshots/v1.30.2.json b/demo-snapshots/v1.30.2.json new file mode 100644 index 000000000..79d655223 --- /dev/null +++ b/demo-snapshots/v1.30.2.json @@ -0,0 +1,311 @@ +{ + "types": { + "NodeId": { + "kind": "type", + "name": "NodeId", + "text": "export type NodeId = string;", + "exported": true + }, + "WorkflowId": { + "kind": "type", + "name": "WorkflowId", + "text": "export type WorkflowId = string;", + "exported": true + } + }, + "interfaces": { + "ComfyApi": { + "kind": "interface", + "name": "ComfyApi", + "members": [ + { + "name": "apiURL", + "kind": "method", + "parameters": [ + { + "name": "path", + "type": "string", + "optional": false + } + ], + "returnType": "string" + }, + { + "name": "fileURL", + "kind": "method", + "parameters": [ + { + "name": "path", + "type": "string", + "optional": false + } + ], + "returnType": "string" + }, + { + "name": "queuePromptAsync", + "kind": "method", + "parameters": [ + { + "name": "prompt", + "type": "object", + "optional": false + }, + { + "name": "options", + "type": "{ priority?: number }", + "optional": true + } + ], + "returnType": "Promise<{ prompt_id: string; number: number }>" + }, + { + "name": "cancelPrompt", + "kind": "method", + "parameters": [ + { + "name": "prompt_id", + "type": "string", + "optional": false + } + ], + "returnType": "Promise" + }, + { + "name": "interrupt", + "kind": "method", + "parameters": [], + "returnType": "Promise" + }, + { + "name": "getQueueStatus", + "kind": "method", + "parameters": [], + "returnType": "Promise<{ queue_running: any[]; queue_pending: any[] }>" + } + ], + "exported": true, + "heritage": [] + }, + "NodeDef": { + "kind": "interface", + "name": "NodeDef", + "members": [ + { + "name": "name", + "type": "string", + "optional": false + }, + { + "name": "category", + "type": "string", + "optional": false + }, + { + "name": "display_name", + "type": "string", + "optional": true + }, + { + "name": "description", + "type": "string", + "optional": true + }, + { + "name": "python_module", + "type": "string", + "optional": false + }, + { + "name": "input", + "type": "{\n required?: Record;\n optional?: Record;\n }", + "optional": false + }, + { + "name": "output", + "type": "string[]", + "optional": false + }, + { + "name": "output_name", + "type": "string[]", + "optional": false + } + ], + "exported": true, + "heritage": [] + }, + "WorkflowMetadata": { + "kind": "interface", + "name": "WorkflowMetadata", + "members": [ + { + "name": "title", + "type": "string", + "optional": true + }, + { + "name": "description", + "type": "string", + "optional": true + }, + { + "name": "author", + "type": "string", + "optional": true + }, + { + "name": "version", + "type": "string", + "optional": true + }, + { + "name": "tags", + "type": "string[]", + "optional": true + }, + { + "name": "thumbnail", + "type": "string", + "optional": true + } + ], + "exported": true, + "heritage": [] + }, + "ExtensionMetadata": { + "kind": "interface", + "name": "ExtensionMetadata", + "members": [ + { + "name": "id", + "type": "string", + "optional": false + }, + { + "name": "name", + "type": "string", + "optional": false + }, + { + "name": "version", + "type": "string", + "optional": false + }, + { + "name": "description", + "type": "string", + "optional": true + } + ], + "exported": true, + "heritage": [] + } + }, + "enums": { + "NodeStatus": { + "kind": "enum", + "name": "NodeStatus", + "members": [ + { + "name": "IDLE", + "value": "\"idle\"" + }, + { + "name": "QUEUED", + "value": "\"queued\"" + }, + { + "name": "RUNNING", + "value": "\"running\"" + }, + { + "name": "ERROR", + "value": "\"error\"" + }, + { + "name": "COMPLETED", + "value": "\"completed\"" + } + ], + "exported": true + } + }, + "functions": {}, + "classes": { + "WorkflowManager": { + "kind": "class", + "name": "WorkflowManager", + "members": [ + { + "name": "workflows", + "type": "Map", + "visibility": "public" + }, + { + "name": "cache", + "type": "Map", + "visibility": "public" + } + ], + "methods": [ + { + "name": "loadWorkflow", + "parameters": [ + { + "name": "id", + "type": "string", + "optional": false + } + ], + "returnType": "Promise", + "visibility": "public" + }, + { + "name": "saveWorkflow", + "parameters": [ + { + "name": "id", + "type": "string", + "optional": false + }, + { + "name": "data", + "type": "object", + "optional": false + } + ], + "returnType": "Promise", + "visibility": "public" + }, + { + "name": "deleteWorkflow", + "parameters": [ + { + "name": "id", + "type": "string", + "optional": false + } + ], + "returnType": "Promise", + "visibility": "public" + }, + { + "name": "searchWorkflows", + "parameters": [ + { + "name": "query", + "type": "string", + "optional": false + } + ], + "returnType": "Promise", + "visibility": "public" + } + ], + "exported": true, + "heritage": [] + } + }, + "constants": {} +} diff --git a/eslint.config.ts b/eslint.config.ts index 6681d2126..d9610e30e 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -58,7 +58,8 @@ export default defineConfig([ 'src/extensions/core/*', 'src/scripts/*', 'src/types/generatedManagerTypes.ts', - 'src/types/vue-shim.d.ts' + 'src/types/vue-shim.d.ts', + 'demo-snapshots/*' ] }, {