@akanjs/cli 3.0.0-alpha.31 → 3.0.0-alpha.33
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
|
-
|
|
1
|
+
92c020a25f9a2117ffc1aac1e1581b005e93ce7da63656e22aa9756cad18ea57
|
|
@@ -63,6 +63,13 @@ that looks wrong; do not "fix" it back.
|
|
|
63
63
|
exempt because neither is an instance: `cnst.<Enum>["value"]`, whose indexed access resolves to a string union, and
|
|
64
64
|
a `ClientInit` / `ClientView` / `ClientEdit` type argument, which the framework maps to `GetStateObject<…>` plain
|
|
65
65
|
data. Any *other* indexed access is still flagged — `cnst.Banner["image"]` is a `File`.
|
|
66
|
+
**Only prop positions are read** — a `*Props` interface or type alias, and the inline object type on the
|
|
67
|
+
component's own parameter. A `cnst` type that never leaves the file is not a boundary crossing and stays legal: a
|
|
68
|
+
local annotation, a callback parameter the framework itself types with the model
|
|
69
|
+
(`renderItem={(ticket: cnst.LightTicket) => …}`), a module-scope helper, a non-`Props` local shape, and the props
|
|
70
|
+
of a component nested inside another one. A function-typed prop (`onPick?: (t: cnst.LightTicket) => void`) is
|
|
71
|
+
exempt for the same reason — a closure cannot cross the RSC boundary at all, so whoever passes it is a client
|
|
72
|
+
component already holding the value.
|
|
66
73
|
- **No deep imports past a barrel** (`no-deep-internal-import.grit`). Cross-module constant references such as
|
|
67
74
|
`../map/map.constant` are the sanctioned exception.
|
|
68
75
|
- **Never import across the client/server boundary.** Client files (`ui/`, `webkit/`, `page/`, `*.store.ts`, every
|
|
@@ -390,6 +397,15 @@ workflow changes.
|
|
|
390
397
|
- Numbers must use `Int` or `Float` — `Number` is rejected (`pkgs/akanjs/signal/endpointInfo.ts`).
|
|
391
398
|
- `Upload` is valid only inside a mutation flagged for file upload: `mutation([cnst.File], { fileUpload: true }).body("files", [Upload])` (see `libs/shared/lib/file/file.signal.ts`). It is not a model field type.
|
|
392
399
|
|
|
400
|
+
### Mutation HTTP Verb
|
|
401
|
+
|
|
402
|
+
- A `mutation` is `POST`. `{ method: "PATCH" | "PUT" | "DELETE" }` moves it, and one path may carry several verbs
|
|
403
|
+
— a `query` GET and a `mutation` POST on the same custom `path` are mounted side by side. Two endpoints claiming
|
|
404
|
+
the same path **and** verb fail the boot rather than silently shadowing one another.
|
|
405
|
+
- Reach for it only when a foreign wire protocol forces the verb (a client you cannot change that sends
|
|
406
|
+
`PATCH /rest/v1/<table>`). Akan's own `fetch.*` client, the OpenAPI document, and the API explorer all follow
|
|
407
|
+
whatever is declared, so nothing needs restating per caller.
|
|
408
|
+
|
|
393
409
|
### Reserved Endpoint Names
|
|
394
410
|
|
|
395
411
|
- Auto-generated CRUD endpoints (e.g. `create<Model>`, `update<Model>`, `remove<Model>`) already exist for every model. Do not declare an `Endpoint`/`Slice` with a name that collides with them.
|
|
@@ -648,9 +664,10 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
|
|
|
648
664
|
`AKAN_AGENT=false` takes it off — and negotiates streaming via `accept`, so assistant text arrives as it is
|
|
649
665
|
generated with zero app code. The endpoint is a stateless relay and **never executes tools**: every tool runs in
|
|
650
666
|
the caller's own browser session, gated by guards and the approval card. Its guard is `AgentRelayAccess`, which
|
|
651
|
-
**refuses every call until a
|
|
652
|
-
product with accounts
|
|
653
|
-
|
|
667
|
+
**refuses every call until the app names a guard of its own** — the same answer `None` gives, with no boot
|
|
668
|
+
warning. A product with accounts names it in its `option.ts`, `option.setAgentAccess(SignedIn)`, taking the same
|
|
669
|
+
guard classes every endpoint takes (an array is ANDed, `null` clears what a library set); without one the chat
|
|
670
|
+
cannot spend the LLM key.
|
|
654
671
|
`persist` keeps the transcript across reloads (sessionStorage; `{ storage: "local" }` to outlive the tab),
|
|
655
672
|
default off. Re-skin through the `AgentChat` slot in `_overrides.tsx`.
|
|
656
673
|
- **The LLM is configured in `option.ts`, never through the environment.** `option.setLlm({ apiKey, model, host })`
|
|
@@ -693,7 +710,11 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
|
|
|
693
710
|
globally and a component cannot build one per render: pass the list it has — a slice's sort keys, the options a
|
|
694
711
|
prop carried — and it is published and enforced the same way. Neither reaches a set that fills in *after* the
|
|
695
712
|
first render, since a declaration is mount-static; put that in the tool's `guard`, which is re-read per call and
|
|
696
|
-
can name the current values in its refusal.
|
|
713
|
+
can name the current values in its refusal. **An argument type nothing can describe — a model class, `Any`, a
|
|
714
|
+
`Map` — withdraws the whole tool and says so on the console**, naming the tool, the argument and the type; the
|
|
715
|
+
callable still drives the click a person makes. It does not throw: a tool schema is built during render, and an
|
|
716
|
+
agent-tooling mistake that aborted the render would cost the route its server rendering. `st.useState`'s `set`
|
|
717
|
+
degrades the same way, to read-only.
|
|
697
718
|
- **A component that renders once per row publishes nothing.** A tool registered under one name by fifty rows is
|
|
698
719
|
forty-nine collisions and one survivor. The container publishes one tool taking the id instead —
|
|
699
720
|
`removeTask(taskId)`, never fifty `removeTask` — and the agent reads the ids from the `<slice>.items` resource
|
|
@@ -732,6 +753,27 @@ apps and libs never import it directly (`no-import-external-library`) — everyt
|
|
|
732
753
|
- **`prompt()` endpoints double as the chat's slash commands.** There is no listing endpoint — the client reads
|
|
733
754
|
its own serialized signals — so a prompt's dictionary `.desc()` is what the menu shows, and its guards are
|
|
734
755
|
enforced by the prompt's own GET at call time.
|
|
756
|
+
- **The chat answers five slash commands of its own**, listed in the same `/` menu ahead of the prompts:
|
|
757
|
+
`/new` (`/clear`), `/retry`, `/copy`, `/help` and `/tools`. An app writes none of them and cannot add one — the
|
|
758
|
+
extension point for a product's own command is a `prompt()` endpoint, which is guarded and server-side.
|
|
759
|
+
**A built-in wins a name collision with a prompt of the same name**, the mirror image of the tool rule: a
|
|
760
|
+
component's `st.tool` shadows a built-in it means to replace, but no library's prompt may take `/new` away from
|
|
761
|
+
the user who typed it — so a shadowed prompt is dropped from the menu rather than listed twice. `/new` and
|
|
762
|
+
`/copy` are also dispatched *before* the is-a-turn-running check, because mid-turn is exactly when they are
|
|
763
|
+
reached for; `/new` therefore aborts the turn it is clearing and waits for it to wind down, since the loop
|
|
764
|
+
clears its own running flag a microtask later and a transcript emptied before that lands is one the dying turn
|
|
765
|
+
appends onto.
|
|
766
|
+
- **A command's output is a `local` message: rendered in the transcript, withheld from the wire.** The transcript
|
|
767
|
+
*is* the model's history, so `/help` text appended plainly would come back next turn as something the assistant
|
|
768
|
+
believes it said. `session.note(text)` is the only way to write one, `session.report(error)` stays what a
|
|
769
|
+
host-side *failure* lands in, and `local` messages are left out of a `/copy` export too — they are the chat
|
|
770
|
+
talking to itself. Their text is user-facing, so it goes through `l("base.*")` like every other chat string.
|
|
771
|
+
- **`/copy` exists because nothing else keeps the transcript.** The relay is stateless and the conversation lives
|
|
772
|
+
only in that browser, so an export is the one path a wrong answer has to whoever could fix it — which is why it
|
|
773
|
+
carries the route and the timestamp. `/retry` replays only the trailing user message, leaving anything before it
|
|
774
|
+
in place, so a prompt's own preamble is not sent twice.
|
|
775
|
+
- **↑ and ↓ in the composer walk what was sent.** A single-line input has nothing of its own on the vertical
|
|
776
|
+
arrows, and the half-written draft they were walked away from comes back at the bottom of the walk.
|
|
735
777
|
- The framework publishes five built-ins on every store surface: `navigate` (internal paths only, the same
|
|
736
778
|
router `Link` rides), `goBack` (this session's history — global, because history is not a control a page owns and
|
|
737
779
|
a page that draws no back link is not one you may not leave), `readScreen` (the rendered DOM as compact text —
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akanjs/cli",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.33",
|
|
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.
|
|
37
|
+
"akanjs": "3.0.0-alpha.33",
|
|
38
38
|
"chalk": "^5.6.2",
|
|
39
39
|
"commander": "^14.0.3",
|
|
40
40
|
"dayjs": "^1.11.20",
|