@akanjs/cli 3.0.0-beta.2 → 3.0.0-beta.4

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.
package/.build-stamp CHANGED
@@ -1 +1 @@
1
- 91f5ad2ee63550b2ce4eee3fe99b7d2f064b37381641718bf796f2f31987b905
1
+ b129370a860bac06e3d96a976bd13d89caf64cc7a00d87d4adde5461f7179cf5
@@ -121,6 +121,24 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
121
121
  reader produced**, not on the file that was picked: a reader that uploads and answers a `url` has already paid
122
122
  what the ceiling exists for, so refusing its 6 MB photo would refuse it for a cost it does not incur. Only the
123
123
  built-in path checks the source size, and there the file itself is the carrier.
124
+ - **An app may also build attachments itself and hand them to `session.send([{ role: "user", text, attachments }])`**,
125
+ which is why `MessageAttachment` is exported from `akanjs/ui` — the composer's path is typed by the `AttachReader`
126
+ callback, that one is not, and an object assembled with no nameable type is the one that gets a field wrong.
127
+ Nothing downstream trusts the result: an attachment whose `mimeType` is not a string is noted like any other
128
+ unreadable one, and its chip renders its name with no preview, because the host wrote the object and the declared
129
+ type is a claim rather than a check. A field that arrives wrong costs that attachment, never the turn.
130
+ - **A `url` carrier is an address the *provider* fetches, so a reader that uploads has to know its storage is
131
+ reachable.** This is the one way an attachment fails with nobody reporting it: the default storage backend
132
+ serves a path only the app can resolve, the adaptor hands it over as written, and the model answers about a
133
+ picture it never saw. Answer `data` when the provider cannot reach the URL — the choice is the reader's,
134
+ because the reader is what chose to upload.
135
+ - **An image type the provider has no block for is refused at the adaptor, not upstream.** `accepts.image` is one
136
+ boolean, so `AgentService.readable` passes every `image/*` through, and the built-in composer reader base64s
137
+ every `image/*` as well — an `AttachReader` answering `null` means "not mine" and falls through to it, so an app
138
+ cannot gate one either. Both shipped vision adaptors therefore match an exact set (`jpeg`, `png`, `gif`, `webp`)
139
+ and name the rest in the text. It matters because an unsupported type is not one unread attachment: it is a
140
+ block the API refuses, so the **whole turn** dies on a vendor 400 — and `image/heic`, the iPhone camera default,
141
+ is the likeliest one an app meets.
124
142
  - **`MessageAttachment.ref` is the host's own handle on the file — carried, never read.** A file id, a storage key,
125
143
  whatever turns the attachment back into something a tool can be handed. The framework only moves it: the model is
126
144
  never shown one, and a tool the app publishes (`useFileFieldTool` below) is what spends it. Without it a host that
@@ -727,6 +727,7 @@ what every developer must know even when not building one.
727
727
  - Put display and predicate logic on the `Light<Model>` class rather than in a util module — see Module File Playbook.
728
728
  - Defaults are a literal for scalars and a thunk for anything constructed. Arrays are `field([T])`; optional is the postfix `.optional()`.
729
729
  - **`field.visual(T)` is a field the page renders and an agent never sees** — a blur placeholder, a rendered HTML body, a serialized geometry. It stays an ordinary stored `property` (persistence, search, forms and the page response untouched) and is stripped wherever a value is masked for an AI caller: every in-page-agent read and every MCP result, along with the MCP readable schema. Unlike `hidden`/`secret` it is cost, not secrecy — nothing is refused over one. Reach for it whenever a field is bulky and useless to a model; that is cheaper than every tool learning to avoid it.
730
+ - **A `field.hidden` / `field.secret` value reads `null` on the client, and the type still declares it.** `SignalContext.resolveReturn` skips both field types while it builds an endpoint's response, and hydration writes `null` over the key rather than leaving it absent — the first branch of the loop in `constant/getDefault.ts`, ahead of the field's own default. So the value is a deliberate `null` behind a type promising a `string`, every use of it typechecks, and the failure lands wherever it is finally dereferenced instead of where it was read. **Guard with `??` or `== null`**: `=== undefined`, a destructuring default and an optional parameter default all catch only a missing key and sail straight past this one. A projection (`pickById(id, { secret: true })`) widens the *server's* read, never the response. If a screen needs the value, the field is neither hidden nor secret; if it only needs to be cheap for a model rather than unseen, that is `field.visual`.
730
731
 
731
732
  ### Scalar & Field Type Reference
732
733
 
@@ -9,6 +9,7 @@ Use this whenever generating constants or scalar constants. It defines the curre
9
9
  - `field(Type).optional()` marks a nullable or optional business value when absence is valid.
10
10
  - `field.hidden(Type).optional()` is for internal state that should not be treated as a normal public field.
11
11
  - `field.secret(Type).optional()` is for sensitive values that should not be selected by default.
12
+ - Neither survives an endpoint response: both are stripped on the way out and hydration writes `null` over the key, while the generated type still declares the field — so a client holds a deliberate `null` behind a type that promises a value, and only `??` / `== null` catch it. A field a browser has to read is neither.
12
13
  - `field([Type])` defines arrays; provide empty array defaults when the app expects list operations.
13
14
 
14
15
  ## Current Akan Patterns
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/cli",
3
- "version": "3.0.0-beta.2",
3
+ "version": "3.0.0-beta.4",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -33,7 +33,7 @@
33
33
  "@langchain/openai": "^1.4.6",
34
34
  "@tailwindcss/node": "^4.3.0",
35
35
  "@trapezedev/project": "^7.1.4",
36
- "akanjs": "3.0.0-beta.2",
36
+ "akanjs": "3.0.0-beta.4",
37
37
  "chalk": "^5.6.2",
38
38
  "commander": "^14.0.3",
39
39
  "dayjs": "^1.11.20",