@akanjs/devkit 3.2.0-rc.0 → 3.2.0-rc.10

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.
Files changed (110) hide show
  1. package/CHANGELOG.md +238 -11
  2. package/agentAssets.ts +1 -1
  3. package/akanApp/akanApp.host.test.ts +127 -0
  4. package/akanApp/akanApp.host.ts +50 -57
  5. package/akanApp/devHostPolicy.test.ts +11 -11
  6. package/akanApp/devHostPolicy.ts +2 -4
  7. package/akanContext.ts +2 -5
  8. package/akanMcpContract.ts +21 -10
  9. package/akanMcpToolError.ts +16 -0
  10. package/apiReport/apiDeclarationPrinter.ts +120 -0
  11. package/apiReport/apiReport.test.ts +497 -0
  12. package/apiReport/apiReport.ts +232 -0
  13. package/apiReport/apiReportDiff.ts +126 -0
  14. package/apiReport/apiReportPolicy.ts +65 -0
  15. package/apiReport/apiTargets.ts +311 -0
  16. package/apiReport/changesetBump.ts +19 -0
  17. package/applicationBuildReporter.test.ts +21 -0
  18. package/applicationBuildReporter.ts +8 -0
  19. package/applicationBuildRunner.test.ts +67 -0
  20. package/applicationBuildRunner.ts +6 -1
  21. package/artifact/implicitRootLayout.test.ts +4 -0
  22. package/artifact/implicitRootLayout.ts +13 -1
  23. package/artifact/storeBootstrap.ts +3 -2
  24. package/bareErrorScanner.ts +126 -0
  25. package/biome.base.json +2 -1
  26. package/codeAgent/skills/akan-debug/SKILL.md +7 -3
  27. package/codeAgent/skills/akan-err/SKILL.md +7 -0
  28. package/codeAgent/skills/akan-mcp/SKILL.md +7 -1
  29. package/codeAgent/skills/akan-scaffold/SKILL.md +3 -2
  30. package/codeAgent/skills/akan-transport/SKILL.md +2 -0
  31. package/codeAgent/skills/akan-validate/SKILL.md +1 -0
  32. package/codeAgent/tools/McpClient.ts +28 -6
  33. package/codeAgent/tools/McpToolPack.ts +1 -1
  34. package/codeAgent/tools/akanCodePlugins.test.ts +13 -1
  35. package/commandDecorators/argMeta.ts +4 -0
  36. package/commandDecorators/cliError.ts +72 -0
  37. package/commandDecorators/command.ts +186 -96
  38. package/commandDecorators/commandDecorators.test.ts +240 -17
  39. package/commandDecorators/exitCodeError.ts +6 -7
  40. package/commandDecorators/index.ts +1 -0
  41. package/commandDecorators/targetMeta.ts +3 -0
  42. package/conventionSet.test.ts +5 -2
  43. package/createTunnel.test.ts +12 -2
  44. package/csrE2e/csrE2eHarness.fixture.ts +1 -1
  45. package/errorCodeReference.test.ts +282 -0
  46. package/errorCodeReference.ts +71 -0
  47. package/errorCodeScan.ts +551 -0
  48. package/frontendBuild/allRoutesBuilder.test.ts +16 -4
  49. package/frontendBuild/allRoutesBuilder.ts +24 -6
  50. package/frontendBuild/buildRouteClient.test.ts +43 -0
  51. package/frontendBuild/bundleDefine.ts +2 -0
  52. package/frontendBuild/clientBuildTypes.ts +5 -2
  53. package/frontendBuild/clientEntryDiscovery.test.ts +80 -0
  54. package/frontendBuild/clientEntryDiscovery.ts +53 -9
  55. package/frontendBuild/csrArtifactBuilder.test.ts +48 -0
  56. package/frontendBuild/csrArtifactBuilder.ts +9 -3
  57. package/frontendBuild/csrDevBundler.ts +12 -2
  58. package/frontendBuild/csrDevModuleCompiler.test.ts +97 -0
  59. package/frontendBuild/csrDevModuleCompiler.ts +37 -8
  60. package/frontendBuild/csrDevPatcher.test.ts +89 -2
  61. package/frontendBuild/csrDevPatcher.ts +47 -7
  62. package/frontendBuild/csrDevTypes.ts +16 -0
  63. package/frontendBuild/cssCompiler.test.ts +63 -1
  64. package/frontendBuild/devBarrelImports.ts +132 -0
  65. package/frontendBuild/devRegistryBundler.ts +19 -4
  66. package/frontendBuild/mcpAppViewBuilder.test.ts +67 -0
  67. package/frontendBuild/nativeCore.test.ts +148 -0
  68. package/frontendBuild/precompressArtifacts.ts +1 -1
  69. package/frontendBuild/ssrBaseArtifactBuilder.test.ts +26 -0
  70. package/frontendBuild/ssrBaseArtifactBuilder.ts +23 -19
  71. package/frontendBuild/ssrDevBundler.ts +13 -2
  72. package/frontendBuild/vendorImportScanner.test.ts +24 -3
  73. package/frontendBuild/vendorImportScanner.ts +25 -10
  74. package/incrementalBuilder/incrementalBuilder.host.test.ts +30 -1
  75. package/incrementalBuilder/incrementalBuilder.host.ts +10 -22
  76. package/lint/__fixtures__/no-import-common-err/bad.tsx +13 -0
  77. package/lint/__fixtures__/no-import-common-err/good.tsx +12 -0
  78. package/lint/no-import-common-err.grit +31 -0
  79. package/lint/no-init-fetch-in-client.grit +1 -1
  80. package/lint/no-web-only-api-outside-webkit.grit +3 -3
  81. package/maintainabilityBaseline.test.ts +49 -0
  82. package/maintainabilityBaseline.ts +73 -8
  83. package/maintainabilityContract.test.ts +302 -1
  84. package/maintainabilityContract.ts +87 -22
  85. package/maintainabilityExceptionScanner.test.ts +14 -0
  86. package/maintainabilityExceptionScanner.ts +5 -1
  87. package/maintainabilityLimits.ts +12 -0
  88. package/maintainabilityReport.ts +20 -3
  89. package/moduleFieldNames.test.ts +56 -0
  90. package/moduleFieldNames.ts +25 -0
  91. package/package.json +3 -3
  92. package/preview/PreviewChrome.ts +3 -3
  93. package/preview/PreviewView.ts +48 -9
  94. package/preview/previewView.test.ts +154 -3
  95. package/routeJsBudget.test.ts +47 -11
  96. package/routeJsBudget.ts +88 -25
  97. package/transforms/barrelAnalyzer.ts +46 -1
  98. package/transforms/barrelImportsPlugin.ts +61 -45
  99. package/transforms/transforms.test.ts +67 -1
  100. package/typecheck/projectTypecheck.ts +5 -1
  101. package/typecheck/typecheck.proc.ts +3 -2
  102. package/typecheck/typecheckFailure.ts +6 -1
  103. package/workflow/artifacts.ts +25 -7
  104. package/workflow/fieldType.ts +92 -0
  105. package/workflow/index.ts +2 -0
  106. package/workflow/plainName.ts +28 -0
  107. package/workflow/plan.ts +67 -22
  108. package/workflow/source.ts +0 -5
  109. package/workspaceGraph.test.ts +200 -3
  110. package/workspaceGraph.ts +46 -8
package/CHANGELOG.md CHANGED
@@ -4,6 +4,40 @@
4
4
 
5
5
  ### Minor Changes
6
6
 
7
+ - e973831: A CLI failure carries a code and the exit status its family takes, so a script branches on either instead of the message.
8
+
9
+ - Exit 2 (`usage`, `unknownTarget`): a flag, argument or command commander refuses, a value outside an option's choices, an argument left out where no terminal can ask for it, a run outside the workspace root, and an app, lib, package or module the workspace does not have. These exited 1 before, except for `akan migrate`, `akan pipeline` and `akan verify <name>`, which already exited 2.
10
+ - Exit 2 (`refused`) stays what it was: a pack that needs a new store build, and a release the Akan Cloud project rejected.
11
+ - Exit 3 (`checkFailed`): `akan verify`, `akan typecheck` and the typecheck of `akan build`, `akan preview` and `akan agent install --check` when they found problems. These exited 1 before.
12
+ - Exit 130 (`interrupted`) for a prompt closed with Ctrl+C, which exited 1.
13
+ - Exit 1 (`failed`, or an `AkanError`'s own code) for anything else, as before.
14
+ - `akan pack-update`, `akan push-update` and `akan register-binary` keep exiting 1 for a usage or unknown-target failure, so their 2 still means only the store-build verdict or the project's refusal. `akan agent` exits 1 for one too, and `akan agent hook` never exits 2, saying on stderr why the hook failed: Claude Code reads a hook's exit 2 as a block.
15
+
16
+ With `--json` or `--format json`, a failure now ends stdout with one line, `{"ok":false,"error":"<message>","code":"<code>"}`, and the message goes to stderr instead of stdout. An NDJSON stream (`akan code --json`, `akan logs --json`) ends with that line too. A command whose own JSON report says it failed, as `akan verify`'s does, adds no line. `akan migrate --json` answers `usage` or `notFound` for a command line or an app it cannot take before the app runs, matching its exit 2.
17
+
18
+ Upgrade: a script that tested for exit 1 after a usage error, a failed check or a closed prompt tests for non-zero, or for 2, 3 and 130. A CI step that branches on exit 2 from the OTA commands needs no change. `@akanjs/devkit/commandDecorators` exports `CliError(code, message, { exitCode })`, `ExitCodeError` is now one coded from its exit status (2 as `refused`, 3 as `checkFailed`), and a target's `usageExitCode` now also sets the exit of a `usage` or `unknownTarget` failure thrown while it runs.
19
+
20
+ - d6b3619: Every `Err` is now one class, `Err` from `akanjs/common`. That covers the one an app's or lib's `lib/dict` builds, the one `useClient` returns, `akanjs/dictionary`'s own, and an error restored off the wire. Each is that class typed with its own dictionary's keys, so `Err.is` and the status classes behave the same in the browser and on the server. `instanceof Err` holds within one copy of the module. A page bundle and the framework each carry one, so check across them with `Err.is`.
21
+
22
+ - **`Err` is an `AkanError`.** `AkanError.is(err)` is true for every `Err`, and `err.forwarded` is true unless it was restored with a `code`, so the request path still sends its `toJSON()` as it is.
23
+ - **A restored failure that carries a `code` is not `forwarded`.** Such a failure is one its origin server generalized, such as `{ "error": "Forbidden", "code": "fileGrantRefused", "statusCode": 403 }`. The request path generalizes it again, to the same body, and a guard or an auth challenge does not read it as a refusal of its own.
24
+ - **`err.code` is always set.** It is the code a generalized failure's payload carried, or else the code of its status (`notFound`, `conflict`, `badRequest`), so `AkanError.is(err, "notFound")` matches an `Err.NotFound`. `toJSON()` still sends `code` only when the payload carried one, so the wire does not change. `{ ...err }` does change, on the server and the client alike: its `code` was usually `undefined`, and now holds that status code.
25
+ - **A status class tells its own status apart.** `Err.NotFound.is(error)` also requires a `statusCode` of 404, so `Err.NotFound.is(new Err.Conflict(key))` is false; `Err.is` still takes any status. `Err.NotFound.fromJSON(payload)` builds an `Err.NotFound`.
26
+ - **Status classes on a dictionary's `Err` are typed as the full constructor:** `Err.BadRequest`, `Err.Unauthorized`, `Err.Forbidden`, `Err.NotFound` and `Err.Conflict`. So `Err.NotFound.is(...)` and `Err.NotFound.fromJSON(...)` type-check on the server too.
27
+ - **A restore with no error constructor gives an `Err`.** That applies to an HTTP, WebSocket or MCP App bridge restore. It used to give a plain `Error` with the payload's fields copied onto it, so a field the wire does not declare is no longer on the error.
28
+ - **On the client, `String(err)` appends the error's `data`**, as it already did on the server, with secret-named keys masked.
29
+ - **The type exports moved.** `ErrConstructor`, `ErrPayload` and `ErrRestoreOption` come from `akanjs/common`, `akanjs/dictionary` re-exports all three, and `akanjs/client` re-exports `ErrPayload`. `ErrInstance`, `PageErrInstance` and `PageErrConstructor` keep their shapes and are deprecated.
30
+ - **The API explorer shows a failed call's wire body**, the error's `toJSON()`, instead of the error object's own fields.
31
+ - **A new lint rule, `no-import-common-err`, refuses a value import of `Err` from `akanjs/common` in `apps/` and `libs/`.** That class takes any string, so only the `Err` from `lib/dict` or a client entrypoint checks a key against the dictionary. `import type` stays legal.
32
+
33
+ Upgrade:
34
+
35
+ - Replace the types `ErrInstance` and `PageErrInstance` with `Err` from `akanjs/common` (through `import type`), and `PageErrConstructor` with `ErrConstructor`.
36
+ - Code that read `err.code === undefined` to tell whether a restored failure carried a code should read `"code" in err.toJSON()` instead.
37
+ - Code that relied on `Err.NotFound.is(...)` accepting an error of another status should call `Err.is(...)`.
38
+ - A test that replaces `akanjs/base` with `mock.module("akanjs/base", …)` while the real `akanjs/common` loads must include `AkanError` in the mock.
39
+ - Nothing else changes for code that throws and checks `Err` through `lib/dict` or `useClient`.
40
+
7
41
  - 29756e1: `akan lint`, `akan lint-all` and `akan verify` now hold each package under a workspace's `pkgs/` to a structure budget, as they already hold apps and libs: a file up to 800 lines, a function up to 150 lines (`akan.size.function`) and a class up to 60 members (`akan.size.class`). Tests and their fixtures (`*.test`, `*.spec`, `*.fixture`, `*.instance` and `*.bench` files, and `test/`, `tests/`, `__tests__/`, `__fixtures__/` and `__mocks__/` folders), `.d.ts` files, re-export barrels and a package's `examples/` are left out, and a package in a git repository is listed through git, so ignored files are never measured. Each package keeps its own `akan.baseline.json`; `akan quality baseline` now seeds one for each package too, `akan quality scan` reports its exceptions, and packing a package that would publish one fails.
8
42
 
9
43
  A baseline only shrinks from the default branch's copy. Where the default branch has none, an app's, lib's or package's baseline may hold only the breaches the default branch's code already has, so a new one starts empty instead of skipping the check. A file's line count no longer includes the newline ending its last line, so a recorded size may drop by one on the next `akan lint`.
@@ -34,6 +68,43 @@
34
68
  - **`pkgs/akanjs/ARCHITECTURE.md`** pairs a hand-kept walk through the processes and a request with a generated part between markers. `akan sync-architecture` regenerates that part, and a devkit test fails when it is stale, when a channel is gone, when two facets load values from each other, when a message lacks a recognised sender or handler outside a short list whose other end lies beyond the framework source, or when the hand-kept part names a class the source no longer has.
35
69
  - **`AkanIpcMessage` no longer lists `backend-ready`.** The gateway sends it to the dev host, which reads it as a `BuilderMessage`, where it stays; no gateway or child ever handled it.
36
70
 
71
+ - 4d61170: The Akan Graph follows an app's adaptor wiring further. `applyAdaptor(LlmAdaptorRole, ChatCompletionsLlm)` in an app's or lib's `option.ts` draws a `binds` edge from the role, `adaptor::LlmAdaptorRole`, to the implementation it binds, labelled with the app or lib and located at the call, so a method that calls a plugged role reaches the class that answers it. `get_graph` scoped to an app keeps that app's own bindings, and a lib's binding of a role the app does not bind itself; scoped to a lib or a module it keeps every binding of a role it reaches. A Change Map carries every binding of a role it shows, changed or not, so the binding an app runs stays in view; a binding the app removed no longer hides the lib binding it now runs; and Studio's Change Map for one app keeps only the bindings that app runs. An app service holds the fields its module's lib services plug (`...user.services`), so `this.notifier.getMemo()` in an app method links to the `Notifier` a lib's `MemoService` plugs, where it linked to the `memo` model; a service whose own builder declares the field (`notifier: use<…>()`) inherits nothing. A plug imported from a package outside the workspace, `plug(Stripe)` from `stripe-sdk`, or through a lib's re-export of it (`export { Stripe }`, `export { default as Stripe }`, or `export * from "stripe-sdk"` where the lib declares no `Stripe` itself), is `adaptor:stripe-sdk:Stripe` with the package in `detail`, where it linked to a same-name adaptor the app declares or to an unlocated `adaptor:libs/util:Stripe`. Two adaptors with the same class name in one app or lib are two nodes, each with its own location, digest and `plugs`, and a plug reaches the one its import names. A job's `detail` lists only the options its kind honours: `once` on an `initialize` job, `unlocked` on an `interval` job (`Bun.cron` never overlaps a cron job, so `lock: false` changes nothing there); `cron("0 * * * *" as const)` reads `0 * * * *`.
72
+
73
+ Ids and details that change for a saved graph or a Change Map base:
74
+
75
+ - While two adaptors of one owner share a class name, each is keyed by its file, `adaptor:apps/demo:srvkit/clockB.ts#Clock`; an adaptor whose name no other adaptor of its owner shares keeps `adaptor:<owner>:<Name>`. The Change Map treats the two forms of one declaration as one node, so a second same-name adaptor shows as one added node, not a removal of the first.
76
+ - A plug from a non-workspace package is `adaptor:<package>:<Name>` with the package as `detail`, where it was `adaptor::<Name>` or a workspace adaptor of that name.
77
+ - A job's `detail` drops `once` and `unlocked` where the runtime ignores them, and `as const` from a cron expression.
78
+
79
+ - **`binds`** joins `AkanGraphEdgeKind` in `akanjs/common`.
80
+ - **`FileFacts.adaptorBindings`** in `@akanjs/language`: each `applyAdaptor(role, adaptor)` call a file makes; `AkanIndex.setFile` also reads non-test files whose text mentions `applyAdaptor`. **`ServiceClassFact.fields`**: the names a service's builder declares.
81
+
82
+ - c723713: The Akan Graph keys a guard function by the file that declares it, locates more of a workspace's guards, and stops counting things that are not guards.
83
+
84
+ A guard function a route or layout imports is keyed by its file, as one the page declares already was: `guard:libs/shared:webkit/signedIn.ts#signedIn`. A `canEdit` in `webkit/` and one in `common/` are two nodes, each at its own declaration, and an edit to either marks only that one changed in the Change Map. A guard called through a namespace import (`auth.signedIn()`), or imported under a name a file re-exports (`export { signedIn as hasSession } from "./auth"`), reaches its declaration. A function the guard declares, or a parameter it binds, shadows an import of the same name only inside its own scope, so `[1].forEach((signedIn) => …)` no longer hides a real `signedIn()` beside it. A guard declared after another declarator (`export const ready = true, signedIn = …`) is found, and an overloaded guard's digest covers every signature. Only a file whose text declares or re-exports the name is parsed, so a guard that calls `usePage()` from the generated client no longer parses every page that names it.
85
+
86
+ A function is a guard factory only when it returns a guard, a class that implements `Guard` (also one handed to a wrapper, `withName(class implements Guard {…}, field)`) or a call to a factory, so `const guardCount = countGuards()` is no longer a guard. An import from a package outside the workspace (`@vendor/auth`) resolves to no guard: it no longer links a same-name workspace guard, and a vendor's `Public` no longer reads as the framework's. A factory imported from akanjs or a package makes no guard. A lib's `export *` chain, walked from the path the import names, is followed only when it reaches exactly one workspace lib declaring the name, none of its `export *` names a package, and the lib does not declare, destructure or export the name itself; otherwise the guard stays `guard:<lib>:<Name>` without a location, so a vendor shim no longer links another lib's guard. A class extending a base that is not a known guard is no guard, even when a lib declares a guard of that name.
87
+
88
+ More guards carry their location: a name a lib re-exports under another name (`export { Admin as AdminGuard }`) reaches the class, and one it re-exports from akanjs is `guard::Public`; `srvkit.SSO.Kakao` reads through the namespace to the lib's map; a map entry a factory makes (`SSO = { Kakao: ssoGuardOf("kakao") }`) is the guard `SSO.Kakao`; a local wrapper of an imported factory, a factory called through a namespace (`srvkit.resourceGuard("pin")`) and a class that extends a guard (`class DemoAdmin extends Admin`) and a factory a lib re-exports under another name (`export { resourceGuard as rg }`) make guards; a guard made in place, `guards: [canEdit("memo")]`, is a node at the call, keyed by its member, callee and ordinal so an edit to its arguments, or to another member's guards, keeps the id. Of two same-name guards in one owner, an import reaches the one its path names. A wrapper's digest covers every factory it can return, and an edit to a factory in another file marks the guards it makes changed instead of listing the file as unmapped.
89
+
90
+ In the Change Map, a declaration whose id moves between `kind:owner:Name` and `kind:owner:<file>#Name` at the same file is one node, so a second same-name guard shows as one addition, not the first one removed and re-added.
91
+
92
+ `get_graph` past the node limit names owners by the nodes it would answer with, changed pages included, so 650 changed routes no longer hide behind one changed lib method. A guard on `const route = page()…; export default route` is no longer read: `RouteSourceValidator` rejects that shape.
93
+
94
+ Ids and details that change for a saved graph or a Change Map base:
95
+
96
+ - An imported guard function's id names its file: `guard:libs/shared:signedIn` is now `guard:libs/shared:webkit/signedIn.ts#signedIn`.
97
+ - A guard name two files of one owner declare is keyed by file, `guard:apps/demo:srvkit/admin.ts#Admin`.
98
+ - A guard made in place is `guard:<owner>:<file>#<model>.<key>:<callee>@<n>`, the `n`th in-place call of that callee in that slice or endpoint key (`…/memo.signal.ts#memo.shareMemo:resourceGuard@1`). Its label, an endpoint's `detail` and the editor hover name the call: `resourceGuard("memo")` where `detail` read `resourceGuard`, or `allow(…)` when the arguments run past 32 characters or a line. A guard read through a namespace's map reads `srvkit.SSO.Kakao` where it read `Kakao`.
99
+ - A map entry a factory makes is `guard:libs/shared:SSO.Kakao` where it was `guard::Kakao` or `guard:<lib>:Kakao`, and a local map's `Roles.Owner` is `guard:apps/demo:Roles.Owner` where it linked `guard:apps/demo:Owner`.
100
+ - A guard a lib re-exports, under its own name or another, or from akanjs, takes the declaring owner's id (`guard:libs/util:Admin`, `guard::Public`) where it took the re-exporting lib's.
101
+ - A guard imported from an unknown package draws no edge.
102
+ - A name the old "sole visible lib" fallback linked through a lib that does not declare it (`guard:libs/billing:Admin` behind a vendor `export *`) now reads `guard:<lib>:<Name>` without a location, unless the lib's `export *` chain reaches exactly one workspace lib declaring it.
103
+ - A class extending a base that is not a known guard (`class Thing extends Base` with an ordinary `Base`) no longer has a guard node; an endpoint naming it in `guards` links an unlocated `guard:<owner>:Thing`.
104
+
105
+ - **`AkanGraphNode.sources`** in `akanjs/common`: the files besides `at.file` that a node's digest reads, set only with digests. The Change Map uses it to map those files and leaves it out of its answer.
106
+ - **The fact reader** in `@akanjs/language`: `GuardFactoryFact.via` is a list and gains `direct`; `GuardCallFact` gains `kind` (`call` or `extends`) and `scope`; `FileFacts` gains `guardLabels`, an in-place guard's name to its call. A slice's or endpoint's guard made in place is read as `<model>.<key>:<callee>@<n>`, and every in-place call is a `GuardCallFact`.
107
+
37
108
  - 0351ad4: The Akan Graph keys each guard by the app or lib that declares it, `guard:libs/shared:Admin`, and follows the import that names it there, so `Admin as AdminGuard` reaches `Admin`, `srvkit.Admin` reaches the lib's class, and two libs' `Admin` stay two nodes. A guard read out of an object map, `SSO.Kakao`, resolves through the imports of the file that declares the map. A name a lib only re-exports reaches the class it re-exports. A guard a factory makes is a guard too, whether the factory sits in the same file, wraps another factory there, or is imported from another lib. A guard node carries its source location, `doc` (the comment above its declaration that says what it checks) and, in `detail`, its `scope` (`account` or `resource`). A factory-made guard takes the factory's scope, and takes its doc when no guard of that factory has its own. With digests, an edit to a guard or to the factory that makes it marks the guard changed in the Change Map. Every guard a workspace declares is a node, referenced or not. `Public` and `None` come from `akanjs`, carry no location and say what they do. Studio shows a node's `doc` in its tooltip.
38
109
 
39
110
  Ids and details that change for a saved graph or a Change Map base:
@@ -94,13 +165,28 @@
94
165
  - The dev builder draws the graph on request through a new `build-graph` builder RPC, and keeps it until the next save.
95
166
  - It sits behind the same gate as the other `/_akan` devtools routes, and `akan tunnel` / `akan start --share` refuse it.
96
167
 
168
+ - 2d3b958: `ApiReportPolicy.check` counts a changeset that a branch adds in place of a similar one it deletes. git's rename detection paired the two, so the added changeset was not listed and its `minor` bump did not satisfy the check.
169
+ - 465ccb9: `@akanjs/devkit/apiReport/apiReport` renders a package's public API, one report per entry point, from its declaration emit. The akanjs repository now commits that report for `akanjs` and checks it in CI: a removed export or a changed declaration needs a `minor` changeset that says how to upgrade.
170
+ - 222c7df: `akan lint` holds `server/`, `service/` and `signal/` of the `akanjs` package to the bare built-in `Error`s they construct or extend today (`akan.error.bare-error`): its `akan.baseline.json` records them per file and holds their total, so moving one between files passes and a new one anywhere fails. A change that removes one must lower the section too: `akan lint --no-fix` fails while the recorded total is above the code's, and `akan verify akanjs` or `akan lint akanjs` lowers it. No other package or workspace is measured by it. A baseline committed before a rule is added now adopts that rule with the debt its code held at the fork point.
171
+
172
+ A generated `errorCodes` guideline lists every code a framework error carries, with its status, whether it is forwarded, and whether the caller's JSON carries it; the `akan-err` skill ships it as a reference.
173
+
97
174
  - 0504209: `akan build <app> --env <env>` builds for an environment other than the workspace `.env`'s, the way the desktop and mobile builds already do. Before, the shell's `AKAN_PUBLIC_ENV` lost to the `.env`, so a new workspace could only build `local` without editing it. The local-build notice, the image guard and the README now say what a `local` build changes in a built server: no endpoint rate limits, and local defaults for Redis and the database mode. They no longer say the dev routes are served, which a built server never does.
98
175
  - bf872ce: A variable the shell sets now outranks the workspace `.env` when `akan` builds or runs an app, as dotenv and Bun's own `.env` loading do: `AKAN_PUBLIC_ENV=main akan build <app>` builds `main` where the `.env` says `local`. The order is `--env` (for `AKAN_PUBLIC_ENV`), then the process environment (the shell, and the `.env.local` and `.env.<NODE_ENV>` Bun loads into it), then the `.env`, then the defaults; an empty export counts as unset. The bundles, the bundled server env, `akan.env.json` and the Dockerfile still take one set of values. Where an exported value outranks the `.env`, `akan build` now warns with both values instead of the old warning that listed the values it ignored, and the server-env message, the `--env` help, the local-build notice, the README and the CLI reference state the new order.
99
176
 
100
177
  **Behavior change:** where the shell exports a value the workspace `.env` also sets, such as `AKAN_PUBLIC_ENV`, `AKAN_PUBLIC_REPO_NAME` or `AKAN_PUBLIC_SERVE_DOMAIN`, `akan` now takes the shell's. Unset it, or match the `.env`, to build what you built before.
101
178
 
179
+ - af7c411: The five child-process restart loops now share one restart schedule, `RestartSchedule` from `akanjs/common`: the gateway's replicas, the RSC worker, the incremental builder, and `akan start`'s backend and builder recovery. It counts failed restarts, waits before the next one and cancels a pending one on stop. Each loop keeps its own delays (200ms–30s for the RSC worker, 2s–60s for `akan start`'s builder recovery, 1s–30s for the rest), its own give-up rule and its own log lines.
180
+
181
+ Two stop races in those loops are fixed:
182
+
183
+ - A replica whose restart timer had fired no longer respawns after the gateway stops.
184
+ - A builder `akan start` was still creating or booting when it stopped is now stopped too, instead of being started or retried after its ready timeout.
185
+
186
+ In `@akanjs/devkit`, `shouldAbandonBackendRecovery` is replaced by `backendRecoveryPolicy`, which gives up after five failed backend restarts as before.
187
+
102
188
  - e65172d: The CLI refreshes a cloud sign-in once less than an hour, or half the token's lifetime, is left, whichever is shorter. Before, a token that lived an hour or less read as due the moment it arrived, so every command rotated the refresh token and then called the cloud unsigned. Any unexpired token is now sent with the request, except the refresh call, which carries none. `akan login` signs in again when a session is due for refresh and has no refresh token left.
103
- - c3b5b3c: A web page no longer loads `@akanjs/native/core`. `isNativeApp()` and the other host checks read the platform the shell writes before the bundle runs, and a native shell still starts core with the page. On the minimal app this takes 15 KB raw (5.6 KB brotli) off the vendor floor and 20 KB raw (6.6 KB brotli) off every route entry. `akan build` also resolves the `production` export condition for the browser, SSR-client, CSR and MCP App view bundles, so a package such as Lexical ships its production build alone. On the minimal app the Agent editor chunk drops from 91 KB to 63 KB brotli. `akan start` is unchanged.
189
+ - c3b5b3c: The framework no longer puts `@akanjs/native/core` on a web page. `isNativeApp()` and the other host checks read the platform the shell writes before the bundle runs, and a native shell still starts core with the page. A file that imports `akanjs/client/native` statically still brings core to every page that reaches it. On the minimal app this takes 15 KB raw (5.6 KB brotli) off the vendor floor and 20 KB raw (6.6 KB brotli) off every route entry. `akan build` also resolves the `production` export condition for the browser, SSR-client, CSR and MCP App view bundles, so a package such as Lexical ships its production build alone. On the minimal app the Agent editor chunk drops from 91 KB to 63 KB brotli. `akan start` is unchanged.
104
190
  - 6d5b544: A database service now has `create<Model>Many(rows)`. It creates the rows on the same path as `create<Model>`: `_preCreate` and `_postCreate`, the document's save and create hooks, and the live and pubsub events each row's commit fires. Every row's `_preCreate` and document pre hooks run first, so a check there that queries the table does not see the batch's own rows. The rows are then written in one transaction, joining the caller's when one is open, with one multi-row INSERT per 500 rows instead of one statement per row; if the database refuses one row, none is written. Every row's `_postCreate` runs once the transaction commits, as `create<Model>`'s runs once its row is stored, so a `_postCreate` that throws leaves the rows written. A service that already declares a method of that name, itself or in a lib service it extends, keeps its own at runtime, but its signature no longer typechecks against the generated one: rename it.
105
191
 
106
192
  A store can list actions in `static silent = ["refreshToken"] satisfies (keyof UserStore)[]`. When a silent action fails, it shows no toast and logs at verbose instead of error. It still rejects with the original error, so a background write such as a token refresh is awaited by its caller, which handles the failure. Generated actions can be listed, and a store built on a lib store keeps the lib's silent actions. A name in `static silent` that is not an action of the store is reported when the store registers.
@@ -128,6 +214,7 @@
128
214
  - **`@akanjs/devkit`**: `applyTemplate` takes `dryRun` to list the files a template would write without writing them, and `WorkspaceExecutor.commit` takes an `identity` to commit under.
129
215
 
130
216
  - 1870fcd: `akan verify` adds a `fix:` line to a module file's two-parent import that names the layer barrel to import from instead, such as `import from "@apps/<app>/common"`. The lint message itself now points at the layer barrel too.
217
+ - 76ab8d4: `akan doctor` exits with code 1 when its report says `"status": "failed"`, in text or JSON, with or without `--strict`, and for `--ios`, so the `agent:doctor` script (`akan doctor --strict --format json`) or a CI step fails on it. Before, it always exited 0. The full report still prints on stdout. A warning never changes the exit code: `--strict` still only decides which conventions count as errors, today a missing module abstract. Doctor's `dictionary-label-missing` now reads both a constant's fields and its dictionary's labels from their syntax, ignoring comments and strings. A field that appears only in a comment no longer asks for a label: a new `--sample` workspace no longer warns about `task`'s `priority`, `tags`, `assignee` and `completedAt` or `workHistory`'s `actor` and `previousStatus`, which its constants suggest only in comments. A label that exists only in a comment, or a `name:` inside a string, no longer counts, so a field whose label is commented out now warns.
131
218
  - 245d318: A font declared on a root layout now gets its metric-adjusted fallback faces: `@font-face` rules named `"<font> fallback"` that draw a local system font with `size-adjust`, `ascent-override` and `descent-override` matched to the web font. The variable `--font-<name>` already named that family, but the build never wrote it, because fontaine's `readMetrics` takes a URL and returned nothing for the file path it was given. While a web font loaded (`font-display: swap`), text drew in the browser's default font, usually a serif, and moved when the web font arrived. The metrics are read from the source font, not the subset, so a subset without Latin letters (`subsets: ["ks-x-1001"]`, or only `subsetText`) still sizes the fallback correctly. A font whose metrics cannot be read keeps its face and gets no fallback, as before. Set `adjustFontFallback: false` on a font to keep the old output. Cached font output from `akan start` is regenerated once.
132
219
  - 6f6cc2a: A fresh clone of a workspace now builds and starts after `bun install` alone. The env files that hold secrets stay gitignored, so a clone has none of them: before, `akan typecheck`, `akan build` and `akan verify` failed with `Cannot find module './env.server.local'`, and with no `.env` the CLI picked the `debug` environment, so `akan build` stopped asking for `AKAN_PUBLIC_REPO_NAME` and `AKAN_PUBLIC_SERVE_DOMAIN`.
133
220
 
@@ -165,7 +252,8 @@
165
252
  - **A narrowed build fails when route code imports a name its facet does not export**, and names the missing names. Before, the page threw a `SyntaxError` in the browser.
166
253
 
167
254
  - 4561152: The skill examples now use one neutral domain, books from a public read-only API: a `BookApi` adapter in `srvkit/`, a `lib/_openlibrary/` service with a `book` query, `fetch.book(id)` and `/books/[id]` pages. This covers the `akan-service` external-API recipe, the `akan-page` API summary, the `akanApi` import block, the `config` rule's `localePrefix` example and the README's as-needed path. The recipes teach the same steps as before.
168
- - 53eb6f1: A command whose app-or-lib target is left out no longer stops at a prompt error when stdin is not a terminal, as in a coding agent's shell or CI. In a workspace with a single app, lib or package, `akan sync`, `akan lint`, `akan test` and `akan create-module <name>` run on it and say so on stderr, so a new workspace's `bun run sync`, `bun run lint` and `bun run test` work there. Otherwise every target command (app, lib, package, module) exits at once with the valid targets and the line to rerun, such as `akan sync <app-or-lib>`. A library, package or module is still never picked unasked, since `akan remove-library` and its kin would delete the only one. A terminal is asked as before.
255
+ - 53eb6f1: A command whose app-or-lib target is left out no longer stops at a prompt error when stdin is not a terminal, as in a coding agent's shell or CI. In a workspace with a single app, lib or package, `akan sync`, `akan lint`, `akan test` and `akan create-module <name>` run on it and say so on stderr, so a new workspace's `bun run sync`, `bun run lint` and `bun run test` work there. Otherwise every target command (app, lib, package, module) exits at once with the valid targets and the line to rerun, such as `akan sync <app-or-lib>`. A terminal is asked as before.
256
+ - 44149b1: Without a terminal, a command that deletes nothing now takes the workspace's only library, package or module when none is named, as it already did for the only app or lib, and names it on stderr: `No lib named, so this runs on 'util', the only one in this workspace: akan sync-library util`. This covers `sync-library`, `sync-package`, `build-package`, `verify-dist-package`, `create-view`, `create-unit`, `create-template` and `create-crud-page`. Before, each refused and asked for the target to be named. The remove commands still never take one they were not given. A terminal is still asked, even when there is only one choice.
169
257
  - b24fef3: An app that draws no Akan UI component now builds and runs without the UI's optional peers. Before, `akan build` failed with `Could not resolve: "react-icons/ai"` or `"react-spring"` in an app that imported nothing from `akanjs/ui`: the System UI every root layout mounts drew react-icons glyphs and reached the model, list and dialog components through the `Load` and `Button` modules, and the CSR build, on by default, bundled the whole `akanjs/ui` barrel.
170
258
 
171
259
  **Upgrade note.** A workspace can drop `react-spring`, `@react-spring/web`, `@use-gesture/react`, `react-refresh`, `scheduler` and `tailwind-scrollbar` from its `package.json`, unless its own code imports them. `akanjs` now depends on `@react-spring/web`, `@use-gesture/react`, `react-refresh`, `scheduler` and `tailwind-scrollbar` itself, because the System UI, the dev runtime and `akanjs/ui/styles.css` always use them, and nothing uses `react-spring` any more. New workspaces no longer list them. A workspace whose own code keeps `react-spring` or `@react-spring/web` must move it to major 10: an older one installs a second copy under `akanjs`, and a spring value the app makes no longer typechecks on an `animated.*` element from `akanjs/ui`.
@@ -177,21 +265,71 @@
177
265
  - **The CSR build and its MCP App views** rewrite `akanjs/ui` imports to the components a file names, as the SSR route builds already did, so a page that imports `Link` no longer bundles every component.
178
266
  - **Animations use `@react-spring/web`** instead of the `react-spring` umbrella package, which also installed the native, three.js, konva and zdog renderers.
179
267
 
180
- - eefd9cb: `akan preview <app> /_akan/studio` opens Studio instead of a 404. Preview added the default locale to every path, and the server routes `/_akan/*` without one, so `/en/_akan/studio` matched no page. A path under `/_akan`, `/__csr`, `/__rsc`, `/.well-known` or the app's API prefix, a file the app's `public/` holds, and the server's own `/favicon.ico`, `/robots.txt`, `sitemap.xml` and `manifest.webmanifest` now open as written: no locale, and no CSR boot query under `--csr`. Every other path, including one that already starts with a locale or ends in a dotted segment such as `/release/1.2.3`, is a page and gets the default locale as before. The `akan-debug` skill and the `akan preview` reference say so.
268
+ - b516497: `akan create-package --name` takes `name` or `@scope/name`, each part lowercase letters, digits, `-`, `.` and `_` starting with a letter or digit, and refuses anything else before it touches a file: `"../x" is no package name; use name or @scope/name, each of lowercase letters, digits, -, . and _, starting with a letter or digit`. Before, `--name ../x` wrote `x/` beside `pkgs/` and added it to the root `tsconfig.json`. `akan create-ui`, `add-field` and `add-enum-field` refuse a `--module` that is not a module name with a `primitive-input-invalid` diagnostic in their report, as they already reported a missing one. Before, `create-ui --module ../x` wrote its component into the app root, and `add-field --module ../x` looked for the constant and dictionary outside the module folder. `plainNameProblem` returns the message `assertPlainName` throws, and `assertPackageName` sits beside it in `@akanjs/devkit/workflow/plainName`.
269
+ - 58b7329: `akan create-scalar`, `remove-scalar`, `create-module`, `create-service`, `create-application`, `create-library`, `install-library` and `create-workspace --app` refuse a name that is not one plain path segment before they touch a file, such as `"../.." is no scalar name; use letters, digits, - and _, starting with a letter`. Before, the name went into the path unchecked: `akan remove-scalar ../.. <app>` deleted `apps/<app>` and exited 0, and the create commands wrote their files outside `lib/`, `apps/` or `libs/`. A scalar, module or service name is checked as a workflow's `module` input already was, an app or lib name as its `app` input; both checks now live in `@akanjs/devkit/workflow/plainName`, with `assertPlainName`.
270
+ - 4e0a38e: A page preview starts a new browser when the one before it died. Bun refuses to start a new browser until a later event-loop turn has reaped the dead one. `akan preview` opens its pages back to back when the app's log socket does not answer. In that case, if Chrome died during one page, every page after it failed at once with `Failed to spawn Chrome (set BUN_CHROME_PATH, …)`. Now a preview whose browser fails to start for any reason other than running out of `startTimeoutMs` waits 100 ms and tries the start once more. A browser that cannot start at all still fails in about 100 ms, now with its own error, such as `Chrome process closed the pipe`.
271
+ - b4b8f85: `akan preview` and the code agent's page preview give a browser that died or was closed the full `startTimeoutMs` (120 s by default) for its next start. Before, after one page had run out of the start bound, a browser that then died while another page waited for it stayed marked as slow to start. The next page started a fresh browser within only its own `timeoutMs` (60 s for `akan preview`, 30 s for the code agent's check).
272
+ - 686e0b8: `akan preview` and the code agent's page preview bound a page only once the browser is up. Before, a process's first page shared its `timeoutMs` with starting the browser. On a cold machine where Chrome took longer than that to start, the first page failed as `Timed out loading …; the dev server may be rebuilding or stuck.`
273
+
274
+ Starting the browser now has its own bound of 120 s, `startTimeoutMs` on `PreviewView.probe`. Running out of it reads `Timed out starting the <engine> browser after 120 s.`, where the engine is `chrome` or `webkit`. A browser that misses its bound may still come up late, so later pages in that process try again, but each waits only its own `timeoutMs` for the browser. Once the browser answers, the full bound applies again. So a browser that never starts holds the first page for 120 s, where before it held it for `timeoutMs` (60 s for `akan preview`, 30 s for the code agent's check).
275
+
276
+ - eefd9cb: `akan preview <app> /_akan/studio` opens Studio instead of a 404. Preview added the default locale to every path, and the server routes `/_akan/*` without one, so `/en/_akan/studio` matched no page. A path under `/_akan`, `/__csr`, `/__rsc`, `/.well-known` or the app's API prefix, a file the app's `public/` holds, and the server's own `/favicon.ico`, `/robots.txt`, `/sitemap.xml` (at the root only, the one place the server answers it) and `manifest.webmanifest` now open as written: no locale, and no CSR boot query under `--csr`. Every other path, including one that already starts with a locale or ends in a dotted segment such as `/release/1.2.3`, is a page and gets the default locale as before. The `akan-debug` skill and the `akan preview` reference say so.
277
+ - 01ca04b: `akan preview` opens `/openapi.json` and the default `/mcp` as written, as the server mounts them outside `/:lang`; before, they got the default locale and opened a 404 page. A full URL (`http://localhost:<port>/oauth/token`) now opens exactly as written, with no locale and no CSR boot query, so an endpoint mounted outside the API prefix or a custom MCP path can be opened; before, a full URL was taken by its path and given the locale. A page `--changed` finds always gets the locale, even one at a server route's path such as `/mcp`. A screenshot's file name carries the page's query and a short hash of it, and a long path or query is cut with a hash, so `/_akan/studio?view=runtime` and `?view=signals` no longer overwrite one another and a long query no longer fails the page. The `akan-debug` skill, `akan preview --help` and the `akan preview` reference state the same rule.
278
+ - b101fcf: `akan remove-application`, `remove-library`, `remove-package`, `remove-module` and `remove-scalar` no longer delete a target they picked themselves. Left out, or named but not in the workspace, the target is refused in a terminal or not, with the choices and the line to rerun, such as `` Missing app: this command deletes files and never picks its target, so rerun it as `akan remove-application <app>` (choices: pokedex). `` Before, `akan remove-application` in a one-app workspace removed `apps/<app>` without asking, and without a terminal `akan remove-scalar <name>` removed the scalar from the only app or lib. A terminal is no longer offered a select for these commands. Other commands still take the only app, or the only app or lib without a terminal, as before. A command declares this with `destructive: true` on its target.
279
+ - 44149b1: `akan remove-module` now removes a service module named exactly, as in `akan remove-module pokedex:_billing` for `apps/pokedex/lib/_billing`. Before, no command could remove a service module: `remove-module` left out every `lib/_<name>` folder and refused one by name with `Invalid module name: _billing`. A service module left out or misnamed gets the same refusal as any target of a remove command, and its choices now list the service modules. `create-view`, `create-unit`, `create-template` and `create-crud-page` still take only a model module. A command opts in to service modules by taking `ModuleOrService` instead of `Module`.
181
280
  - 4fcf44f: A new `rename-key` workflow renames a slice key or a Filter query key everywhere it is spelled. That covers the key itself, every name derived from it (`initMemoInPublic`, `memoListInPublic`, `queryByName`) in the app and every lib, and its module dictionary entry. It is the same rename the editor extension's F2 runs, so agents get it through `plan_workflow` / `apply_workflow` and the CLI through `akan workflow plan rename-key --app <app> --module <module> --slice <key> --to <newKey>` (or `--query <key>`). The plan lists each file it will change. A use that could also be another model's is left alone, and `akan verify` then reports it.
281
+ - 627dde4: The route JS budget stops failing deploy builds: a plain `akan build` reports an overage, `akan build --check-budget` fails on it, and CI runs that for `apps/minimal` and `apps/akan`, which now commit their `akan.budget.json`. The rc npm publish, which calls CI, skips that job, so an app's budget never holds a release.
282
+
283
+ - **Report by default:** a plain `akan build`, the one a deploy runs, prints a route over its entry or with none, or an unreadable `akan.budget.json`, as a warning under the route table and passes, as `akan verify` does. `--quiet` drops the rest of the summary but still prints the warning.
284
+ - **`--check-budget`** fails the build on an overage, a route with no entry (a new page records its entry with `--update-budget` in the same change), an unreadable file, or an app with no file, naming every overage and missing entry in one failure.
285
+ - **`--raise-budget`** re-records every route at its measured size and names the entries it raised, for the change that grows a route on purpose. An overage now names it with the app's own name, along with the file and section to edit by hand. `--check-budget`, `--update-budget` and `--raise-budget` exclude each other.
286
+ - **`System` counts as the SSR shell:** the generated root layout imports `System` whole because it serves SSR pages, the CSR shell and MCP App views. The measure now reads that import as `System/SSR.tsx` and leaves out `System`'s CSR and MCP App providers wherever an app imports `System`, since no server page renders them; every client entry is still built. On `apps/minimal` the median route drops from 342KB to 307.5KB brotli and the largest, `/:lang/explore`, from 499.1KB to 473.3KB. On `apps/akan` most routes drop about 1KB, because their other client entries load the providers' dependencies anyway.
287
+
182
288
  - 9a9e1fa: A server page from `akan build` now preloads its client modules from `<head>`, so a cold load stops waiting on chains of imports.
183
289
 
184
290
  - **What is preloaded:** the rsc client and the chunks it imports, the chunks every client reference row (`I` row) in the shell's flight names, and the importmap vendors those chunks import, each with its own chunks. A client URL that only the page's own text carries is never preloaded. Before, only the rsc client and the locale dictionary were preloaded. The browser found the rest one import level at a time, after the document finished.
185
- - **Measured on `apps/minimal`:** `/en/explore` preloads 45 modules and its flight names 18 client chunks, all of them preloaded. `/en/lab/buttons` preloads 112 for 85. Preloading every client component each route's page and layouts import would have meant 237 modules for `/en/explore`, so the preloads follow the flight instead.
291
+ - **Measured on `apps/minimal`:** `/en/explore` preloads 64 modules and its flight names 37 client chunks, all of them preloaded. `/en/lab/buttons` preloads 165 for 137. Preloading every client component each route's page and layouts import would have meant 274 modules for `/en/explore`, so the preloads follow the flight instead.
186
292
  - **A boundary that resolves after the shell** still loads its chunks when its flight rows arrive. `akan start` preloads nothing new, because a dev page loads its client code from the SSR dev registry.
187
293
  - `routes-manifest.json` carries the preload table as `modulePreloads`: the runtime chunks, each vendor's chunks, and the vendors each browser chunk imports.
188
294
 
189
- - 9a9e1fa: `akan build` measures the JavaScript each server route loads, and fails a route that outgrows the budget the app commits.
190
-
191
- - **The measure:** the runtime, every client module statically reachable from the route's page and layouts, and their vendors, counted in the brotli bytes the server sends. A chunk loaded by a dynamic `import()` is left out, and so is the locale dictionary. A new `Measuring route JS` step names the largest route, and the summary lists the ten largest with their brotli and raw sizes. On `apps/minimal` the largest is `/:lang/explore` at 499.1KB brotli (1.3MB raw).
192
- - **The budget:** `akan build <app> --update-budget` writes `apps/<app>/akan.budget.json` with the environment it built for and one `routeJsBrotliKB` entry per route. After that, `akan build` fails a route that passes its entry by more than the larger of 1% and 4KB, as the bundle size gate does, and names the route, its bytes and its limit, so CI stops the growth. The slack absorbs the `AKAN_PUBLIC_*` values a build inlines, so a budget recorded for one environment holds for another, and a failure says when the file was recorded for another one. The update adds a new route, lowers an entry its route now fits under and drops a route that is gone. It never raises an entry: to raise one, edit it by hand in the change that grows the route.
193
- - **Where it fails:** `akan build` fails on an overage or an unreadable file, and `--update-budget` rewrites an unreadable file. `akan verify` warns of each route over its entry and of an unreadable file, one line each, but never fails on them. A mobile or desktop build skips the step.
194
- - **Opt-in:** an app without the file gets the report and nothing fails. A route without an entry is reported, not failed. `akan sync` accepts `akan.budget.json` at an app root.
295
+ - 9a9e1fa: `akan build` measures the JavaScript each server route loads, and reports a route that outgrows the budget the app commits; `akan build --check-budget` fails on it.
296
+
297
+ - **The measure:** the runtime, every client module statically reachable from the route's page and layouts, and their vendors, counted in the brotli bytes the server sends. A chunk loaded by a dynamic `import()` is left out, and so is the locale dictionary. A new `Measuring route JS` step names the largest route, and the summary lists the ten largest with their brotli and raw sizes. On `apps/minimal` the largest is `/:lang/explore` at 473.3KB brotli (1.2MB raw).
298
+ - **The budget:** `akan build <app> --update-budget` writes `apps/<app>/akan.budget.json` with the environment it built for and one `routeJsBrotliKB` entry per route. After that, a route that passes its entry by more than the larger of 1% and 4KB, as the bundle size gate allows, is an overage, named with its bytes and its limit. The slack absorbs the `AKAN_PUBLIC_*` values a build inlines, so a budget recorded for one environment holds for another, and an overage says when the file was recorded for another one. The update adds a new route, lowers an entry its route now fits under and drops a route that is gone. It never raises an entry: `--raise-budget` or a hand edit does, in the change that grows the route.
299
+ - **Where it fails:** only `akan build --check-budget`, on an overage, a route with no entry, an unreadable file or a missing one. A plain `akan build` warns of each but a missing file under its route table, and `--update-budget` rewrites an unreadable file. `akan verify` warns of each route over its entry or with none and of an unreadable file, one line each, but never fails on them. A mobile or desktop build skips the step.
300
+ - **Opt-in:** an app without the file gets the report and nothing fails, unless `--check-budget` asks for it. A route without an entry is reported, and fails only `--check-budget`. `akan sync` accepts `akan.budget.json` at an app root.
301
+
302
+ - af133d7: A route level whose server render fails after the page has started streaming now draws a notice ("This page could not be loaded.") with a "Try again" button in its own place, and the layouts above it stay. Before, the browser rethrew the error with no error boundary above it, so React unmounted the whole page (production error #441, a blank screen). That covered a page or layout below a `.loading()` that throws, and a fetch handle field that reaches no `Load.*` when the server refuses it: awaited in a component below the page, rendered as a child, or `use()`-d by a client component outside `Load.*`.
303
+
304
+ - The generated root layout exports `LevelBoundary`, and server rendering puts it around every route level below that root layout, inside the level's Suspense. The notice is the one a failed level already draws in a CSR app. "Try again" calls `router.refresh()`, and the page's next payload renders the level again.
305
+ - The root layout's own level and any `_overrides` level above it get no boundary: the root layout renders `System.Provider`, which starts the router, so a notice at or above it would have no router to retry with. The root level includes an app's `page/_layout.tsx`, and an error there after the first byte still blanks the page.
306
+ - A not-found or redirect raised below the route after the page started streaming renders nothing in that level's place, as the host answers it.
307
+ - An error that fails a level before the first byte has left still gets the nearest layout's `.error()` and its status, since React's server renderer runs no error boundary. The page's markup is the same as before. Its inline payload gains the boundary's client reference and one wrapper per level, and its head gains a modulepreload for the boundary.
308
+ - **Propagation change:** an error the server streamed now stops at the nearest route level. An error boundary an app put above a layout's `children` no longer sees it. An error thrown while the browser renders a client component carries no digest and propagates as before, so render bugs still surface.
309
+ - **Reporting change:** React now logs a streamed error it caught with `console.error` instead of `reportError`. Window `error` listeners, error trackers that hook them, and the dev HMR client's report no longer see it, and an app has no hook to change the notice. One case still reaches them on a first document load: if the level suspends when React retries it in the browser, for example on a client chunk still loading, React also passes its own recoverable error to `reportError` (#419 in production), not the original error. The server still logs each error, and `akan preview` still reports the page as FAIL.
310
+ - `akanjs/client` exports `isRouteControl(error)`, true for the not-found and redirect digests that both `Load.*` and the route level draw nothing for.
311
+ - What still differs from a refusal before the first byte: such a field takes the notice in place of its whole level, not the layout's `.error()`, and the page answers 200. Hand it to a `Load.*` to keep the rest of the level, or await the handle for `.error()`.
312
+
313
+ - 9055634: Partial RSC commit can now patch a real page, and it patches cleanly. It is still off by default behind `AKAN_PUBLIC_RSC_PARTIAL_COMMIT=1`. With the flag on:
314
+
315
+ - **Which pages render their head through `AkanRouteHead`.** Every page whose head is plain `title`, `meta` and `link` tags now renders it through a client component instead of plain head tags. That way any page can be the one a patch starts from. Patches still only land on pages that set `.config({ rscPatchHeadSafe: true })`.
316
+ - **A plain `.head()` is its own head snapshot.** A page no longer needs a hand-written snapshot. A head with anything else, such as a script or a component, keeps the full render.
317
+ - **React renders the head.** The old patch swapped `<head>` nodes behind React's back. That left a stale or broken head after the next full navigation or a back navigation.
318
+ - **A patch carries only the page's part of the head.** The layouts' part stays on the client, under the layouts the patch keeps. The page's part travels in the `X-Akan-Rsc-Patch-Head-Snapshot` header, which is now capped at 2 KB encoded, down from 12 KB. A larger page head renders whole, and the server logs that once per route.
319
+ - The cap leaves room under nginx's default 4 KB `proxy_buffer_size`, but it doesn't guarantee a fit: router state, trace headers and `Set-Cookie` share that buffer.
320
+ - The docs pages' part is about 1.1 KB, against about 5.7 KB for their whole head.
321
+ - **The layouts a patch keeps follow the new page.** `usePathCtx()` under an SSR page gives the patched page's path, pathname and query, so a menu's active item and a pager move with it.
322
+ - **A full commit after a patch goes straight to the new page's head, path and body.** It no longer shows the last full page for a frame first.
323
+ - **A patch falls back to a full render when the kept layouts would be wrong:**
324
+ - another route group's layout sits at the same URL prefix (`(guest)/account/login` to `(member)/account/settings`);
325
+ - the layouts' head would be different for the target, for example a layout `.head()` that reads a search arg. The router state carries a key of the layouts head its page rendered (`headKey`), and the server compares it with the target's. The key changes together with the rest of the router state, so a navigation started while the previous page is still committing sends that page's key;
326
+ - a route param differs (`/en` to `/ko`);
327
+ - a frame setting differs, such as `transition`;
328
+ - the page navigated from has no patchable head;
329
+ - its frame cannot be resolved.
330
+ - **A client built without the flag no longer asks for patches it cannot apply.** Before, a server running with the flag answered such a client with patches, and every sibling navigation made a second request. Such a client leaves the head key out of the router state it sends.
331
+ - **A refused head-safe patch runs each `.head()` once.** When a patch is refused after its head resolved, the full render reuses that head. Before, it ran every `.head()` a second time.
332
+ - **`@akanjs/devkit`: the SSR runtime manifest keeps every client export of the segment outlet module.** Before, it kept only one.
195
333
 
196
334
  - 27440aa: A production build now runs without Docker: `cd dist/apps/<app> && bun main.js` serves the app with no env set. Until now the env the built server needs (the app and repo names, the serve domain, locales, route prefixes, database modes and the rest) existed only as `ENV` lines in the generated Dockerfile. On a host without the image, such as a PaaS or a test harness, the server stopped at boot with `getEnv() cannot run at build time` unless a start script copied every value by hand.
197
335
 
@@ -248,6 +386,14 @@
248
386
  - **A public env value holding a private key is refused** when the native build records its `AKAN_PUBLIC_*` values, as names with `SECRET`, `TOKEN`, `PASSWORD`, `PRIVATE` or `CREDENTIAL` already were.
249
387
  - **akan-native only warns about `'unsafe-inline'` in `script-src`.** Inline styles under `style-src 'unsafe-inline'` no longer produce a warning; inline scripts are still left unhashed when `script-src` allows them.
250
388
 
389
+ - db5b284: An app using the `shared` and `util` libraries no longer loads `@akanjs/native/core` on its web pages. Their stores imported `akanjs/client/native` for `isNativeShell()` and for the push installation id. That put core and every native plugin wrapper on every page. Native SSO and `usePushNotification` now load the plugin they call on first use inside a shell. The `useCamera`, `useGeoLocation` and `usePurchase` hooks in `akanjs/webkit`, which `shared`'s `Field` and `User.Template` reach, import their plugin and the few core exports they use dynamically, when first called; inside a shell `useCamera` still reads the camera permission at mount. On the minimal app with `shared` merged into its store:
390
+
391
+ - a Link route drops from 148.7 KB raw (38.5 KB brotli) to 101.5 KB raw (23.3 KB brotli);
392
+ - a route drawing `Field` drops from 416.6 KB (113.8 KB brotli) to 370.2 KB (99.8 KB brotli);
393
+ - a route drawing `User.Template` drops from 526.8 KB (140.2 KB brotli) to 481.2 KB (126.3 KB brotli).
394
+
395
+ The runtime guideline and the `no-web-only-api-outside-webkit` message now name `akanjs/client` for `isNativeApp()`, and the native subpaths for push and haptics.
396
+
251
397
  - 5e08722: A coding agent now finds the imports and signatures a first app needs in its skills, instead of reading the akanjs sources.
252
398
 
253
399
  - **The `akan-service` and `akan-page` recipes** start each file with its import lines, and the `akan-service` rules say what `serverMode: "batch"` does: the module, endpoints included, mounts only in a `batch` or `all` process, so a page-facing service leaves it off.
@@ -259,8 +405,13 @@
259
405
  - **Bootstrap.** Each route's `"use client"` entry, every generated root layout and the SSR dev registry start with `import "@apps/<app>/lib/useClient"` and `import "@apps/<app>/lib/st"`, which load the client runtime and the store. They used to import `@apps/<app>/client` bare, and that bundled the whole barrel.
260
406
  - **Narrowed barrel imports.** A named import from an app or lib `client` barrel is still narrowed to the files that define the names. This includes `import { st } from "@apps/<app>/client"` in a component and the generated `import { RootStore as <lib> } from "@libs/<lib>/client"` in `lib/st.ts`.
261
407
  - What the rewrite keeps of the barrel is now the files that define its `usePage` and `st`, normally `lib/useClient` and `lib/st`. It used to keep a bare import of the barrel itself, which put every module's UI of the app and of each merged lib on every route.
262
- - A barrel that defines neither name keeps its bare import, as before.
408
+ - A barrel that lacks either name keeps its bare import, as before. One that defines only one of them is not the generated shape, so what else it runs on import is unknown.
263
409
  - **Namespace re-exports.** A name the barrel re-exports as a namespace (`export * as cnst`, `export * as store`) is now narrowed too. `import { cnst } from "@libs/<lib>/client"` becomes `import * as cnst from "@libs/<lib>/lib/cnst"`, where it used to load the whole barrel.
410
+ - **`akan start`.** The dev module registry narrows app and lib barrels the same way, so a page loads in dev the module UI it loads in production. The narrowed imports are written as relative paths, so a save that adds a barrel import still updates the page without a full rebuild. `akanjs` barrels stay whole in dev: in an installed workspace their files are npm modules, and a save that reached a new one would rebuild the whole registry.
411
+ - On `apps/minimal`, the registry behind `/en/explore`, `/en/memo` and `/en/lab/data` holds 505 modules (2.5MB app, 1.2MB vendor), down from 949 (2.6MB app, 6.0MB vendor).
412
+ - Moving an export to another file of a barrel compiles again the importers whose names now point at that file, and only those. This works during `akan start` and on the next start after a move made while it was stopped.
413
+ - Client entry discovery under `akan start` reads a barrel again when one of its files changes. An export moved into a `"use client"` file is found without a restart.
414
+ - **CSR shell and MCP App views.** The single-file CSR build that native apps load, and each MCP App view, narrow app and lib barrels too; they used to narrow only `akanjs/ui`. On `apps/minimal` the CSR shell is 1.58MB raw / 411.9K br, down from 3.51MB / 828.8K, and its MCP App views are 20-29% smaller.
264
415
  - **Discovery and Tailwind.** Client entry discovery and Tailwind's candidate scan follow the same imports. A lib `"use client"` component is no longer a client entry of every route, and a module UI file that no route imports is no longer scanned.
265
416
  - **Size.** Production build of `apps/minimal`:
266
417
  - A route that renders only `Link` ships 53.1K raw / 17.2K br of route code, down from 226.6K / 67.1K.
@@ -271,6 +422,44 @@
271
422
  - A UI file that reads another UI file's export at its top level, through an import cycle, can now find it uninitialised and throw a TDZ error. Move that read into the component.
272
423
  - Generated module `index.ts` files only collect namespaces, so they are unaffected.
273
424
 
425
+ - 94d3673: Akan Studio lands on the Runtime view when `akan start`'s builder is stopped, not only when there is none or it never answers.
426
+
427
+ - **The dev host marks a reply no builder answered.** A builder request the dev host answers itself carries `kind: "unavailable"`: the builder is stopped, not started yet, failed to start, or exited or was stopped before answering. A failure the builder reports, such as a broken build, carries no kind and reads as before.
428
+ - **`BuilderRpc.isUnavailable(error)`** tells such a failure apart, as `BuilderRpc.isTimeout` does for a request that times out. A bare, empty or unknown `/_akan/studio` view then lands on Runtime, and a view asked for by name still answers 503 with the reason.
429
+ - **Mixed versions keep working.** A server reading a reply from an older dev host, with no kind, answers 503 as before, and an older server ignores the new field.
430
+
431
+ - 3b7247e: A failed tool call now names a code a client or a model can branch on, beside the text it already sent, which is unchanged. No upgrade step is needed: `AgentWireToolResult` and `use-agentic`'s `ToolCallResult` only gain an optional `code`, and `akanjs/common` adds `MCP_FAILURE_META`, `McpFailure` and `FailureCode`.
432
+
433
+ Every code is a bounded token, a dictionary key (`<module>.error.<key>`) or one camelCase identifier, never prose, so no text can pass for one.
434
+
435
+ - **An app's `/mcp`:**
436
+ - A tool error carries `_meta["akanjs/failure"]: { code, statusCode }`, beside the server's own `_meta` for a 2026-07-28 client. The code is the one an HTTP caller gets:
437
+ - a domain `Err` by its dictionary key, such as `base.error.documentNotFound`;
438
+ - an `AkanError` by its code, such as `invalidArgument` for an argument the call got wrong;
439
+ - a 401 or 403 by its status alone (`unauthorized`, `forbidden`);
440
+ - a 5xx by a dictionary key or this server's own `AkanError` code, else by its status (`internalError`, `serviceUnavailable`), never by a code a duck-typed error put in its body.
441
+ - A JSON-RPC error carries `data.code`, which tells apart what `-32602` covers:
442
+ - `unknownTool`, `unknownPrompt` (an unlisted page prompt included) and `unknownResource`;
443
+ - `invalidArgument` for bad arguments or a missing tool name, prompt name or resource uri;
444
+ - a refused screen's `forbidden` or `notFound`.
445
+ A rate-limited call names `tooManyRequests` and the catch-all names `internalError`.
446
+ - An MCP Apps view's call that fails without a domain `Err` restores as an error with that status and code, where it used to be a plain `Error`. A tool the view itself serves to the host names its code in the same `_meta` entry, without a `statusCode`.
447
+ - **`akan mcp`:** a tool error carries the same `_meta["akanjs/failure"]`, with one of these codes:
448
+ - `unknownTool` for a name no mode lists;
449
+ - `toolUnavailable` for a tool outside the server's mode;
450
+ - `invalidArgument` for a missing argument, an unknown guideline name, or a workflow path outside `.akan/workflows/`;
451
+ - `toolFailed` for anything else, with `statusCode` 500. A coded `AkanError` keeps its own code.
452
+ - **The code agent:** an MCP server's tool result keeps the code it named, from `_meta["akanjs/failure"]` or a JSON-RPC error's `data.code`, in the call's `details`.
453
+ - **The in-page agent:** a `toolResults` entry whose tool threw carries `code` beside `error` (see `use-agentic`'s WIRE.md): a dictionary `Err`'s key, else the thrown error's own `code`. A `taint: "source"` tool's result carries none, since its code would travel outside the page-content fence. The bundled Anthropic and OpenAI adaptors send `code` to the model inside the tool result, beside `error`.
454
+
455
+ - 44149b1: A module named in a library that lacks it, such as `akan create-view util:nope`, is refused at once, as one named in an app is. Before, it fell through to the module picker in a terminal, and without one it failed as if no module had been named. Both are now refused, terminal or not, with the modules there are and the line to rerun: `` Unknown module 'util:nope': util has no such module, so rerun it as `akan create-view <sys:module>` (choices: pokedex:card, util:photo). `` An app's used to say only `Invalid module name: nope`.
456
+ - 0d7294c: Narrowed vendor entries hold up during a rolling deploy and on very large builds.
457
+
458
+ - **A route chunk that fails to load during a rolling deploy now loads its page as a document.** A document from the new build can get a page from a replica the deploy has not reached yet, and that page's chunks can import a name the document's narrowed vendor entries lack. Before, the page broke, and React's Flight client kept the failed load, so retrying in the tab failed the same way. Now, if a navigation to another page has not committed, the tab loads its target as a document, which brings a matching import map. If the page is already on screen (a refresh of it counts), the tab reloads it at its current address, fragment and any later query-only change included, and only when the error is a module link or resolve error and the browser is online. A network, ad-blocker or evaluation error leaves the page in place. Only chunks that the latest page navigation's response imports count. The document's own chunks, an overtaken navigation's and a replaced response's do not trigger it. The exception is a refresh of the same page that imports a chunk the document is still loading, which takes that chunk over. Each chunk starts at most one document load per tab, so a chunk that always fails shows its error instead of reloading in a loop. While one document load is under way, another failure does not start a second; the page's next navigation, or its return from the back-forward cache, ends that wait. This applies to `akan build` output only.
459
+ - **A document fallback to the address the tab already shows now reloads it.** A failed refresh, or a back or forward move to a URL with a `#fragment`, fell back with `location.replace` to that same URL, which only scrolls to the fragment and loads nothing. It now calls `location.reload()`.
460
+ - **`akan build` fails when the vendor scan cannot find a route's client entry**, and names the entry. Before, a build that wrote its route bundles somewhere the scan did not look narrowed every vendor entry to nothing. The build passed, and pages threw in the browser.
461
+ - **The vendor scan no longer overflows the stack on large minified chunks.** A function body of about 20,000 statements, which a minifier folds into one comma chain, used to fail `akan build` with `Maximum call stack size exceeded`.
462
+
274
463
  - bd4d45a: `akan verify` now fixes or explains three lint failures that were costly to resolve by hand.
275
464
 
276
465
  - **A daisyUI component class your own CSS defines is no longer refused.**
@@ -284,13 +473,21 @@
284
473
  - The rule's own rewrite is removed. Under `--unsafe` it renamed a `#field` where it was called but not where it was declared.
285
474
  - **A raw `Error` in an `srvkit/` adapter names its fix.** `akan verify` prints the `Err` import path from that file, and where the key goes: the app's or lib's own service dictionary, `lib/_<name>/<name>.dictionary.ts`, as `<name>.error.<key>`.
286
475
 
476
+ - d4d84c6: `akan workflow validate` exits 0 when the only failures left are known baseline blockers (`overallStatus` `passed-with-baseline-blockers`); any other failed validation still exits 1. Over MCP, a passing `apply_workflow` dry run names `apply_workflow` with the same `planPath` and no `dryRun` as `next`, where it named `run_validation`, which had nothing to validate. A failed `akan workflow apply` reports no generated files queued for sync, no recommended validation command and no `akan verify` next action, and a failed field, mutation or slice write (`akan add-field` and its siblings) lists no generated file, validation command or next action; both used to list them as if the write had passed. With `-o json`, `akan workflow plan`, `apply`, `validate` and `report` print only the JSON report on stdout and send their log lines (`File Create:`, sync's warnings) to stderr; `create-module` and `create-scalar` applies used to print them before the report, so stdout did not parse. The text output is unchanged. `add-field` (the workflow and `akan add-field`) imports the type it writes: a scalar of the target from `../__scalar/<scalar>/<scalar>.constant`, a model from `../<model>/<model>.constant`, and `ID`, `Any` and the other `akanjs/base` types from `akanjs/base`, where it imported only `Int` and `Float` and wrote `field(Address)` with no import. A type that is not built in, not imported by the constant and not a scalar or model of the target is refused with `primitive-field-type-unknown`, at plan time and again at apply, before anything is written.
477
+ - d2b2291: A failed workflow no longer reports success to its caller. `akan workflow plan` exits 1 when the plan has an error, `akan workflow apply` when the apply or its `--dry-run` fails, and `akan workflow validate` when its status is `failed` (which includes `passed-with-baseline-blockers`); all three exited 0 before. A dry run of a plan with an error, such as `add-field --type Number`, reports `failed` and lists no changed or generated files, where it used to list the plan's edits under "Automatically Modified". Over MCP, `plan_workflow` names `apply_workflow` in `next` and `approval.canApplyWith` only for a plan without an error, and `apply_workflow` names `run_validation` only when the apply did not fail; a refused plan also drops its "apply this plan" and "validate the apply report" recommendations. The workflows that write into an existing module (`add-field`, `add-enum-field`, `add-mutation`, `add-slice`, `create-ui`, `rename-key`) now refuse a service module, or any folder without its `<module>.constant.ts`, at plan time and again at apply. The `workflow-module-not-database` error lists the target's database modules and points at `create-module`, and for a field at `create-scalar`. Before, `add-field` on a service module passed its plan and dry run and failed only at apply, and `create-ui` wrote a misnamed `_<service>.View.tsx` into it. The `workflow-module-missing` error now lists only database modules too, says a name that matches a service module (with or without its `_`) is one instead of asking "Did you mean \_<service>?", and points at another app or library only when it holds a database module of that name.
287
478
  - adcdf3b: `akan workflow plan` and the `plan_workflow` MCP tool refuse a module the target app or library lacks, for every workflow that writes into an existing module (`add-field`, `add-enum-field`, `add-mutation`, `add-slice`, `create-ui`, `rename-key`). The `workflow-module-missing` error names the module, lists the modules the target has, and points at the module whose name differs only in case or by a leading `_`, at a scalar of that name, or at the app or library that holds it; only when none exists does it point at `create-module`. Before, the plan passed and its dry run reported `passed`. `add-mutation` used to plan a missing module with a warning so that a `create-module` plan could precede it; it now refuses too, so plan it after applying `create-module`. Every workflow now refuses an unknown `app` at plan time, listing the workspace's apps and libraries. `apply` and `--dry-run` check the target again before anything else, so a plan written earlier for a module that is gone fails instead of passing. `plan_workflow` now inspects the MCP server's workspace rather than the process directory.
479
+ - Updated dependencies [bd198af]
288
480
  - Updated dependencies [bc792ab]
481
+ - Updated dependencies [eb88032]
482
+ - Updated dependencies [31f7039]
289
483
  - Updated dependencies [61fbd7d]
290
484
  - Updated dependencies [b3f85fa]
291
485
  - Updated dependencies [a707354]
486
+ - Updated dependencies [4d61170]
487
+ - Updated dependencies [c723713]
292
488
  - Updated dependencies [0351ad4]
293
489
  - Updated dependencies [ba417c6]
490
+ - Updated dependencies [485f707]
294
491
  - Updated dependencies [bb40785]
295
492
  - Updated dependencies [d2bd9b7]
296
493
  - Updated dependencies [b391491]
@@ -302,17 +499,22 @@
302
499
  - Updated dependencies [ddd3d96]
303
500
  - Updated dependencies [3f231a7]
304
501
  - Updated dependencies [96f9ff6]
502
+ - Updated dependencies [af7c411]
305
503
  - Updated dependencies [1ebc57a]
306
504
  - Updated dependencies [c3b5b3c]
505
+ - Updated dependencies [dcb7e61]
307
506
  - Updated dependencies [6d5b544]
507
+ - Updated dependencies [73f8830]
308
508
  - Updated dependencies [958f175]
309
509
  - Updated dependencies [9f30e93]
310
510
  - Updated dependencies [d9eaacc]
311
511
  - Updated dependencies [d9eaacc]
312
512
  - Updated dependencies [c334caf]
513
+ - Updated dependencies [170be15]
313
514
  - Updated dependencies [e143263]
314
515
  - Updated dependencies [e4f7876]
315
516
  - Updated dependencies [cb0fd5b]
517
+ - Updated dependencies [256b6e3]
316
518
  - Updated dependencies [c48d780]
317
519
  - Updated dependencies [3537448]
318
520
  - Updated dependencies [c882491]
@@ -322,15 +524,26 @@
322
524
  - Updated dependencies [9b5bcee]
323
525
  - Updated dependencies [4561152]
324
526
  - Updated dependencies [73e833b]
527
+ - Updated dependencies [d6b3619]
325
528
  - Updated dependencies [b24fef3]
529
+ - Updated dependencies [465ccb9]
530
+ - Updated dependencies [513e48d]
326
531
  - Updated dependencies [5cd1fc3]
327
532
  - Updated dependencies [f47cc82]
533
+ - Updated dependencies [7f0de74]
534
+ - Updated dependencies [c0b84d0]
328
535
  - Updated dependencies [1f93507]
329
536
  - Updated dependencies [5d3cb3e]
330
537
  - Updated dependencies [9a9e1fa]
538
+ - Updated dependencies [af133d7]
539
+ - Updated dependencies [463fd1e]
540
+ - Updated dependencies [9055634]
331
541
  - Updated dependencies [3537448]
542
+ - Updated dependencies [a373d51]
543
+ - Updated dependencies [c723e7a]
332
544
  - Updated dependencies [6c3a303]
333
545
  - Updated dependencies [27440aa]
546
+ - Updated dependencies [bc5fdb0]
334
547
  - Updated dependencies [e3de9ef]
335
548
  - Updated dependencies [e3de9ef]
336
549
  - Updated dependencies [e3de9ef]
@@ -338,12 +551,26 @@
338
551
  - Updated dependencies [e3de9ef]
339
552
  - Updated dependencies [e3de9ef]
340
553
  - Updated dependencies [e3de9ef]
554
+ - Updated dependencies [463fd1e]
341
555
  - Updated dependencies [99fda20]
556
+ - Updated dependencies [db5b284]
342
557
  - Updated dependencies [5e08722]
558
+ - Updated dependencies [91ccf38]
559
+ - Updated dependencies [c2af76a]
343
560
  - Updated dependencies [df32c46]
344
561
  - Updated dependencies [5f809e8]
562
+ - Updated dependencies [76705dd]
345
563
  - Updated dependencies [206bb69]
564
+ - Updated dependencies [170be15]
565
+ - Updated dependencies [cfe50cb]
566
+ - Updated dependencies [94d3673]
567
+ - Updated dependencies [e4c7e5c]
568
+ - Updated dependencies [6291fec]
569
+ - Updated dependencies [3d1d448]
346
570
  - Updated dependencies [0c480c6]
571
+ - Updated dependencies [3b7247e]
572
+ - Updated dependencies [e4c3009]
573
+ - Updated dependencies [0d7294c]
347
574
  - Updated dependencies [d9eaacc]
348
575
  - akanjs@3.2.0
349
576
  - @akanjs/language@3.2.0
package/agentAssets.ts CHANGED
@@ -45,7 +45,7 @@ export class AgentAssets {
45
45
  "modelUtil",
46
46
  "framework",
47
47
  ],
48
- "akan-err": [],
48
+ "akan-err": ["errorCodes"],
49
49
  "akan-deps": [],
50
50
  "akan-debug": [],
51
51
  "akan-page": ["pageRule", "akanApi"],