From 8bc2ff0800893d111d7cfe9caefbdfe3987991d5 Mon Sep 17 00:00:00 2001 From: Connor Byrne Date: Wed, 13 May 2026 13:55:39 -0700 Subject: [PATCH] docs(ext-api): update README to reflect implementation status - Change status from "scaffolded" to "implemented (Phase A)" - Update file structure to match actual files - Replace stale decision doc refs with ADR links - Add related research document links Co-Authored-By: Claude Opus 4.5 --- src/extension-api/README.md | 65 +++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/src/extension-api/README.md b/src/extension-api/README.md index 66f3b863ad..a29ba30750 100644 --- a/src/extension-api/README.md +++ b/src/extension-api/README.md @@ -1,9 +1,7 @@ # Extension API — Public Source of Truth -> **Status**: scaffolded. Implementation pending PKG2 — see -> `../../../plans/P2-extension-api-package.md` and -> `../../../plans/prompts/PKG2-author-declaration.md` in the workspace -> root. +> **Status**: Implemented (Phase A). Runtime backed by stub ECS components; +> full ECS integration lands with #11939. This folder is the single source of truth for the public ComfyUI extension API. Every file here is part of the published `@comfyorg/extension-api` @@ -11,18 +9,18 @@ npm package. Do not re-export from `/src` — this barrel is the **published package entry point**, which is the explicit exception to the project's "no barrel files in /src" rule (root AGENTS.md rule #19). -## Intended structure (post-PKG2) +## File structure ``` extension-api/ ├── index.ts ← barrel — package entry point -├── node.ts ← NodeHandle + NodeEvents + payload types -├── widget.ts ← WidgetHandle + WidgetEvents + payload types -├── events.ts ← shared Handler, cross-cutting event types -├── lifecycle.ts ← Setup ctx, defineExtension, lifecycle hooks -├── shell.ts ← sidebar, bottom panel, command, toast (moved -│ from ../types/extensionTypes.ts) -├── identifiers.ts ← NodeLocatorId etc. (re-exports) +├── node.ts ← NodeHandle interface + node event payload types +├── widget.ts ← WidgetHandle interface + widget event payload types +├── types.ts ← ExtensionOptions, NodeExtensionOptions, WidgetExtensionOptions +├── events.ts ← Handler, AsyncHandler, Unsubscribe +├── lifecycle.ts ← onNodeMounted, onNodeRemoved hooks + rationale docs +├── shell.ts ← SidebarTabExtension, BottomPanelExtension, CommandManager, etc. +├── identifiers.ts ← NodeLocatorId, NodeExecutionId + parsers/type guards └── README.md ← this file ``` @@ -32,34 +30,39 @@ v1 (`ComfyExtension` interface in `../types/comfy.ts`, `app.registerExtension(.. runtime entry point in `../scripts/app.ts`) **stays in its current locations**. Custom extensions in the wild consume the runtime entry point, not the type file — moving the type file would churn ~30 internal imports for zero runtime -benefit. The v1↔v2 distinction is at the entry point (D6 Part 1), not the folder. +benefit. The v1↔v2 distinction is at the entry point, not the folder. ## Authoring rules -1. **Hand-authored**, not generated. This is a public API; we own the - shape. -2. **No `any`, no `as any`, no `@ts-expect-error`.** If you need an - escape hatch, the type is wrong. +1. **Hand-authored**, not generated. This is a public API; we own the shape. +2. **No `any`, no `as any`, no `@ts-expect-error`.** If you need an escape + hatch, the type is wrong. 3. Every public type has a TSDoc block with at minimum: - 1-line summary - `@stability` tag (`stable` | `experimental` | `deprecated`) - - `@example` block -4. Naming follows D6 Part 3: - - Read-only invariants (set at construction): accessor (`get name()`) + - `@example` block (where applicable) +4. Naming follows conventions: + - Read-only invariants (set at construction): `readonly` property - Read-only state (changes over time): method (`getValue()`) - Mutating actions: method (`setValue(v)`) - Boolean predicates: method (`isHidden()`) -5. Events follow D5: typed payloads, no `Function`, split-channel events - (`valueChange`/`optionChange`/`propertyChange`). -6. No internal types (`World`, `Component`, branded `EntityId`) +5. Events: typed payloads, no `Function`, split-channel events + (`valueChange` / `optionChange` / `propertyChange`). +6. No internal types (`World`, `Component`, branded `EntityId` internals) leak through this barrel. -## Cross-references +## Key design decisions -- `decisions/D5-events-and-payload-typing.md` -- `decisions/D6-parallel-paths-migration.md` -- `decisions/D7-widget-shape-and-persistence.md` (gating blocker for - `widget.ts`) -- `decisions/D8-world-vue-reactive-adapter.md` -- `plans/P2-extension-api-package.md` -- `plans/P1-comfy-extension-v2-api.md` +| ADR | Decision | +| ----------------------------------------------------------------------------- | --------------------------------------------------------- | +| [ADR-0008](../../docs/adr/0008-entity-component-system.md) | Entity Component System architecture | +| [ADR-0010](../../docs/adr/0010-deprecate-node-level-serialization-control.md) | Deprecate `node.on('beforeSerialize')` — use widget-level | +| [ADR-0011](../../docs/adr/0011-immutability-via-fresh-copies.md) | Return fresh copies from collection methods | +| [ADR-0012](../../docs/adr/0012-pure-function-loader-pattern.md) | Pure function registration + loader activation | + +## Related research + +- [Identity encapsulation](../../docs/research/identity-encapsulation.md) — when extensions need raw entity IDs +- [Coordinate systems](../../docs/research/coordinate-systems.md) — canvas vs screen coordinates +- [Widget state categories](../../docs/research/widget-state-categories.md) — value/properties/options/DOM +- [Serialization context](../../docs/research/serialization-context.md) — workflow/prompt/clone/subgraph-promote