@akanjs/cli 3.0.0-alpha.52 → 3.0.0-alpha.53

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
- 01ea8ed0ffbaa2533de87a90a0f930f8914cabb255e887095d14f13152decabd
1
+ 75e6ebc02c938b9bfa7b3bbce9bbe0a59753853c08b168184806c0321e3bb71e
@@ -1,8 +1,8 @@
1
1
  // @bun
2
2
  import {
3
3
  CloudScript
4
- } from "./index-ssrz6xr1.js";
5
- import"./index-wmwcwn1f.js";
4
+ } from "./index-rrcdemys.js";
5
+ import"./index-d3vvvzsd.js";
6
6
  import"./index-x1dbhd80.js";
7
7
  import {
8
8
  GlobalConfig
@@ -41,6 +41,9 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
41
41
  replacement for `AgentBubble` carries its own `memo`, since the transcript re-renders on every delta. Only then
42
42
  `AgentChat`, which replaces the panel whole: it also replaces the slash commands, the compaction notice and the
43
43
  approval gate, so reach for it when the *layout* differs, not when the look does.
44
+ A manifest reaches a layout-mounted chat like any other component: the override provider wraps the whole layout
45
+ stack, root layouts included. `UiOverrideProvider` is also a public `akanjs/ui` export, for giving one mount site
46
+ a different slot map than its route would.
44
47
  - **The composer is a textarea**: Enter sends, Shift+Enter writes a newline, and it grows to a few lines before
45
48
  it scrolls. The vertical arrows still walk what was sent, but only from the first or last line — anywhere else
46
49
  the caret is the textarea's own. On a phone the panel is the whole screen (it is a card from `sm:` up) and it
@@ -116,12 +119,19 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
116
119
 
117
120
  ## Publishing A Tool
118
121
  - **Declare the tool beside the control that already does it.**
119
- `st.tool("x", { desc }).arg("id", ID).exec(fn)` publishes one action and returns the callable to hand to
120
- `onClick` — one handler for the person and the agent, which is the point: a button wired to an inline arrow can
121
- be clicked by a person and by nobody else. `.exec()` is the only hook, so the chain completes in one
122
- unconditional statement, and the callable carries `data-akan-action` like a store setter does. A `remove*` name
123
- defaults to a confirm gate. Reach a store action from the body — `.exec((id) => st.do.removeX(id))` — which is
124
- how an agent gets CRUD; `st.do` on its own reaches nobody.
122
+ `st.tool("x").desc("…").arg("id", ID).opt("force", Boolean).exec(fn)` publishes one action and returns the
123
+ callable to hand to `onClick` — one handler for the person and the agent, which is the point: a button wired to
124
+ an inline arrow can be clicked by a person and by nobody else. `.desc()` is required and comes first, `.arg()`
125
+ is an argument the caller must pass and `.opt()` one it may leave out (the `exec` parameter is then `| null`),
126
+ and `.exec()` is the only hook, so the chain completes in one unconditional statement and the callable carries
127
+ `data-akan-action` like a store setter does. A `remove*` name defaults to a confirm gate. Reach a store action
128
+ from the body — `.exec((id) => st.do.removeX(id))` — which is how an agent gets CRUD; `st.do` on its own
129
+ reaches nobody.
130
+ - **The second argument is how the call behaves, never what it is.** `{ settle, confirm, guard }`:
131
+ `settle: false` marks a read that returns what is already there and skips the wait; every other tool is waited
132
+ out before its effect on the screen is reported, because a write may still be landing when `exec` resolves. A
133
+ tool that reads and one that writes are otherwise the same declaration — there is no taxonomy field, because
134
+ nothing downstream would read one.
125
135
  - **A falsy name declares the tool without publishing it** — the callable still drives the click a person makes,
126
136
  and the agent never learns the tool exists. That is the only way a conditional surface stays legal, because
127
137
  `.exec()` is a hook and the declaration can never be skipped: withhold the name, not the call. `st.useState`
@@ -132,7 +142,7 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
132
142
  - **An `enumOf` class is a complete argument type on its own**: `.arg("mode", TaskStatus)` publishes the values as
133
143
  the argument's `enum`, refuses anything off them by name at call time, and narrows the `.exec` parameter to the
134
144
  value union — nothing else to write, and the scalar (`string` / `integer` / `number`) comes from the values.
135
- **A value set the *render* decides takes `.arg(name, type, { oneOf })`** instead, because `enumOf` registers
145
+ **A value set the *render* decides takes `.arg(name, type, { oneOf })`** (or `.opt`) instead, because `enumOf` registers
136
146
  globally and a component cannot build one per render: pass the list it has — a slice's sort keys, the options a
137
147
  prop carried — and it is published and enforced the same way. Neither reaches a set that fills in *after* the
138
148
  first render, since a declaration is mount-static; put that in the tool's `guard`, which is re-read per call and
@@ -145,10 +155,13 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
145
155
  tool that captured its own row would be fifty registrations of one name, forty-nine of them shadowed, and the
146
156
  survivor would remove whichever row happened to mount last. Take the id instead — `removeTask(taskId)`, never
147
157
  fifty `removeTask` — and every row's registration is then interchangeable, so a row component may publish after
148
- all: say so with `shared: true` and the repeats are one declaration rather than a warned-about clash. The ids
149
- come from the `<slice>.items` resource `Load.Units` and `Data.ListContainer` already expose. `shared` is a claim
150
- about the *tool*, not a way to quiet a console: two rows whose tools would do different things (a different
151
- `modal`, a different redirect) are not interchangeable, and that one wants a `namespace` or nothing at all.
158
+ all. **Nothing is written to say so: the description says it.** Fifty rows of one component produce one name
159
+ and one `.desc()`, which is the same declaration fifty times over and warns about nothing; a second description
160
+ arriving under a name already taken is two components that happened to pick one word, and that warns. So the
161
+ rule an app follows is about the sentence, not about a flag — two tools that would do different things
162
+ (a different `modal`, a different redirect) cannot honestly share a description, and that pair wants a
163
+ `namespace` or nothing at all. The ids come from the `<slice>.items` resource `Load.Units` and
164
+ `Data.ListContainer` already expose.
152
165
 
153
166
  ## What `akanjs/ui` Publishes For You
154
167
  - **`akanjs/ui` publishes its own controls, so an app writes nothing for them.** `Data.ListContainer` (and every
@@ -199,9 +212,9 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
199
212
  **The patch writes each plain field through that control's own published tool, not the setter underneath it** —
200
213
  which is what carries the control's `transform`, so a field cannot normalize one way for `setPhoneOnBizAccount`
201
214
  and another way for `fillBizAccountForm`. Only a composite, having no control, dispatches its setter directly.
202
- The patch tool is registered `shared`, because the entry is a pure function of the model: a form put on screen by
203
- a shell that subscribes it (`Model.EditModal`) *and* by the `Template` inside it is one declaration twice over,
204
- not a clash — so neither has to suppress the other, and neither is asked to.
215
+ The patch tool's entry is a pure function of the model, so a form put on screen by a shell that subscribes it
216
+ (`Model.EditModal`) *and* by the `Template` inside it registers the same name with the same description twice
217
+ over — one declaration, not a clash. Neither has to suppress the other, and neither is asked to.
205
218
  - **A `disabled` control publishes nothing, so the agent never gets a lever the person cannot pull.** Every value
206
219
  control reads it — `Field.*`, `Input.*`, `Select`, `Switch`, and the four relation pickers — and disabling a
207
220
  mounted control withdraws its tool for as long as it stays disabled. One gate covers both writers: with no
@@ -271,18 +284,26 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
271
284
  `Field.TextList` does, and the only place an inline arrow is the right answer rather than a bug.
272
285
 
273
286
  ## Reading State
274
- - **Reading is per key, not per store.** `st.useState(name, initial, meta)` publishes local state (read-only
275
- unless `set:` names a type) and `st.expose(name, value)` a derived value. A subscribed store key is listed in
287
+ - **Reading is per key, not per store.** `st.expose(name, Type).desc("…").value(v)` publishes a derived value and
288
+ `st.useState(name, Type, { set: true }).desc("…").init(initial)` local state, read-only without `set`. Both
289
+ end in a hook, so a conditional surface withholds the name rather than skipping the chain. A subscribed store key is listed in
276
290
  the state context block by name and pulled with `readState(key)`, masked by the model that key declares — while
277
291
  a key the screen does not read stays unreadable even when a sibling key of the same store is live. **There is no
278
292
  store-level exposure declaration**: a store class says nothing about agents, and `st.use.x({ agent: false })` is
279
293
  how the component that subscribes a value keeps it off the surface. Base-store plumbing does the same at the
280
294
  call site — `st.use.path({ agent: false })`, `st.use.tryJwt({ agent: false })` — so routing and the caller's
281
295
  credential stay off the surface unless a component opts a key in, as ThemeToggle does for `theme`.
282
- - **Model-facing text is English, always** — tool `desc`, `instructions`, Guide text. The `l()` rule covers
296
+ - **Model-facing text is English, always** — every `.desc()`, `instructions`, Guide text. The `l()` rule covers
283
297
  strings a *user* reads: Chat's own buttons go through `l("base.*")`, the model's text never does.
284
- - A masked model never crosses the boundary: a value whose `hidden`/`secret` fields are populated is refused at
285
- read unless a `mask:` model is named — the same rule and wording as `AgentBridge.read`.
298
+ - **The declared type is the mask.** `st.expose`/`st.useState` take a scalar, an enum, a model class, a one-level
299
+ array of any of those, or `Any`. A model class both typechecks what the component hands over — the state object,
300
+ so a hydrated document and a plain copy of one are equally accepted — and strips the model's `hidden`, `secret`,
301
+ and `visual` fields on the way out, by the model that was *named* rather than by whatever class the value still
302
+ happens to carry. A `Date` leaves as an ISO string. `Any` is the escape hatch and passes the value untouched, so
303
+ a payload nobody modeled stays publishable and its owner keeps the tokens it costs. A type nothing can read (a
304
+ `Map`, an `Upload`, a class that is not a model) is reported on the console and left unpublished, never thrown —
305
+ the same degradation an undescribable `.arg` gets. `.value()` also takes a thunk, which is read when the agent
306
+ reads: that is the shape for a value assembled out of a ref the children fill in after the render.
286
307
  - **A field the page needs and an agent does not is `field.visual`.** `abstractData: field.visual(String)` — a blur
287
308
  placeholder, a rendered HTML body, a serialized geometry: real data the screen renders, and hundreds of tokens per
288
309
  record no question is answered from. It is stripped by `mask`, so it leaves every agent-facing read and every MCP
@@ -529,14 +529,21 @@ package; apps and libs never import it directly (`no-import-external-library`)
529
529
  `option.setAgentAccess(SignedIn)`.
530
530
  - **The LLM is configured in `option.ts`, never through the environment.** `option.setLlm({ apiKey, model, host })`
531
531
  fills whichever adaptor holds `LlmAdaptorRole`; swap providers with `option.applyAdaptor(LlmAdaptorRole, X)`.
532
- - **Declare the tool beside the control that already does it.** `st.tool("x", { desc }).arg("id", ID).exec(fn)`
533
- publishes one action and returns the callable to hand to `onClick` — one handler for the person and the agent.
534
- Reach a store action from the body (`.exec((id) => st.do.removeX(id))`); `st.do` on its own reaches nobody.
532
+ - **Declare the tool beside the control that already does it.**
533
+ `st.tool("x").desc("…").arg("id", ID).opt("force", Boolean).exec(fn)` publishes one action and returns the
534
+ callable to hand to `onClick` — one handler for the person and the agent. `.desc()` is required and comes first,
535
+ `.arg()` is an argument the caller must pass and `.opt()` one it may, and `.exec()` is the only hook. Reach a
536
+ store action from the body (`.exec((id) => st.do.removeX(id))`); `st.do` on its own reaches nobody.
535
537
  - **Publish a tool only where the screen already renders the control.** A falsy name declares the tool without
536
538
  publishing it, which is how a conditional surface stays legal — `.exec()` is a hook, so withhold the name, not
537
539
  the call. A `disabled` control publishes nothing.
538
540
  - **A component that renders once per row takes the row id as an argument**, never a closure over it — fifty
539
- registrations of one name leave forty-nine shadowed. Interchangeable repeats say so with `shared: true`.
541
+ registrations of one name leave forty-nine shadowed. The description is what makes the repeats one declaration:
542
+ same name and same `.desc()` is the same tool registered fifty times, and only a second description under that
543
+ name warns.
544
+ - **`{ settle: false }` is the read that returns what is already there.** Every other tool is waited out before
545
+ what it did to the screen is reported, because a write may still be landing when `exec` resolves. `{ confirm }`
546
+ and `{ guard }` ride the same object; a `remove*` name confirms by default.
540
547
  - **A component that can render twice on one screen takes a `namespace` prop** (`Tab`, `Dialog`, `Dropdown`,
541
548
  `ScreenNavigator`) and publishes nothing without one.
542
549
  - **Forms publish themselves**: a `Field.*` / `Input.*` / `Select` / `Switch` handed `onChange={st.do.setXOnY}`
@@ -544,6 +551,11 @@ package; apps and libs never import it directly (`no-import-external-library`)
544
551
  nothing — normalize with the control's `transform` prop, and multi-write with a `_postSet<Field>` store method.
545
552
  - **Reading is per key, not per store.** `st.use.x({ agent: false })` keeps a subscribed key off the surface;
546
553
  a key no component reads is unreadable. A value with populated `hidden`/`secret` fields is refused at read.
554
+ - **A component's own value is published by its declared type.** `st.expose("taskId", ID).desc("…").value(v)` for
555
+ a derived value and `st.useState("tab", String, { set: true }).desc("…").init("all")` for local state — the type
556
+ typechecks what is handed over and decides how it is read, so a model class masks by that model. `Any` is the
557
+ escape hatch: no typecheck, and the value passes untouched. `.value()` also takes a thunk, read when the agent
558
+ reads.
547
559
  - **Return what answers the question, not the record.** A tool's value is capped at 20,000 characters before it
548
560
  enters the transcript and clipped with a note the model reads (`ToolOutput.limit`), because a store key is sized
549
561
  for a screen and not for a model's window: one `readState` of a list whose rows carry inlined bytes is megabytes,
@@ -562,7 +574,7 @@ package; apps and libs never import it directly (`no-import-external-library`)
562
574
  - The framework publishes five built-ins on every store surface — `navigate`, `goBack`, `readScreen`,
563
575
  `readState(key)`, `highlight(target)` — plus `askUser`, which the session owns. **There is no general-purpose
564
576
  wait**: publish an `st.tool` beside the control that starts the work and let it await the work.
565
- - **Model-facing text is English, always** — tool `desc`, `instructions`, Guide text. The `l()` rule covers
577
+ - **Model-facing text is English, always** — every `.desc()`, `instructions`, Guide text. The `l()` rule covers
566
578
  strings a *user* reads.
567
579
 
568
580
  Full contract — the chat's own options, attachments and speech, zones, what `akanjs/ui` publishes for you, slash
@@ -283,7 +283,7 @@ ${chalk.green("\u27A4")} Authentication Required`));
283
283
  return;
284
284
  }
285
285
  }
286
- await Promise.all(akanPkgs.map(async (library) => {
286
+ for (const library of akanPkgs) {
287
287
  Logger.info(`Publishing ${library}@${nextVersion} to ${registry ?? "npm"}...`);
288
288
  await workspace.spawn("npm", ["publish", "--tag", tag, ...this.#getRegistryArgs(registry), ...this.#getLocalRegistryAuthArgs(registry)], {
289
289
  cwd: path.join(workspace.workspaceRoot, "dist/pkgs", library),
@@ -291,7 +291,7 @@ ${chalk.green("\u27A4")} Authentication Required`));
291
291
  stdio: "inherit"
292
292
  });
293
293
  Logger.info(`${library}@${nextVersion} is published to ${registry ?? "npm"}`);
294
- }));
294
+ }
295
295
  Logger.info(`All libraries are published to ${registry ?? "npm"}`);
296
296
  }
297
297
  async update(workspace, tag = "latest", { registryUrl } = {}) {
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  CloudRunner
4
- } from "./index-wmwcwn1f.js";
4
+ } from "./index-d3vvvzsd.js";
5
5
  import {
6
6
  PackageScript
7
7
  } from "./index-x1dbhd80.js";
package/index.js CHANGED
@@ -19,16 +19,16 @@ import path from "path";
19
19
 
20
20
  // pkgs/@akanjs/cli/commandModules.ts
21
21
  var commandModules = {
22
- workspace: async () => (await import("./workspace.command-zg8me6fg.js")).WorkspaceCommand,
22
+ workspace: async () => (await import("./workspace.command-s2g36sgr.js")).WorkspaceCommand,
23
23
  agent: async () => (await import("./agent.command-tsx1nsdj.js")).AgentCommand,
24
24
  application: async () => (await import("./application.command-n8ex8g9h.js")).ApplicationCommand,
25
25
  library: async () => (await import("./library.command-p3jgf5h2.js")).LibraryCommand,
26
- localRegistry: async () => (await import("./localRegistry.command-jewr722x.js")).LocalRegistryCommand,
26
+ localRegistry: async () => (await import("./localRegistry.command-5hp7am6e.js")).LocalRegistryCommand,
27
27
  package: async () => (await import("./package.command-fbpa6r4w.js")).PackageCommand,
28
28
  module: async () => (await import("./module.command-hb3xm07r.js")).ModuleCommand,
29
29
  page: async () => (await import("./page.command-92vrmw96.js")).PageCommand,
30
30
  context: async () => (await import("./context.command-s7a41qjs.js")).ContextCommand,
31
- cloud: async () => (await import("./cloud.command-eqafzn1a.js")).CloudCommand,
31
+ cloud: async () => (await import("./cloud.command-v5g0c7nm.js")).CloudCommand,
32
32
  guideline: async () => (await import("./guideline.command-qrw84ttb.js")).GuidelineCommand,
33
33
  scalar: async () => (await import("./scalar.command-zcsjgvax.js")).ScalarCommand,
34
34
  primitive: async () => (await import("./primitive.command-k6b9jfxr.js")).PrimitiveCommand,
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  CloudRunner,
4
4
  getNpmRegistryUrl
5
- } from "./index-wmwcwn1f.js";
5
+ } from "./index-d3vvvzsd.js";
6
6
  import {
7
7
  PackageScript
8
8
  } from "./index-x1dbhd80.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/cli",
3
- "version": "3.0.0-alpha.52",
3
+ "version": "3.0.0-alpha.53",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -34,7 +34,7 @@
34
34
  "@langchain/openai": "^1.4.6",
35
35
  "@tailwindcss/node": "^4.3.0",
36
36
  "@trapezedev/project": "^7.1.4",
37
- "akanjs": "3.0.0-alpha.52",
37
+ "akanjs": "3.0.0-alpha.53",
38
38
  "chalk": "^5.6.2",
39
39
  "commander": "^14.0.3",
40
40
  "dayjs": "^1.11.20",
@@ -11,11 +11,11 @@ import"./index-ss469dec.js";
11
11
  import"./index-kkya2ped.js";
12
12
  import {
13
13
  CloudScript
14
- } from "./index-ssrz6xr1.js";
14
+ } from "./index-rrcdemys.js";
15
15
  import {
16
16
  getLatestPackageVersion,
17
17
  getNpmRegistryUrl
18
- } from "./index-wmwcwn1f.js";
18
+ } from "./index-d3vvvzsd.js";
19
19
  import {
20
20
  PackageScript
21
21
  } from "./index-x1dbhd80.js";