@kudzujs/core 0.16.10 → 0.16.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,6 +24,12 @@ Apache Answer's first route-shell gate replaces `RouterProvider` and nested `Out
24
24
 
25
25
  Apache Answer authoring/admin intake now builds native question creation and keyed administration without form, editor, query, or state package runtimes. Constraint-backed title/markdown fields, controlled preview, markdown file import, local draft mutation, keyed admin rows, and deletion compile through existing handlers/lists while a legal sibling remains JavaScript-free. Rich CodeMirror ownership, server validation, upload progress, and destructive confirmation remain later acceptance gates.
26
26
 
27
+ Apache Answer's reduced authentication, query, route, detail, create/edit, validation, refresh, administration, and logout paths now pass one connected deterministic browser journey. Existing layout-owned Zustand reduction, search signals, dependency effects, runtime parameters, native forms, keyed lists, enhanced navigation, and direct handlers preserve server-authoritative errors and mutations, edit persistence across reload, admin deletion refresh, accessible statuses, exact source retention, and a zero-JavaScript public sibling. No compiler, IR, runtime, package adapter, or public API changed; this remains a connected reduction rather than a whole-application migration claim.
28
+
29
+ Memos now has a first durable connected slice derived from pinned upstream source: invalid and valid login, loading and server error, overlapping-key pagination, explicit refresh, native memo creation, editing, deletion, reaction, realtime refresh, reload persistence, and logout pass one deterministic browser journey. Existing layout state, dependency effects, keyed ownership, native forms and handlers, enhanced navigation, and effect-owned WebSocket lifecycle retain one memo DOM node through error recovery, feed mutations, duplicate and stale events, reconnect, and fresh route ownership. Listener, socket, and reconnect-timer counts return to zero on release, and the public sibling remains JavaScript-free. No query runtime, Connect RPC client, React runtime, compiler semantic, or public API is added, and this remains a reduced application slice rather than a whole-Memos claim.
30
+
31
+ Actual Budget intake remains deferred at its pinned MIT revision. The available sparse acquisition omits required workspace tooling, component and backend packages, database and worker coordination, and spreadsheet implementation, so it cannot establish an executable user journey or honest whole-workspace retention denominator. No compatibility claim or speculative framework work is authorized until a complete pinned workspace is available.
32
+
27
33
  ## North Star
28
34
 
29
35
  An AI should be able to migrate ordinary React-shaped TypeScript and TSX to CDN-deployable static HTML, CSS, and only the route-specific ESM capabilities actually used, with minimal source restructuring.
@@ -51,7 +57,7 @@ Syntax compatibility does not mean reproducing React wholesale. Kudzu accepts th
51
57
  - stronger JavaScript failure resilience;
52
58
  - no remaining material large-route build-scaling weakness.
53
59
 
54
- The completed 0.9 plan defines the cross-framework comparison and release gate. The active application packet is `0.19.2` in the capability release plan below. Benchmark-only feature omission, unmatched accessibility, weighted scores that hide losses, and unrecorded environment differences do not count as proof.
60
+ The completed 0.9 plan defines the cross-framework comparison and release gate. The active application packet is `0.20.1` in the capability release plan below. Benchmark-only feature omission, unmatched accessibility, weighted scores that hide losses, and unrecorded environment differences do not count as proof.
55
61
 
56
62
  ### 0.10.0 Through 0.21.x: Application Capability Release Train
57
63
 
package/PERFORMANCE.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  Reproducibility classes: `npm run benchmark`, `npm run benchmark:keyed`, `npm run benchmark:native`, `npm run benchmark:module-cache`, `npm run benchmark:project-navigation`, `npm run benchmark:project-state`, and `npm run benchmark:source-scale` are maintained in this repository; `npm run benchmark:commerce` is a maintained paired runner over the public external storefront; older excluded-workspace sections are historical provenance only and are not current framework rankings.
4
4
 
5
+ ## 0.16.11 Structured Compiler Diagnostics
6
+
7
+ Measured 2026-08-31 on Linux x64 with Node 24.14.0. Structured diagnostics are
8
+ compiler and CLI output only; all representative deploy manifests, route bytes,
9
+ and hashes remain unchanged. The maintained Worker graph remains 907 raw / 477
10
+ gzip B and the window graph remains 14,456 raw / 6,160 gzip B. Seven clean
11
+ release-candidate builds record a 1,034.4 ms median on this loaded host; timing is
12
+ not compared.
13
+ The complete browser-disabled and required-Chrome suites pass 293/293 tests,
14
+ focused JSON CLI and human diagnostic tests pass, and package smoke builds one
15
+ static page with zero interactive pages.
16
+
5
17
  ## 0.16.10 Apache Answer Authentication Journey
6
18
 
7
19
  Measured 2026-08-31 on Linux x64 with Node 24.14.0 and required Chrome. The
package/README.md CHANGED
@@ -14,7 +14,7 @@ Kudzu compiles ordinary React-shaped TypeScript and TSX into complete static HTM
14
14
 
15
15
  > Experimental `0.16.x`: the compiler API and supported TSX surface may change.
16
16
 
17
- **Latest release: 0.16.10 - Apache Answer authentication journey.** The existing layout-owned session reduction now passes anonymous, invalid and valid login, reload restoration, shared settings, and 401 replacement navigation against a deterministic server without compiler or browser-output changes. Read the [release notes](./RELEASES.md#01610---apache-answer-authentication-journey), open the [release page](https://github.com/kudzujs/kudzu/releases/tag/v0.16.10), or follow the [architecture packet](./docs/next-architecture/README.md).
17
+ **Latest release: 0.16.11 - Structured compiler diagnostics.** `kudzu build --json` now emits stable codes, semantic stages, exact authored-source ranges, compatibility classes, and safe suggestions while ordinary human diagnostics and browser output remain unchanged. Read the [release notes](./RELEASES.md#01611---structured-compiler-diagnostics), open the [release page](https://github.com/kudzujs/kudzu/releases/tag/v0.16.11), or follow the [architecture packet](./docs/next-architecture/README.md).
18
18
 
19
19
  - [Documentation](https://kudzujs.cloud/docs)
20
20
  - [Installation guide](https://kudzujs.cloud/docs#install)
package/RELEASES.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # Kudzu Releases
2
2
 
3
+ ## 0.16.11 - Structured Compiler Diagnostics
4
+
5
+ Kudzu 0.16.11 gives tools and agents stable machine-readable authored-source
6
+ errors without replacing concise human diagnostics or exposing compiler internals.
7
+
8
+ ### Changed in 0.16.11
9
+
10
+ - Adds `kudzu build --json`, which emits one versioned diagnostic envelope with
11
+ stable semantic code, stage, severity, project-relative source range, message,
12
+ nullable compatibility class, and nullable safe suggestion.
13
+ - Preserves readable source-located build and development errors; agents no
14
+ longer need to parse maintained error-message substrings.
15
+ - Covers unresolved imports and re-exports, unsupported dynamic imports,
16
+ TypeScript syntax errors, runtime-locale `react-i18next`, and invalid keyed-row
17
+ ref initializers through the shared diagnostic transport.
18
+ - Reuses the existing compatibility registry and keeps pass filenames, generated
19
+ source, IR slots, runtime records, and stack traces out of machine output.
20
+ - Adds no semantic primitive, compiler pass, runtime concept, browser module, or
21
+ deploy byte. Representative artifact manifests and hashes remain unchanged.
22
+ - Updates `create-kudzu@0.1.136` to generate projects on
23
+ `@kudzujs/core@^0.16.11`.
24
+
25
+ ### Upgrade
26
+
27
+ ```sh
28
+ npm install @kudzujs/core@^0.16.11
29
+ ```
30
+
3
31
  ## 0.16.10 - Apache Answer Authentication Journey
4
32
 
5
33
  Kudzu 0.16.10 promotes the existing Apache Answer authentication reduction from
package/bin/kudzu.mjs CHANGED
@@ -16,7 +16,16 @@ if (command === "build" && !process.env.KUDZU_BUILD_CHILD) {
16
16
  } else if (command === "build" || command === "dev") {
17
17
  module.enableCompileCache?.()
18
18
  const { build, dev } = await import("../framework/build.mjs")
19
- await (command === "build" ? build : dev)()
19
+ const json = command === "build" && process.argv.includes("--json")
20
+ try {
21
+ await (command === "build" ? build({ quiet: json }) : dev())
22
+ } catch (error) {
23
+ const { diagnosticEnvelope } = await import("../framework/compiler/diagnostics.mjs")
24
+ const envelope = diagnosticEnvelope(error)
25
+ if (!envelope) throw error
26
+ console.error(json ? JSON.stringify(envelope) : error.message)
27
+ process.exitCode = 1
28
+ }
20
29
  } else {
21
30
  console.error(`Unknown command: ${command}\nUse: kudzu <build|dev>`)
22
31
  process.exitCode = 1
@@ -15,7 +15,7 @@ The completed `0.9.0` milestone is recorded in [`0.9-semantic-compression.md`](.
15
15
 
16
16
  [`1.0-large-application-compatibility-audit.md`](./1.0-large-application-compatibility-audit.md) records the first post-0.9 probes against Memos, Apache Answer, and Actual Budget. The audit finds that reduced slices build but whole-application source retention and behavior parity do not yet pass.
17
17
 
18
- [`application-capability-release-plan.md`](./application-capability-release-plan.md) is the authoritative post-0.9 execution queue, currently at `0.19.2`. It assigns one application-capability section to each minor release and one independently accepted evidence packet to each patch release from `0.10.0` through the `1.0.0` gate. It supersedes the provisional 0.10/0.11/0.12 tool-first ordering in the completed 0.9 handoff without rewriting that historical record.
18
+ [`application-capability-release-plan.md`](./application-capability-release-plan.md) is the authoritative post-0.9 execution queue, currently at `0.20.1`. It assigns one application-capability section to each minor release and one independently accepted evidence packet to each patch release from `0.10.0` through the `1.0.0` gate. It supersedes the provisional 0.10/0.11/0.12 tool-first ordering in the completed 0.9 handoff without rewriting that historical record.
19
19
 
20
20
  ## Required Invariants
21
21
 
@@ -1679,6 +1679,27 @@ retain the public `0.16.x` line.
1679
1679
  introduced.
1680
1680
  - **Done condition:** this is a connected browser journey, not a whole-app claim.
1681
1681
 
1682
+ Complete. One Apache Answer-derived fixture now connects invalid and valid login,
1683
+ layout-shared authentication, page/order query loading, explicit refresh, native
1684
+ creation with server validation and retained draft, runtime detail routing,
1685
+ editing, reload persistence, keyed administration, delete-and-refetch, and
1686
+ logout against one deterministic server. Native controls and status/alert
1687
+ regions preserve the accessibility boundary, every retained source file is
1688
+ checked, and the public sibling remains complete HTML with zero JavaScript.
1689
+
1690
+ The packet reuses existing Zustand normalization, search signals, dependency
1691
+ effects, runtime parameters, native handlers, bindings, keyed ownership, and
1692
+ enhanced navigation. It adds zero semantic primitives, ModuleIR kinds, compiler
1693
+ passes or core LOC, runtime concepts, package adapters, and public APIs. The new
1694
+ fixture emits 33 deploy files and 88,198 raw / 33,173 gzip bytes; `/` owns 27,196
1695
+ raw / 11,968 gzip bytes, `/questions` owns 51,577 raw / 19,801 gzip bytes,
1696
+ `/questions/add` owns 27,109 raw / 11,893 gzip bytes, runtime detail owns 32,783
1697
+ raw / 14,056 gzip bytes, admin owns 50,861 raw / 19,426 gzip bytes, and `/public`
1698
+ owns zero JavaScript. Worker and window graphs remain 907 raw / 477 gzip and
1699
+ 14,456 raw / 6,160 gzip bytes; seven clean Linux x64 builds record a 640.5 ms
1700
+ median without a timing comparison. No production logic changed, so the public
1701
+ version remains `0.16.10` and no release is consumed.
1702
+
1682
1703
  ### `0.19.3`: Memos Feed And CRUD Journey
1683
1704
 
1684
1705
  - **Purpose:** establish the first durable Memos application slice.
@@ -1689,6 +1710,26 @@ retain the public `0.16.x` line.
1689
1710
  - **Done condition:** pinned upstream provenance and exact retained source are
1690
1711
  recorded.
1691
1712
 
1713
+ Complete. A fixture pinned to Memos revision
1714
+ `e5ed6e7ec60e141d6e354f3ab59906c2c47dccac` now runs invalid and valid login,
1715
+ initial loading, a server pagination failure, explicit recovery, overlapping-key
1716
+ pagination, create, edit, delete, reload persistence, and logout against one
1717
+ deterministic server. The retained memo row keeps DOM identity through the
1718
+ failed request, successful pagination, and every CRUD refetch. Native labels,
1719
+ status and alert regions preserve the accessibility boundary, every authored
1720
+ source file is retained, and the public sibling emits zero JavaScript.
1721
+
1722
+ The packet reuses existing Zustand normalization, dependency effects, keyed
1723
+ ownership, native forms and handlers, and enhanced navigation. It adds zero
1724
+ semantic primitives, ModuleIR kinds, compiler passes or core LOC, runtime
1725
+ concepts, package adapters, and public APIs. The fixture emits 19 deploy files
1726
+ and 56,167 raw / 21,634 gzip bytes; `/` owns 25,856 raw / 11,396 gzip bytes,
1727
+ `/feed` owns 45,690 raw / 17,836 gzip bytes, and `/public` owns zero JavaScript.
1728
+ Worker and window graphs remain 907 raw / 477 gzip and 14,456 raw / 6,160 gzip
1729
+ bytes; seven clean Linux x64 builds record a 761.8 ms median without a timing
1730
+ comparison. No production logic changed, so the public version remains
1731
+ `0.16.10` and no release is consumed.
1732
+
1692
1733
  ### `0.19.4`: Memos Realtime Journey
1693
1734
 
1694
1735
  - **Purpose:** add reaction and realtime refresh using the accepted long-lived
@@ -1698,6 +1739,27 @@ retain the public `0.16.x` line.
1698
1739
  - **Stop condition:** a query or SSE package runtime is copied wholesale.
1699
1740
  - **Done condition:** browser and endurance acceptance pass.
1700
1741
 
1742
+ Complete. The connected Memos fixture now adds a native reaction mutation and
1743
+ an effect-owned WebSocket that refreshes the keyed feed from versioned server
1744
+ events. Required Chrome proves duplicate and stale version rejection, old-socket
1745
+ callback rejection after reconnect, retained memo DOM identity, exact route
1746
+ cleanup, and fresh ownership after re-entry and reload. Active sockets,
1747
+ listeners, and reconnect timers remain bounded and return to zero after each
1748
+ owner release. The public sibling remains complete HTML with zero JavaScript.
1749
+
1750
+ The packet reuses existing native handlers, keyed ownership, effect-private
1751
+ lifecycle, invalidation, timers, and route release. It adds zero semantic
1752
+ primitives, ModuleIR kinds, compiler passes or core LOC, runtime concepts,
1753
+ normalization or adapter rules, and public APIs. The fixture emits 19 deploy
1754
+ files and 57,811 raw / 22,069 gzip bytes; `/` owns 25,856 raw / 11,396 gzip
1755
+ bytes, `/feed` owns 46,740 raw / 18,184 gzip bytes, and `/public` owns zero
1756
+ JavaScript. Worker and window graphs remain 907 raw / 477 gzip and 14,456 raw /
1757
+ 6,160 gzip bytes; seven clean Linux x64 builds record a 620.7 ms median without
1758
+ a timing comparison. Browser-disabled tests pass 292/292, required-Chrome
1759
+ focused acceptance, package smoke, and artifact accounting pass. No production
1760
+ logic changed, so the public version remains `0.16.10` and no release is
1761
+ consumed.
1762
+
1701
1763
  ### `0.19.5`: Actual Budget Intake Decision
1702
1764
 
1703
1765
  - **Purpose:** determine whether a complete, legally and technically usable
@@ -1708,6 +1770,18 @@ retain the public `0.16.x` line.
1708
1770
  - **Done condition:** a later packet is authorized, or deferral is recorded with
1709
1771
  no compatibility claim.
1710
1772
 
1773
+ Deferred by the stop condition. The pinned MIT revision
1774
+ `87e33e49eb4d666c33e0c0f172faf340d1b7aa0a` remains only a sparse desktop-client
1775
+ acquisition: 810 TS/TSX modules, 163,344 LOC, and 80 route declarations without
1776
+ the workspace tooling, component library, core backend, Yarn release, database,
1777
+ worker coordinator, or spreadsheet implementation needed to install and run an
1778
+ honest user journey. The prior static report probe is an exported report, not
1779
+ Actual Budget, and its 22/906 retained-line result is not a whole-workspace
1780
+ denominator. No later application packet, compatibility claim, compiler work,
1781
+ runtime, package adapter, public API, version, or release is authorized. Intake
1782
+ may resume only from a complete pinned workspace and executable dependency
1783
+ graph.
1784
+
1711
1785
  ## `0.20.x`: AI Tooling And Delivery Cost
1712
1786
 
1713
1787
  ### `0.20.0`: Structured Diagnostics
@@ -1719,6 +1793,30 @@ retain the public `0.16.x` line.
1719
1793
  - **Done condition:** agents no longer parse message substrings for maintained
1720
1794
  fixtures.
1721
1795
 
1796
+ Complete. Authored
1797
+ source failures now propagate as one versioned diagnostic envelope with stable
1798
+ semantic code, stage, severity, project-relative source range, human message,
1799
+ nullable compatibility class, and nullable safe suggestion. `kudzu build
1800
+ --json` emits only that deterministic envelope for structured failures, while
1801
+ ordinary builds and the development overlay retain readable source-located
1802
+ messages. Unresolved imports and re-exports, unsupported dynamic imports,
1803
+ TypeScript syntax errors, runtime-locale `react-i18next`, and keyed-row ref
1804
+ initializers prove the maintained boundary without parsing message text.
1805
+
1806
+ The implementation centralizes 72 lines in `diagnostics.mjs`, reuses the
1807
+ existing compatibility classification function, and normalizes paths only at
1808
+ the project build boundary. It adds zero semantic primitives, ModuleIR kinds,
1809
+ compiler passes, normalization entries, runtime concepts, browser modules, or
1810
+ public application APIs. Production source is +111 net lines, including +8 in
1811
+ the measured core semantic file set; the increase is compiler/tooling error
1812
+ transport rather than semantic analysis. All representative deploy manifests
1813
+ and hashes remain unchanged. Worker and window graphs remain 907 raw / 477 gzip
1814
+ and 14,456 raw / 6,160 gzip bytes; seven clean Linux x64 release-candidate builds
1815
+ record a 1,034.4 ms median without a timing comparison. `npm run check`, 293/293
1816
+ browser-disabled and required-Chrome tests, focused CLI JSON tests, development error recovery, package smoke,
1817
+ artifact accounting, and `git diff --check` pass. The packet ships as
1818
+ `@kudzujs/core@0.16.11` with `create-kudzu@0.1.136`.
1819
+
1722
1820
  ### `0.20.1`: `kudzu inspect --json`
1723
1821
 
1724
1822
  - **Purpose:** expose reachable application and compatibility inventory.
@@ -1948,3 +2046,8 @@ release transaction where possible or document and publish a forward-fix patch.
1948
2046
  | `0.18.3` | Released as `0.16.8` | Preserve shared deferred ownership, interaction-only loading, native document module-map deduplication, exact owner cleanup, binding-aware import validation, and static exclusion. | Patch release retained the `0.16.x` public version line |
1949
2047
  | `0.19.0` | Released as `0.16.9` | Preserve the compatibility registry, reachable source inventory, exact ranges, and package-neutral output boundary. | Patch release retained the `0.16.x` public version line |
1950
2048
  | `0.19.1` | Released as `0.16.10` | Preserve anonymous, invalid/valid login, token restore, layout-shared session reads, 401 clear, replacement navigation, and public zero-JavaScript output. | Patch release retained the `0.16.x` public version line |
2049
+ | `0.19.2` | Closed by existing semantics | Preserve connected auth, query, route, create/edit validation, refresh, persistence, admin deletion, logout, source retention, accessibility, and public zero-JavaScript output. | No production change; no release consumed |
2050
+ | `0.19.3` | Closed by existing semantics | Preserve connected Memos login, loading/error, feed, overlapping-key pagination, refresh, CRUD, reload persistence, logout, source retention, accessibility, and public zero-JavaScript output. | No production change; no release consumed |
2051
+ | `0.19.4` | Closed by existing effect ownership | Preserve reaction mutation, version deduplication, stale-socket rejection, reconnect, keyed identity, exact route cleanup, fresh ownership, bounded handles/listeners/timers, and public zero-JavaScript output. | No production change; no release consumed |
2052
+ | `0.19.5` | Deferred by stop condition | Resume only from a complete pinned Actual Budget workspace with an executable dependency graph and honest retention denominator. | Sparse acquisition omits required workspace and core packages; no compatibility claim |
2053
+ | `0.20.0` | Released as `0.16.11` | Preserve stable diagnostic schema/codes, authored ranges, human errors, compatibility reuse, and zero browser/output delta. | Patch release retained the `0.16.x` public version line |
@@ -1,6 +1,6 @@
1
1
  # Current Compiler Architecture
2
2
 
3
- This maps the current `0.16.10` architecture, built on the completed `0.9.0` semantic-compression release and `0.8.23` Goal A compiler foundation. The active application packet is `0.19.2`; file and function names are the stable references, while line numbers are intentionally omitted because later work may still move code.
3
+ This maps the current `0.16.11` architecture, built on the completed `0.9.0` semantic-compression release and `0.8.23` Goal A compiler foundation. The active application packet is `0.20.1`; file and function names are the stable references, while line numbers are intentionally omitted because later work may still move code.
4
4
 
5
5
  ## Responsibility Map
6
6
 
@@ -12,6 +12,7 @@ This maps the current `0.16.10` architecture, built on the completed `0.9.0` sem
12
12
  | Build orchestration | [`framework/build.mjs`](../../framework/build.mjs), `build()`, `buildWithSession()` | Coordinates config, discovery, source compilation, RouteBuildRecord collection, CapabilityIR projection, generator invocation, artifact emission, and `afterBuild`. A retained session caches source results and pre-family route renders by page graph; successful builds alone replace that cache. |
13
13
  | Reachability/import resolution | [`framework/compiler/source-compiler.mjs`](../../framework/compiler/source-compiler.mjs), `reachableSourceFiles()`; [`framework/compiler/source-graph.mjs`](../../framework/compiler/source-graph.mjs), `ordinaryRuntimeDependencies()`, `resolveSourceImport()` | Starts from page entries, follows relative runtime imports/re-exports and validated Worker references, excludes unreachable migration source, and fails unresolved ordinary edges or dynamic imports at the importer source location before code generation. A lazy package edge must resolve lexically to a named React or Kudzu `useEffect` import. |
14
14
  | Compatibility inventory | [`framework/compiler/compatibility-registry.mjs`](../../framework/compiler/compatibility-registry.mjs), `createCompatibilityReport()` | Classifies package/API sites in reachable original source as Native, Compiled, Normalized, Adapter, Owned External UI, Partial, or Unsupported and writes deterministic source ranges to `.kudzu/kudzu-compatibility.json`. Package provenance ends here and never enters semantic IR or browser output. |
15
+ | Structured diagnostics | [`framework/compiler/diagnostics.mjs`](../../framework/compiler/diagnostics.mjs), `KudzuDiagnosticError`, `diagnosticEnvelope()` | Carries versioned stable codes, semantic stages, severity, authored source ranges, messages, nullable compatibility classes, and safe suggestions through programmatic builds. Build-boundary path normalization keeps JSON project-relative; human compiler and development messages retain their existing source context. Internal IR and artifact invariants remain ordinary errors. |
15
16
  | Ordered normalization | [`framework/compiler/normalization-pipeline.mjs`](../../framework/compiler/normalization-pipeline.mjs), `applyNormalizationPasses()`; [`framework/compiler/source-compiler.mjs`](../../framework/compiler/source-compiler.mjs), `normalizeCompilerSource()` | Applies migration/resource passes in order and repairs TypeScript parent pointers after every structural change. Imported source uses the same pipeline. |
16
17
  | Focused normalization passes | [`framework/compiler/`](../../framework/compiler/) | React, Router, browser signals, animation-frame refs, custom-hook timers, Zustand, and render control each validate and lower a narrow source shape. |
17
18
  | Shared AST/scope helpers | [`framework/compiler/ast-helpers.mjs`](../../framework/compiler/ast-helpers.mjs) | Binding, scope, reference, inclusive ancestry, effect-return, and source-location analysis. |
@@ -2,9 +2,9 @@
2
2
 
3
3
  ## Status
4
4
 
5
- Completed compiler-foundation record and longer-term plan after `0.8.35`. The [`0.9-semantic-compression.md`](./0.9-semantic-compression.md) execution queue is complete. The active queue for current work is [`application-capability-release-plan.md`](./application-capability-release-plan.md) at packet `0.19.2`. This document does not mark any remaining planned capability as supported and does not authorize a React runtime, VDOM, hydration, retained browser component tree, generic rerenderer, public store/query/resource API, SPA router, or islands.
5
+ Completed compiler-foundation record and longer-term plan after `0.8.35`. The [`0.9-semantic-compression.md`](./0.9-semantic-compression.md) execution queue is complete. The active queue for current work is [`application-capability-release-plan.md`](./application-capability-release-plan.md) at packet `0.20.1`. This document does not mark any remaining planned capability as supported and does not authorize a React runtime, VDOM, hydration, retained browser component tree, generic rerenderer, public store/query/resource API, SPA router, or islands.
6
6
 
7
- [`MIGRATION_ROADMAP.md`](../../MIGRATION_ROADMAP.md) remains the product authority for product invariants and fixture-driven feature selection. [`application-capability-release-plan.md`](./application-capability-release-plan.md) is authoritative for current work order and evidence at packet `0.19.2`; this plan retains the completed foundation, deferred program, and long-term production gates. If implementation evidence changes either boundary, update the relevant document before broadening a patch.
7
+ [`MIGRATION_ROADMAP.md`](../../MIGRATION_ROADMAP.md) remains the product authority for product invariants and fixture-driven feature selection. [`application-capability-release-plan.md`](./application-capability-release-plan.md) is authoritative for current work order and evidence at packet `0.20.1`; this plan retains the completed foundation, deferred program, and long-term production gates. If implementation evidence changes either boundary, update the relevant document before broadening a patch.
8
8
 
9
9
  ## Product Outcome
10
10
 
@@ -483,4 +483,4 @@ The first comparison is Kudzu versus React + Vite using the same agent, model, t
483
483
 
484
484
  ## Immediate Decision
485
485
 
486
- All listed foundation and `0.9` slices are complete. Current work continues at `0.19.2` Apache Answer Connected Authoring Journey under the [`application-capability-release-plan.md`](./application-capability-release-plan.md); keep ResourceIR limited to qualifying independent fixtures, and do not add range ownership, virtualization, optimistic transactions, a public adapter/store API, or a router before evidence justifies them.
486
+ All listed foundation and `0.9` slices are complete. Current work continues at `0.20.1` `kudzu inspect --json` under the [`application-capability-release-plan.md`](./application-capability-release-plan.md); keep ResourceIR limited to qualifying independent fixtures, and do not add range ownership, virtualization, optimistic transactions, a public adapter/store API, or a router before evidence justifies them.
@@ -1,6 +1,6 @@
1
1
  # Planned Version Sequence
2
2
 
3
- This is an execution sequence, not release history. `0.8.16` through `0.8.62` are completed scopes represented by package/release records. The `0.10.0` through `1.0.0` minor/patch sequence is maintained in [`application-capability-release-plan.md`](./application-capability-release-plan.md), currently at `0.19.2`; that plan supersedes the provisional tool-first 0.10/0.11/0.12 ordering in the completed 0.9 handoff.
3
+ This is an execution sequence, not release history. `0.8.16` through `0.8.62` are completed scopes represented by package/release records. The `0.10.0` through `1.0.0` minor/patch sequence is maintained in [`application-capability-release-plan.md`](./application-capability-release-plan.md), currently at `0.20.1`; that plan supersedes the provisional tool-first 0.10/0.11/0.12 ordering in the completed 0.9 handoff.
4
4
 
5
5
  Keep each patch behavior-preserving and independently reviewable. If a boundary proves inseparable, revise this plan before combining releases; do not silently broaden a patch.
6
6
 
@@ -66,7 +66,7 @@ Keep each patch behavior-preserving and independently reviewable. If a boundary
66
66
 
67
67
  ## Generator Versions
68
68
 
69
- `create-kudzu@0.1.135` retains the explicit install instructions and generates projects with `@kudzujs/core@^0.16.10`.
69
+ `create-kudzu@0.1.136` retains the explicit install instructions and generates projects with `@kudzujs/core@^0.16.11`.
70
70
 
71
71
  ## Release Boundary
72
72
 
@@ -5,6 +5,7 @@ import { pathToFileURL } from "node:url"
5
5
  import { build as bundle, transform } from "esbuild"
6
6
  import { createEffectCodegen } from "./compiler/effect-codegen.mjs"
7
7
  import { createCompatibilityReport } from "./compiler/compatibility-registry.mjs"
8
+ import { normalizeDiagnosticError } from "./compiler/diagnostics.mjs"
8
9
  import { generateListRuntime } from "./compiler/list-runtime-codegen.mjs"
9
10
  import { assetPath, browserPath, relativeModulePath, withBase } from "./compiler/path-helpers.mjs"
10
11
  import { createProjectSession } from "./compiler/project-session.mjs"
@@ -51,6 +52,8 @@ export async function buildWithSession(project, { changedFiles, quiet = false, m
51
52
  project.buildCache = retainCache ? cache : undefined
52
53
  if (!quiet) console.log(`Built ${pageCount} page(s), ${behaviorCount} interactive page(s) into dist/`)
53
54
  return result
55
+ } catch (error) {
56
+ throw normalizeDiagnosticError(error, root)
54
57
  } finally {
55
58
  try {
56
59
  await rm(stagedOutput, { recursive: true, force: true })
@@ -1,4 +1,5 @@
1
1
  import ts from "typescript"
2
+ import { createDiagnosticError } from "./diagnostics.mjs"
2
3
 
3
4
  export function importDeclarationNames(statement) {
4
5
  const names = []
@@ -146,11 +147,22 @@ export function functionVarDeclaresName(fn, name) {
146
147
  return found
147
148
  }
148
149
 
149
- export function sourceNodeError(node, fallbackSource, message) {
150
+ export function sourceNodeError(node, fallbackSource, message, metadata = {}) {
150
151
  const original = ts.getOriginalNode(node)
151
152
  const sourceFile = original.getSourceFile?.()?.fileName ? original.getSourceFile() : fallbackSource
152
- const position = sourceFile.getLineAndCharacterOfPosition(original.getStart(sourceFile))
153
- return new Error(`${sourceFile.fileName}:${position.line + 1}:${position.character + 1} ${message}`)
153
+ const startOffset = original.getStart(sourceFile)
154
+ const endOffset = original.getEnd()
155
+ const start = sourceFile.getLineAndCharacterOfPosition(startOffset)
156
+ const end = sourceFile.getLineAndCharacterOfPosition(endOffset)
157
+ return createDiagnosticError({
158
+ message,
159
+ source: {
160
+ file: sourceFile.fileName,
161
+ start: { line: start.line + 1, column: start.character + 1, offset: startOffset },
162
+ end: { line: end.line + 1, column: end.character + 1, offset: endOffset },
163
+ },
164
+ ...metadata,
165
+ })
154
166
  }
155
167
 
156
168
  export function sourceLocation(node, fallbackSource) {
@@ -46,7 +46,7 @@ function compatibilitySites(file, source) {
46
46
  const sites = []
47
47
  const add = (target, imported, local, kind, node) => {
48
48
  if (!isBarePackage(target) || target === "@kudzujs/core" || target.startsWith("@kudzujs/core/")) return
49
- const rule = classify(target, imported, kind)
49
+ const rule = classifyCompatibility(target, imported, kind)
50
50
  const start = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile))
51
51
  const end = sourceFile.getLineAndCharacterOfPosition(node.getEnd())
52
52
  sites.push({
@@ -94,7 +94,7 @@ function compatibilitySites(file, source) {
94
94
  return sites
95
95
  }
96
96
 
97
- function classify(target, imported, kind) {
97
+ export function classifyCompatibility(target, imported, kind) {
98
98
  if (kind === "re-export") return { id: "package.re-export.unsupported", classification: "Unsupported" }
99
99
  if (kind === "side-effect-import") return { id: "package.side-effect.unsupported", classification: "Unsupported" }
100
100
  const root = packageRoot(target)
@@ -0,0 +1,72 @@
1
+ import { isAbsolute, relative, sep } from "node:path"
2
+
3
+ export class KudzuDiagnosticError extends Error {
4
+ constructor(diagnostics) {
5
+ super(diagnostics.map(formatDiagnostic).join("\n"))
6
+ this.diagnostics = diagnostics
7
+ }
8
+ }
9
+
10
+ export function createDiagnosticError(diagnostic) {
11
+ return new KudzuDiagnosticError([{
12
+ code: "source.unsupported",
13
+ stage: "analyze",
14
+ severity: "error",
15
+ compatibilityClass: null,
16
+ suggestion: null,
17
+ ...diagnostic,
18
+ }])
19
+ }
20
+
21
+ export function createTypeScriptDiagnosticError(errors, flattenMessage) {
22
+ return new KudzuDiagnosticError(errors.map(error => {
23
+ const sourceFile = error.file
24
+ const startOffset = error.start ?? 0
25
+ const endOffset = startOffset + (error.length ?? 0)
26
+ const start = sourceFile?.getLineAndCharacterOfPosition(startOffset)
27
+ const end = sourceFile?.getLineAndCharacterOfPosition(endOffset)
28
+ return {
29
+ code: "source.syntax.invalid",
30
+ stage: "analyze",
31
+ severity: "error",
32
+ compatibilityClass: null,
33
+ suggestion: null,
34
+ message: flattenMessage(error.messageText),
35
+ ...(sourceFile && start && end ? { source: {
36
+ file: sourceFile.fileName,
37
+ start: { line: start.line + 1, column: start.character + 1, offset: startOffset },
38
+ end: { line: end.line + 1, column: end.character + 1, offset: endOffset },
39
+ } } : {}),
40
+ }
41
+ }))
42
+ }
43
+
44
+ export function normalizeDiagnosticError(error, root) {
45
+ if (!(error instanceof KudzuDiagnosticError)) return error
46
+ const normalized = new KudzuDiagnosticError(error.diagnostics.map(diagnostic => ({
47
+ ...diagnostic,
48
+ source: diagnostic.source && {
49
+ ...diagnostic.source,
50
+ file: normalizeFile(diagnostic.source.file, root),
51
+ },
52
+ })))
53
+ normalized.message = error.message
54
+ return normalized
55
+ }
56
+
57
+ export function diagnosticEnvelope(error) {
58
+ if (!(error instanceof KudzuDiagnosticError)) return undefined
59
+ return { version: 1, diagnostics: error.diagnostics }
60
+ }
61
+
62
+ function normalizeFile(file, root) {
63
+ if (!isAbsolute(file)) return file.replaceAll(sep, "/")
64
+ const path = relative(root, file)
65
+ return (path.startsWith("..") ? file : path).replaceAll(sep, "/")
66
+ }
67
+
68
+ function formatDiagnostic(diagnostic) {
69
+ const start = diagnostic.source?.start
70
+ const location = diagnostic.source ? `${diagnostic.source.file}${start ? `:${start.line}:${start.column}` : ""} ` : ""
71
+ return `${location}${diagnostic.message}`
72
+ }
@@ -11,6 +11,7 @@ import { analyzeCollectionPipeline, collectionExpression, collectionParameters,
11
11
  import { compatibilityPackages } from "./compatibility-registry.mjs"
12
12
  import { normalizeCustomHookTimerRefs } from "./custom-hook-timer-pass.mjs"
13
13
  import { captureNames, createDescriptorSession, createSemanticArtifact, nativeCaptureNames, referencedReducerDispatches, referencedStateNames } from "./descriptor-session.mjs"
14
+ import { createTypeScriptDiagnosticError } from "./diagnostics.mjs"
14
15
  import { analyzeEffectDependencies, validateEffectOwnedBrowserResources } from "./effect-analysis.mjs"
15
16
  import { createHandlerCodegen } from "./handler-codegen.mjs"
16
17
  import { createHandlerLowering } from "./handler-lowering.mjs"
@@ -62,7 +63,7 @@ function compileSource(file, sourceFiles, sourceIndex, staticFiles, cssModules,
62
63
 
63
64
  const errors = result.diagnostics?.filter(diagnostic => diagnostic.category === ts.DiagnosticCategory.Error) ?? []
64
65
  if (errors.length) {
65
- throw new Error(errors.map(error => ts.flattenDiagnosticMessageText(error.messageText, "\n")).join("\n"))
66
+ throw createTypeScriptDiagnosticError(errors, message => ts.flattenDiagnosticMessageText(message, "\n"))
66
67
  }
67
68
  const packageReference = emittedPackageReference(result.outputText, file, new Set(["react", "react-router-dom"]))
68
69
  if (packageReference) throw new Error(`${relative(root, file)} Runtime ${packageReference} module references are not supported`)
@@ -404,7 +405,11 @@ function createKudzuTransformer({ semantic, handlerUrl, file, sourceFiles, sourc
404
405
  for (const [name, binding] of packageBindings) {
405
406
  const references = referenceIdentifiers(sourceFile, name)
406
407
  const invalid = references.find(reference => !insideJsxEventHandler(reference, sourceFile) && !insideOwnedEffectCallback(reference, sourceFile))
407
- if (invalid && binding.target === compatibilityPackages.reactI18next && binding.imported === "useTranslation") throw sourceNodeError(invalid, sourceFile, "React i18next useTranslation() depends on runtime locale resources; migrate build-known locales through getStaticPaths() and props, or browser-only locale reads through an owned effect")
408
+ if (invalid && binding.target === compatibilityPackages.reactI18next && binding.imported === "useTranslation") throw sourceNodeError(invalid, sourceFile, "React i18next useTranslation() depends on runtime locale resources; migrate build-known locales through getStaticPaths() and props, or browser-only locale reads through an owned effect", {
409
+ code: "react-i18next.runtime-locale.unsupported",
410
+ compatibilityClass: "Unsupported",
411
+ suggestion: "Use getStaticPaths() and props for build-known locales, or read browser-only locale state in an owned effect.",
412
+ })
408
413
  if (invalid) throw sourceNodeError(invalid, sourceFile, `Package import ${JSON.stringify(name)} may only be referenced directly inside JSX event handlers or owned effect setup/cleanup callbacks`)
409
414
  }
410
415
  const hasUseEffectImport = sourceFile.statements.some(statement => ts.isImportDeclaration(statement) && ["@kudzujs/core", "react"].includes(statement.moduleSpecifier.text) && statement.importClause?.namedBindings && ts.isNamedImports(statement.importClause.namedBindings) && statement.importClause.namedBindings.elements.some(entry => !entry.propertyName && entry.name.text === "useEffect"))
@@ -3028,7 +3033,10 @@ function specializeComponentCall(call, component, sourceFile, factory, context,
3028
3033
  }
3029
3034
  if (declaration.initializer && ts.isCallExpression(declaration.initializer) && ts.isIdentifier(declaration.initializer.expression) && declaration.initializer.expression.text === "useRef") {
3030
3035
  const hookLabel = ordinaryHooks ? "Setter-callback component" : "Keyed row"
3031
- if (declaration.initializer.arguments.length !== 1 || declaration.initializer.arguments[0].kind !== ts.SyntaxKind.NullKeyword) throw sourceNodeError(declaration.initializer, component.getSourceFile(), `${hookLabel} useRef() must use the direct initial value null`)
3036
+ if (declaration.initializer.arguments.length !== 1 || declaration.initializer.arguments[0].kind !== ts.SyntaxKind.NullKeyword) throw sourceNodeError(declaration.initializer, component.getSourceFile(), `${hookLabel} useRef() must use the direct initial value null`, {
3037
+ code: "keyed.ref.initializer.unsupported",
3038
+ suggestion: "Initialize the object ref directly with null.",
3039
+ })
3032
3040
  if (!ts.isIdentifier(declaration.name)) throw sourceNodeError(declaration.name, component.getSourceFile(), `${hookLabel} useRef() must be assigned to one identifier`)
3033
3041
  const refs = ordinaryHooks ? ordinaryRefs : rowRefs
3034
3042
  const name = `${ordinaryHooks ? "__kComponentRef" : "__kRowRef"}${Math.max(0, call.pos)}_${refs.length}`
@@ -3573,7 +3581,7 @@ async function compileClientModule(file, sourceFiles, staticFiles, cssModules, b
3573
3581
  reportDiagnostics: true
3574
3582
  })
3575
3583
  const errors = result.diagnostics?.filter(diagnostic => diagnostic.category === ts.DiagnosticCategory.Error) ?? []
3576
- if (errors.length) throw new Error(errors.map(error => ts.flattenDiagnosticMessageText(error.messageText, "\n")).join("\n"))
3584
+ if (errors.length) throw createTypeScriptDiagnosticError(errors, message => ts.flattenDiagnosticMessageText(message, "\n"))
3577
3585
  return { file: relative(root, file).replaceAll(sep, "/"), path: clientModulePath(file), code: result.outputText, importedAssets: [...importedAssets].map(file => relative(root, file).replaceAll(sep, "/")).sort() }
3578
3586
  }
3579
3587
 
@@ -24,7 +24,11 @@ export function createSourceGraph(root) {
24
24
  const argument = node.arguments[0]
25
25
  const specifier = node.arguments.length === 1 && ts.isStringLiteralLike(argument) ? JSON.stringify(argument.text) : argument?.getText(sourceFile) ?? "<missing>"
26
26
  if (ownedLazyPackageImport(node, bindingIndex)) return
27
- throw sourceNodeError(node, sourceFile, `Dynamic import ${specifier} is not supported in ordinary source modules`)
27
+ throw sourceNodeError(node, sourceFile, `Dynamic import ${specifier} is not supported in ordinary source modules`, {
28
+ code: "source.dynamic-import.unsupported",
29
+ stage: "graph",
30
+ suggestion: "Use a reachable static import, or the supported guarded package import inside an owned effect.",
31
+ })
28
32
  }
29
33
  ts.forEachChild(node, rejectDynamicImports)
30
34
  }
@@ -38,7 +42,11 @@ export function createSourceGraph(root) {
38
42
  } catch (error) {
39
43
  const detail = error.message.slice(error.message.indexOf("Relative import"))
40
44
  const edge = ts.isExportDeclaration(node) ? "re-export" : "import"
41
- throw sourceNodeError(specifier, sourceFile, detail.replace("Relative import", `Relative runtime ${edge}`))
45
+ throw sourceNodeError(specifier, sourceFile, detail.replace("Relative import", `Relative runtime ${edge}`), {
46
+ code: edge === "import" ? "source.import.unresolved" : "source.reexport.unresolved",
47
+ stage: "graph",
48
+ suggestion: "Point the relative runtime edge to exactly one .ts or .tsx source file under src/.",
49
+ })
42
50
  }
43
51
  }
44
52
  return dependencies
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kudzujs/core",
3
- "version": "0.16.10",
3
+ "version": "0.16.11",
4
4
  "description": "HTML-first TSX framework with synchronous state semantics and no virtual DOM",
5
5
  "type": "module",
6
6
  "license": "MIT",