Skip to content

Releases: BESSER-PEARL/BESSER

v7.4.1

30 Apr 15:23
05c714a

Choose a tag to compare

Patch release: internal cleanup — drop the legacy packages/webapp and rename packages/webapp2 to packages/webapp in the Web Modeling Editor frontend. No user-visible behavior changes, no API changes, no metamodel changes — this is a tidy-up that removes dead code and restores the canonical package name.

Highlights

  • Frontend monorepo simplification. The legacy Webpack + Bootstrap packages/webapp package — kept on disk "for reference only" since the v7 redesign — is now removed. The active React + Vite + Radix UI app that previously lived under packages/webapp2 is renamed to packages/webapp so the canonical workspace name reflects what users actually run. Build artefacts now land in build/webapp/ instead of build/webapp2/; the standalone packages/server reads from the new path directly (the legacy fallback was deleted).
  • Documentation sweep. Every reference to webapp2 across both repositories is now webapp — frontend README.md, CLAUDE.md, CONTRIBUTING.md; the backend docs/source/contributing/ RSTs; and 15 frontend Sphinx RSTs (overview/, contributing/, editor/, reference/, webapp/). Stale "this package is deprecated and will be removed" warnings are gone too.
  • Documentation polish (separate from the rename). Tightened the backend's README.md, CONTRIBUTING.md, DEVELOPMENT_SETUP.md, and CLAUDE.md in three small ways: the repository URL is now the canonical Title-Case BESSER-Web-Modeling-Editor (GitHub still redirects the old all-caps form, but the new form is what we ship); the Node version requirement in the backend CONTRIBUTING.md is now Node.js 20+ to match the frontend repo's CI matrix; and docker-compose (Compose v1 syntax) is replaced with the v2 form docker compose in setup instructions.

Compatibility

  • No public API change. The published @besser/wme npm package (the editor) is untouched; only the internal monorepo workspace name changed.
  • No metamodel, generator, or backend API change.
  • Anyone who scripted npm run *:webapp2 against this monorepo will need to switch to npm run *:webapp. npm run dev, npm run build, npm run test, and npm run lint continue to work unchanged — they were already aliases that covered both names.

Testing

  • Frontend: npm run build produces build/webapp/ and build/server/ cleanly under the renamed workspace.
  • Frontend: 55 perspective unit tests (project.test.ts, HiddenPerspectivesBanner.test.tsx, ProjectSettingsPanel.test.tsx, WorkspaceSidebar.test.tsx) green.
  • Backend: no Python code changed; the existing test suite still applies.

v7.4.0

30 Apr 14:38
935cb1e

Choose a tag to compare

This release introduces a new OCL utility package under besser.BUML.metamodel.ocl (chain, clone, predicates, substitute, walk) and a new OCL normalization subsystem under besser.BUML.notations.ocl.normalization that rewrites parsed constraints into a canonical CNF/iterator-fused form. The Web Modeling Editor gains per-project modeling perspectives (filter the workspace to the diagram families a project actually uses, with quick-select presets and a recovery banner when hidden perspectives still hold content), a substantial agent configuration rewrite, and a number of editor polish fixes. bocl is bumped to 1.0.1 to pick up the matching parser-side fixes.

New Features and Improvements

OCL Utility Package (besser.BUML.metamodel.ocl)

  • Added walk — post-order traversal helper that skips structural InfixOperator markers and surfaces only AST nodes.
  • Added clone — typed AST cloner that preserves shared metamodel references (Property, InfixOperator) while deep-copying the expression tree, so rewrite rules can mutate without touching the source.
  • Added substitute — capture-avoiding substitution with an explicit ScopeStack (push/pop in try/finally), correct under nested iterators and shadowed iterator variables.
  • Added chain — extracts the property-call chain rooted at a navigation expression, surfacing the navigation path consumers need for downstream analysis.
  • Added predicates — composable predicate set (is_op, is_and, is_implies, is_xor, is_isempty, is_loop, …) for matching nodes in rewrite rules and external analyzers.

OCL Normalization Subsystem (besser.BUML.notations.ocl.normalization)

  • Added a fixed-iteration rewrite engine (normalize.normalize) that drives a deterministic, ordered rule pipeline to a fixpoint, with a developer-bug max_iterations guard against non-terminating rules.
  • Added six rule modules covering the normalization tactics: boolean (NNF / De Morgan / double-negation elimination), cnf (implies-elimination, if-bool-elim, distribute-or-over-and), collection (size/isEmpty / notEmpty rewrites), iterator (select/forall/exists fusion), multiplicity (multiplicity-aware optimizations), all_instances (allInstances rewrites).
  • Added pretty_printer for human-readable round-tripping of OCL ASTs back to source form.
  • Added api.parse_ocl as the single new public entry point that wraps the existing ANTLR parser and surfaces aggregated BOCLSyntaxError instead of raising on the first error.
  • Added wrapping_visitor so external callers can catch parse-shaped errors uniformly across the visitor stack.
  • Narrowed the if-to-boolean rewrite so it only fires on if-expressions whose branches are boolean-typed (preventing accidental rewrites of conditional values), and surfaced unresolved-property errors as BOCLSyntaxError instead of bare Exception.

Web Modeling Editor — Modeling Perspectives

  • Added per-project modeling perspectives: each project carries a per-diagram visibility map under BesserProject.settings.perspectives that filters the workspace sidebar, mobile navigation, and command palette in lockstep. Hiding a perspective removes it from every switch surface but preserves its diagrams, so toggling it back on restores the workspace state. Project schema bumped from v3 to v4 with an automatic migration that preserves any pre-existing user choices and defaults missing keys to enabled.
  • Added quick presets in Project Settings — Data Modeler, Agent Developer, Full Application, Quantum, Show All — that flip the per-diagram toggles together for common project shapes. Individual per-diagram toggles remain available below the presets for fine-grained control.
  • Added a last-enabled guard: the only remaining enabled perspective cannot be toggled off (the workspace would have nothing to show). Disabling the perspective whose diagram is currently active auto-switches the editor to the first still-enabled type, so the canvas never lands on a hidden diagram.
  • Added a hidden-perspectives recovery banner at the top of the workspace that appears whenever the project still references a hidden perspective (either because that perspective's diagrams hold content, or because another diagram cross-references one of them). The banner offers one-click re-enable and renders on every route, including Project Settings itself, so users can recover the moment they realize a toggle was a mistake.

Web Modeling Editor — Agent Configuration

  • Rewrote the Agent Configuration panel for usability: clearer grouping of platform / intent-recognition / LLM provider settings on the agent diagram, refined personalization flow, and tighter agent-variant lifecycle. Agent runtime config continues to live on the agent diagram itself (single source of truth introduced in v7.3.0); no storage changes required for existing projects.

  • Fixed a class-diagram bug where toggling Abstract or Enumeration off left the stereotype label and italic styling on the element; the toggle now clears stereotype, italic, and underline on the underlying UMLClass instance.

v7.3.0

28 Apr 14:47
99efbd0

Choose a tag to compare

This release introduces a new UserDiagram for describing the different end-user profiles of apps, the Agent Personalization workflow to create variations of the same agent for each user profile, and a standalone chatbot deploy target on the existing GitHub deploy flow. It also tightens the deploy export so diagrams.json written into deployed repos is re-importable through the editor, and gates the new recommendation endpoints behind GitHub OAuth so the BESSER server's OpenAI quota cannot be drained anonymously.

New Features and Improvements

User Diagram

  • Added UserDiagram as a first-class diagram type for describing the different user profiles of created apps, capturing personal information, language profile, competences, accessibility constraints, abilities, and cultural dimensions in the same metamodel space as the rest of B-UML.
  • Shipped an OCL constraint set (pi_age_range, skill_name_not_empty, education_required_fields, disability_description_not_empty) declared in constants/user_buml_model.py and evaluated by the existing check_ocl_constraint pipeline.
  • Extended the validation router so the same /validate-diagram endpoint covers UserDiagram payloads alongside the existing diagram types.
  • Added a dedicated palette in the Web Modeling Editor (UserModelName, UserModelAttribute, UserModelIcon).
  • The attribute-edit panel now supports enumeration values with case-insensitive enum lookup.

Agent Personalization Pipeline

  • Based on a given agent model, user model, and agent profile (defining user-specific customizations), a personalized model can be generated, reflecting the customizations.
  • The BAFGenerator can now ingest multiple agent models with a user-profile-to-agent-model mapping and generate an agent that provides a personalized experience based on the available profiles.

Standalone Chatbot Deploy

  • Extended POST /github/deploy-webapp to accept a deploy_config.target of "webapp" or "chatbot" (the frontend translates its "agent""chatbot" at the wire boundary).

Web Modeling Editor

  • Added the agent-personalization workflow with AgentConfigurationPanel (absorbing the previous two personalization panels) and an agent-variant management UI on the agent diagram.
  • Added the Deploy → "Publish to Render" agent target so users can deploy a personalized chatbot directly from the editor.
  • Added v2 LocalStorageRepository migrations for besser_systemConfig and the legacy agentConfig key.
  • Migrated useGitHubRepo.createRepo to apiClient.post with X-GitHub-Session forwarded; DeployWebappResponse is hoisted at module scope and the deployment_urls/is_first_deploy fallback lives in a single toGitHubRepoResult mapper.
  • Added a real UI-driven Playwright spec at tests/e2e/github-deploy.spec.ts that drives the production Deploy menu and asserts the captured request body carries projectExport.version === "2.0.0" and a non-empty project.diagrams map.
  • Object diagram now prefers the className label for user-model elements.
  • Late additions on top of the submodule bump: agent-diagram topbar collapse fix, agent-config mapping-collision warning on Save/Apply, transform timeout raised to 10min with surfaced TimeoutError, and ProjectHubDialog import-area accessibility/UX improvements.

B-UML Metamodel

  • Fixed Object._validate_object_completeness so a child class that only inherits attributes is still flagged when no slot values are provided. The check now calls classifier.attributes and classifier.inherited_attributes() directly (instead of guarding with hasattr/getattr defaults that masked real type bugs).

Testing

  • Backend full pytest suite: 771 passed, 5 skipped, 3 xfailed.
  • New unit tests cover user_profile_utils, agent_config_recommendation_utils, and agent_config_manual_mapping_utils.
  • New behavioral integration tests cover /recommend-agent-config-mapping, /recommend-agent-config-llm, and /deploy-webapp with deploy_target="agent".
  • Frontend vitest: 23/23 on shared/utils/__tests__/projectExportUtils.test.ts.
  • Added .github/codeql/codeql-config.yml excluding py/clear-text-storage-sensitive-data: the rule fires on the f.write(render_config) calls in the deploy paths because render.yaml references env-var KEY names (no password VALUES are written).

Frontend pair

Frontend submodule moves to BESSER-PEARL/BESSER-WEB-MODELING-EDITOR develop HEAD. Matching frontend release: BESSER-PEARL/BESSER-Web-Modeling-Editor#113.

v7.2.0

23 Apr 08:35
57da5dc

Choose a tag to compare

Minor release: ER notation support for class diagrams + one-to-many REST endpoints. Adds a display-only ER (Chen) rendering flavor for class diagrams in the Web Modeling Editor and closes a longstanding gap in the backend REST API generator where one-to-many relationships had no traversal endpoints. No metamodel or public API changes — ER is a client-side rendering flavor, and the REST endpoint work is additive.

Highlights

  • ER (Chen) notation for class diagrams (#508, WME PR #108): the Web Modeling Editor now supports an ER rendering flavor alongside the default UML notation, selectable from the Project Settings panel under Display. The setting is persisted in localStorage under besser-standalone-settings.classNotation and is rendering-only — the underlying model and its serialized multiplicities stay in UML form, so toggling back to UML is lossless. In ER mode, plain binary associations (bidirectional, unidirectional, aggregation, composition) are drawn with a named diamond at the midpoint of the line; inheritance, realization, OCL link, and dependency keep their UML rendering (explicit allow-list rather than an exclusion list, so new relationship types don't silently inherit the diamond). Multiplicities display in the Chen (min,max) form ((1,1), (0,N), (1,N)) while remaining stored as UML ranges; the association-update popover accepts either syntax as input and normalizes (0,N) / (1,1) to 0..* / 1..1 on save. Class and abstract-class classifiers drop the methods compartment (ER has no operations concept); enumerations and interfaces are explicitly excluded. Attributes marked with is_id render underlined. The toggle repaints the canvas live via the existing settingsService.onSettingsChange subscription in scenes/application.tsx. Shipped with 15 unit tests in multiplicity.test.ts covering the parseMultiplicity / toERCardinality / erCardinalityToUML helpers (including the round-trip invariant for canonical inputs) and a Playwright suite in tests/e2e/er-notation.spec.ts covering the radio-group toggle, localStorage persistence, and reload survival.

  • One-to-many relationship GET endpoints in the REST API generator (PR #509): the FastAPI backend generator was only emitting relationship-traversal endpoints for many-to-many associations, which meant generated BAL methods that walked one-to-many navigations could not actually resolve the target objects at runtime. backend_fast_api_template.py.j2 now emits a matching GET /<class>/{id}/<relationship>/ endpoint for every one-to-many association, mirroring the shape of the existing many-to-many block — 404 on missing parent, SQLAlchemy-filtered child query on the foreign-key column, response payload shaped as {<class>_id, <rel>_count, <rel>}. The endpoint is tagged "<Class> Relationships" so it groups correctly in the generated OpenAPI docs.

Frontend submodule bump

The frontend submodule moves from 279c8f8 to b8b522e — all 12 commits are part of the ER-notation feature branch (feature/er-notation-508). No unrelated commits piggy-back on this pointer move.

Testing

Backend: full suite passes against v7.1.7 baseline — the REST API generator change is covered by template-rendering tests (no new regressions). Frontend: 15 unit tests in multiplicity.test.ts plus the er-notation.spec.ts Playwright suite are additive; existing UML rendering tests continue to pass unchanged.

v7.1.7

21 Apr 14:19
0953e15

Choose a tag to compare

Version 7.1.7

Patch release: OCL parser fixes + IMG2UML merge-into-existing-model. Closes #198, #202, and #338. No metamodel or public API changes — the OCL work is a grammar fix plus a diagnostics layer, and the IMG2UML change adds an optional parameter while preserving the original behaviour when the active diagram is empty.

Highlights

  • OCL accepts attributes named size (closes #198): size is a reserved lexer keyword for the OCL ->size() / .size() collection operation, so any domain model with an attribute literally named size failed to parse with mismatched input '>' expecting '(' — the lexer tokenized the attribute name as SIZE and the parser insisted on LPAREN RPAREN after it. The reporter blamed inheritance because their repro had size on a parent class, but the bug fired identically on a direct attribute. Grammar fix: expression DOT SIZE #dotSizeNavigation added as a fallback rule below the existing DOT SIZE LPAREN RPAREN. ANTLR's longest-match keeps .size() winning when parens follow, so collection->size() and string.size() still parse unchanged. The visitor gains visitDotSizeNavigation that resolves size via the same property-lookup path as visitDotNavigation. Seven regression tests in tests/BUML/metamodel/ocl/test_size_attribute.py.
  • OCL parser emits actionable error messages (closes #202): the raw ANTLR diagnostics (mismatched input 'then' expecting <EOF>, missing ')' at '<EOF>') exposed internal parser state and used token names that mean little to someone writing an OCL constraint. The worst example from the issue — forgetting the if before then ... else ... — surfaced as Error: pop from empty list, which gives zero hint about what went wrong. besser/BUML/notations/ocl/error_handling.py now sits on top of ANTLR's error listener and rewrites diagnostics into OCL-level hints: Did you forget the 'if'?, Missing 'endif', Missing closing ')', operand on the right is missing, must start with 'context <ClassName> inv: ...', and so on. When no targeted pattern matches, the raw ANTLR message is kept as a fallback but reformatted into a consistent line N, column M: <msg> shape. Thirteen regression tests in tests/BUML/metamodel/ocl/test_error_messages.py pin every rewrite rule plus positive-parse sanity checks so the translation layer doesn't reject valid OCL.
  • IMG2UML extends an existing class diagram instead of replacing it (closes #338): when an image is uploaded while the active ClassDiagram already has elements, the image is now merged into the current model — same-name classes are preserved and only new attributes/methods/relationships from the image are appended, new classes are added with their own relationships. image_to_buml and image_to_plantuml gain an optional existing_model parameter; when supplied, a compact textual summary of the current classes, attributes, methods, associations and inheritance is included in the vision prompt with explicit merge rules so the LLM returns a single merged PlantUML chunk. /get-json-model-from-image carries an optional existing_model form field with the current diagram JSON, converted via process_class_diagram and forwarded down. The frontend submodule only sends the active ClassDiagram when it is non-empty, so empty-diagram imports keep the original "replace" behaviour.

Testing

Twenty new OCL tests (seven for the size keyword fix, thirteen for the error-message rewrites) cover every targeted pattern plus positive-parse guards. Full suite: 712 passed, 5 skipped, 3 xfailed — no regressions against v7.1.6.

v7.1.6

21 Apr 13:17
9a2cf73

Choose a tag to compare

Version 7.1.6

Minor release: identifier story overhaul + more permissive PlantUML importer. Closes #230, #225, #108, #236 and completes the is_id work from #478 / #486. Frontend submodule advances twice to expose the two new attribute checkboxes.

Highlights

  • New Property.is_external_id (closes #230, #225, #108): B-UML now distinguishes the internal surrogate PK (is_id) from user-facing identifiers (is_external_id). Composite keys supported. Flag round-trips through metamodel, JSON converters, and code builder. SQLAlchemy emits unique=True on non-PK external ids (subsumes #108's UNIQUE ask). Django emits unique=True and — crucially for #225 — uses external ids in __str__ so ForeignKey dropdowns show isbn / first_name - last_name instead of the PK.
  • is_id propagation completed (#478): PR #486 landed the metamodel + converters but deferred the builder, generators, and editor. Finished here: domain_model_to_code emits is_id=True, Django template emits primary_key=True, editor gains an ID checkbox (SQLAlchemy already worked).
  • PlantUML importer permissiveness (closes #236): grammar now accepts single-dash - associations, integer / boolean type aliases, and trailing < / > direction hints on labels. Lexer/parser regenerated with ANTLR 4.13.2.
  • Django template whitespace fix: pre-existing bug where the attribute for-loop stripped every newline — rendered models.py was invalid Python. Regression test compiles the output.
  • Editor UI (submodule c4252a6 → b5102c0): two new attribute-popup checkboxes (ID, External ID), {id} / {external id} markers in the display name, plus c50f6dc (attribute/method reorder — piggybacked on develop).

Testing

11 new tests: metamodel setter validation, JSON↔BUML round-trip, code-builder exec round-trip, SQLAlchemy schema introspection + real IntegrityError on duplicate external-id, Django field emission + __str__ variants + compile() sanity, and 5 PlantUML grammar regressions. Full suite: 692 passed, 5 skipped, 3 xfailed.

v7.1.5

21 Apr 11:02
5c3dbf2

Choose a tag to compare

Version 7.1.5

Patch release: the DB Agent template now generates without an internal server error. Backend-only fix — no metamodel, generator, or public API contract changes. The frontend submodule pointer is unchanged.

Highlights

  • DB Agent template generation no longer fails with NameError: name 'ReceiveTextEvent' is not defined: the shipped dbagent.json template has an event-only transition ("event": "ReceiveTextEvent" with no conditions), which agent_model_builder.agent_model_to_code emits as initial.when_event(ReceiveTextEvent()).go_to(db_reply). The generated module's import block pulled in Agent, AgentReply, LLMReply, RAGReply, DBReply and the LLM classes, but none of the *Event classes. generate_agent_files in generation_router.py then exec_module-ed the generated file and raised, which the frontend surfaced as a 500 on /besser_api/generate-output. The other four shipped templates (faqragagent, greetingagent, gymagent, libraryagent) hid the bug because they use intent-matcher transitions and the builder emits those as when_intent_matched(intent).go_to(...) without ever referencing the event class directly.
  • Fix: besser/utilities/buml_code_builder/agent_model_builder.py now adds ReceiveTextEvent, ReceiveFileEvent, ReceiveJSONEvent, ReceiveMessageEvent, WildcardEvent, and DummyEvent to the from besser.BUML.metamodel.state_machine.agent import ... line it writes into the generated agent_model.py. All six are already exported by besser.BUML.metamodel.state_machine.agent — this change only affects generated code, not runtime behavior of the builder itself.
  • Regression coverage: all five shipped agent templates (dbagent, faqragagent, greetingagent, gymagent, libraryagent) were round-tripped through process_agent_diagramgenerate_agent_files and each produces a valid agent_output.zip containing a syntactically valid agent_model.py and the BAFGenerator output bundle.

v7.1.4 — accept XLSX uploads in the Project Hub spreadsheet flow

21 Apr 10:29
5ec9a1c

Choose a tag to compare

Patch release: the "From Spreadsheet" project creation flow now accepts XLSX workbooks as advertised. Backend-only fix — no metamodel, generator, or public API contract changes. The frontend submodule pointer is unchanged.

Highlights

  • XLSX uploads in /besser_api/csv-to-domain-model no longer fail with "Unsupported file type '.xlsx'" (#501). The Project Hub "From Spreadsheet" dialog already exposed accept=".csv,.xlsx,.xls,..." on its file input and the copy promised "Auto-generate a class diagram from CSV/XLSX files", but the backend's _validate_upload whitelisted only {".csv"} and rejected everything else with a 415. conversion_router.py now carries an ALLOWED_SPREADSHEET_EXTENSIONS = {".csv", ".xlsx"} set, validates .xlsx content by checking the ZIP magic bytes (PK\x03\x04), and converts each uploaded workbook's first worksheet to a UTF-8 CSV via openpyxl inside the request's temp directory before handing the resulting path list to the existing csv_to_domain_model reverse engineer. csv_reverse.py itself is unchanged — the xlsx-to-csv normalization happens entirely in the endpoint.

  • New optional backend dependency: openpyxl >= 3.1.0 added to besser/utilities/web_modeling_editor/backend/requirements.txt (not the top-level requirements.txt — this only matters for the editor backend). The import is lazy inside the helper, so the rest of the backend stays importable when the package is missing; if a user uploads XLSX without openpyxl installed they get a clear 500 with installation instructions instead of a traceback.

  • Legacy .xls (BIFF) is deliberately not supported. Reading .xls would require the deprecated xlrd package (upstream dropped .xlsx support in 2.0 and warns against use for new work). Users who upload .xls get the same clear 415 as before, listing .csv, .xlsx as the allowed extensions.

  • Regression coverage in tests/utilities/web_modeling_editor/backend/test_spreadsheet_import.py: CSV upload still succeeds, XLSX upload succeeds and produces a ClassDiagram, unsupported extensions return 415 with both allowed extensions named in the error, and malformed XLSX (bad magic bytes) returns 400 before reaching openpyxl.

v7.1.3

15 Apr 14:24
c1bcf9c

Choose a tag to compare

Patch release.

Highlights

  • Standalone agent ZIP now contains the full BAF project. BAFGenerator was being constructed without an output_dir, so it wrote to <backend-CWD>/output instead of the request's temp dir. The downstream zipper walked the (empty) temp dir and shipped an agent_output.zip that only held the raw agent_model.py. Both constructor branches in _handle_agent_generation now pin output_dir to the request temp dir. WebApp-embedded agent flow was unaffected.
  • Modeling agent can now link new Object Diagram instances to their class. add_object dropped the reference classId entirely, so the update panel's "class:" dropdown always looked empty. ObjectDiagramModifier and ObjectDiagramConverter now carry classId / attributeId through to the created elements.
  • No more author2: Author : Author double rendering. After wiring classId through, the component started appending " : ClassName" on top of a name that already contained it. .name now holds only the bare instance name when classId is set.
  • Frontend submodule bump also pulls in: drag perf fix (fractional deltas), DeployResultDialog copy refresh, unified external URL handling, agent diagram title-uniqueness, more robust object removal.

Full release notes: docs/source/releases/v7/v7.1.3.rst

v7.1.2

14 Apr 17:47
5347889

Choose a tag to compare

Patch release: adds multi-agent support to the Full Web App generator and hardens the GitHub → Render deployment pipeline. No metamodel or API changes.

Highlights

  • Multi-agent Full Web App: projects with multiple AgentDiagrams now generate one agent per diagram under agents/<slug>/. GUI AgentComponents route per-component via a new VITE_AGENT_URLS JSON map. docker-compose.yml and render.yaml emit one service per agent.
  • Stable Render service names: the generator reuses the existing suffix from the repo's render.yaml on redeploy instead of minting a fresh one — no more zombie services on every push.
  • WebSocket auto-reconnect: the generated React AgentComponent retries on failure with backoff (2s → 30s, ~26 min budget), so cold-starting free-tier agents connect transparently without a manual refresh.
  • Agent-name uniqueness: adding a template that would collide auto-suffixes ("Library Agent""Library Agent 2"); manual renames to a duplicate are hard-blocked.

Bug Fixes

  • Underscore → dash hostname normalization: Render silently rewrites _ to - in subdomains. Both app_name and agent slugs are now converted up-front so the URLs baked into .env.production actually resolve.
  • 40-character hostname cap: Render truncates longer service names at dash boundaries, dropping our suffix. The new _fit_service_name() helper falls back to a deterministic besser-<12 hex> form (stable across redeploys) when the readable name would overflow.
  • Agent dropdown enumerates every AgentDiagram: getAgentOptions() used to return only the GUI diagram's per-diagram reference, collapsing multi-agent projects to one selectable agent.
  • Template add preserves auto-suffixed titles: TemplateLibraryDialog was re-applying the template's original title after addDiagram() returned a unique title, silently undoing the uniqueness resolution. Fixed.
  • Deploy result dialog now distinguishes first deploy (create-blueprint link) from redeploy (direct live-app link + Manual Sync guidance).