@akanjs/cli 3.0.0-alpha.5 → 3.0.0-alpha.7

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 (50) hide show
  1. package/.build-stamp +1 -1
  2. package/{agent.command-b0fcx3r2.js → agent.command-pggr92jj.js} +6 -6
  3. package/{application.command-cgmy00gd.js → application.command-692yap1d.js} +4 -4
  4. package/{applicationBuildRunner-n1svrwgt.js → applicationBuildRunner-ha3y8ew8.js} +1 -1
  5. package/buildBatch.proc.js +2 -2
  6. package/{capacitorApp-yyw35vg4.js → capacitorApp-p0z5yab2.js} +4 -2
  7. package/{cloud.command-1m7hfdpk.js → cloud.command-wqfsyzv2.js} +7 -7
  8. package/{context.command-b5heat2a.js → context.command-9bxtdn0w.js} +13 -13
  9. package/{guideline.command-9ew6aqhm.js → guideline.command-nfqahxex.js} +3 -3
  10. package/incrementalBuilder.proc.js +1 -1
  11. package/{index-m4kpmmtj.js → index-2c3e2xh8.js} +1 -1
  12. package/{index-hrwzz2wf.js → index-4hek879p.js} +1 -1
  13. package/{index-nx1vbtsc.js → index-5dw57f0d.js} +5 -5
  14. package/{index-c94nq3c1.js → index-5pmx7bkg.js} +3 -3
  15. package/{index-jkynkyfk.js → index-6rhabeev.js} +1 -1
  16. package/{index-qp089jp0.js → index-7myvn0f0.js} +1 -1
  17. package/{index-exhpp31y.js → index-a1e0j63x.js} +2 -2
  18. package/{index-meh7mmz9.js → index-azv0xjb5.js} +2 -2
  19. package/{index-pfrt7qwh.js → index-bz2sfzzt.js} +4 -4
  20. package/{index-nfxq39kj.js → index-gex7c8kd.js} +4 -4
  21. package/{index-wrrb8rxk.js → index-gmy45vz2.js} +3 -3
  22. package/{index-mn96y1nk.js → index-js368gk9.js} +5 -5
  23. package/{index-jn9vfpwz.js → index-mssqn2sq.js} +2 -2
  24. package/{index-p6txr1ss.js → index-p3f4q532.js} +3 -3
  25. package/{index-0fj4yg7k.js → index-qb61h0k7.js} +2 -2
  26. package/{index-47qxw1tz.js → index-vg0sj9nc.js} +1 -1
  27. package/{index-60a3jfcz.js → index-vtj3zps1.js} +5 -5
  28. package/{index-p69fcwe1.js → index-w6wbb612.js} +11 -11
  29. package/{index-mterpj70.js → index-xhgtkekh.js} +86 -17
  30. package/{index-6npsfpxr.js → index-ztpw544k.js} +3 -3
  31. package/index.js +18 -18
  32. package/{library.command-aa1g8nsa.js → library.command-md9715jz.js} +3 -3
  33. package/{localRegistry.command-kshva1ck.js → localRegistry.command-exkbamyj.js} +6 -6
  34. package/{module.command-b1zzgqde.js → module.command-w5aaddxk.js} +6 -6
  35. package/{package.command-9qv6vr9s.js → package.command-yfkrcy0z.js} +3 -3
  36. package/package.json +2 -2
  37. package/{page.command-k16pw244.js → page.command-echbavp4.js} +3 -3
  38. package/{primitive.command-s60dn1ae.js → primitive.command-9fbhspw2.js} +7 -7
  39. package/{quality.command-p3vaze52.js → quality.command-3pnt9yep.js} +4 -17
  40. package/{repair.command-mfv749ha.js → repair.command-carj4vax.js} +5 -5
  41. package/{routeSourceValidator-cncd92fv.js → routeSourceValidator-e4jmbfcx.js} +2 -38
  42. package/{scalar.command-hs3nwzv1.js → scalar.command-51ryzypc.js} +5 -5
  43. package/templates/workspaceRoot/.cursor/rules/lint-enforced-rules.mdc.template +3 -2
  44. package/templates/workspaceRoot/.cursor/rules/module-file-playbook.mdc.template +1 -0
  45. package/templates/workspaceRoot/.cursor/rules/scalar-modeling.mdc.template +41 -0
  46. package/templates/workspaceRoot/AGENTS.md.template +12 -7
  47. package/templates/workspaceRoot/biome.json.template +25 -1
  48. package/templates/workspaceRoot/docs/AI-DEVELOPMENT.md.template +4 -1
  49. package/{workflow.command-z0e0fk0z.js → workflow.command-91wmvm8k.js} +10 -10
  50. package/{workspace.command-3q1d6kk4.js → workspace.command-wa10mfd9.js} +19 -19
@@ -56,3 +56,44 @@ alwaysApply: false
56
56
  - Declare an image/file field as a relation to `File`: `image: field(File).optional()` for one, `images: field([File])` for many (see `libs/shared/lib/user/user.constant.ts`, `libs/shared/lib/banner/banner.constant.ts`).
57
57
  - The store then auto-generates an `upload<Field>On<Model>(fileList)` action that calls the framework upload mutation and polls file status until it leaves `"uploading"` (`pkgs/akanjs/store/action.ts`).
58
58
  - Storage is wired through the `StorageAdaptor` DI role (default `BlobStorage`, `pkgs/akanjs/service/predefinedAdaptor/storage.adaptor.ts`); the reference implementation is the `file` lib (`libs/shared/lib/file/*`). Do not hand-roll data-URL fallbacks.
59
+
60
+ ### Cascade Remove — the `cascade` option
61
+
62
+ **The value names the direction, and getting it wrong is a data loss.** The two actions can sit on the same field
63
+ shape, so `cascade` never means "related" — it means one of exactly these:
64
+
65
+ - `removeRef` — *when I am removed, remove what this field points at.* Declared on the relation the owner holds:
66
+ `image: field(File, { cascade: "removeRef" })`, arrays included. Only a relation accepts it; a primitive, a bare
67
+ `ID`, and a scalar each fail the class build, because none of them names a document to remove.
68
+ - `removeWith` — *when what this field points at is removed, remove me.* Declared on the child's own reference to
69
+ its owner, so the owner never learns about its children and a lib model can be extended by an app's. Three forms:
70
+ a relation (`agentSession: field(AgentSession, { cascade: "removeWith" })`), an id with `ref`
71
+ (`field(ID, { ref: "agentSession", cascade: "removeWith" })`), or a polymorphic id with `refPath`
72
+ (`field(ID, { refPath: "parentType", cascade: "removeWith" })`). An array, a Map, `ref` together with `refPath`,
73
+ and a field naming no owner each fail the class build.
74
+ - **A `refPath` must name an `enumOf` field.** A free-form owner type is unknowable at build time, so every model's
75
+ removal would have to sweep the polymorphic table on the chance it is the owner. The enum names the candidates and
76
+ the reverse index reaches only them.
77
+ - **A cascade goes through the target's service, never its model** — unless it provably makes no difference. The
78
+ service path is what runs the target's `_postRemove`, which is where a module puts the side effect the removal has
79
+ to carry (`FileService._postRemove` deletes the stored blob there).
80
+ - **Bulk is decided at boot, per target model, for both directions.** When the target has no `remove` schema hook, no
81
+ `_pre`/`_postRemove` (its own or a lib's), no cascade of its own, and no children, one `removeManyByQuery` leaves
82
+ exactly the rows the loop would, so the framework takes it. Adding a `_postRemove` to that model silently flips it
83
+ back to one document at a time — the boot log (`info` summary, `verbose` per edge) is the only place that shows.
84
+ - **The plan is sealed after every service is live**, so a `listenPost("remove")` registered in `onInit` still counts
85
+ and a `removeRef` target the app never mounted fails the boot rather than the first removal. An unmounted
86
+ `removeWith` owner fails the boot too; an unmounted `refPath` candidate only warns, since that list spans optional
87
+ modules by design.
88
+ - **Nothing checks whether another document still references the same target.** `File` in particular is deduped by
89
+ `origin`, so two parents can share one row; declaring `removeRef` says the field owns its target exclusively, and
90
+ that judgement is the declaring model's to make.
91
+ - Removal is soft (`removedAt`) but the storage delete a `_postRemove` performs is not — a cascade is not
92
+ restorable, and reviving the owner does not revive what went with it.
93
+ - A `removeWith` declaration **auto-creates its index** (`{ removedAt, fk }`, or `{ removedAt, typeKey, fk }` when
94
+ polymorphic). Every non-base field lives in the `_doc` JSON column, so the lookup would otherwise scan the table
95
+ on every owner removal.
96
+ - **Query-level removes fire no hooks and therefore no cascade.** `removeManyByQuery` / `updateManyByQuery`, the generated `remove<Filter>` / `update<Filter>`, and the facade's `removeById` / `updateById` stamp
97
+ `removedAt` in one atomic UPDATE, so nothing downstream runs. Remove one document at a time when it cascades.
98
+ - Cascades are **idempotent**: `removedAt IS NULL` is ANDed into every query-level write, so a retry after a partial
99
+ failure re-stamps nothing. Cycles are cut by a visited set carried down the whole chain, with a depth cap of 16.
@@ -261,8 +261,10 @@ final fallback when no CLI command covers the change.
261
261
  | Use JS `#private` in `*.constant.ts`, `*.document.ts`, `*.service.ts`, or `*.store.ts` | `no-js-private-class-method.grit` bans `#private` in exactly those four file suffixes. The rule is scoped by file path, not class shape — `#private` stays the house style under `srvkit/`, including `adapt()` classes. | `private _methodName()` in those four files; `#methodName()` in `srvkit/` |
262
262
  | Use `console.log()` | Biome lint forbids `console.log`. Only `console.error`, `console.info`, `console.warn` are allowed. | Use one of the three allowed console methods, or `this.logger.*` / `new Logger("ClassName")` on the server |
263
263
  | Write a `//!` marker in `ui/`, `webkit/`, `common/`, `page/**/*.tsx`, `*.constant.ts`, `*.store.ts`, or a module component file | `no-bang-comment-in-client.grit` bans it. Bun classifies `//!` and `/*!` as legal comments and keeps them through minification, so the note ships to every visitor. | `// FIXME:` in browser-reachable code; `//!` stays legal in server, `srvkit/`, and CLI files |
264
- | `throw new Error("...")` | `no-throw-raw-error.grit` bans raw errors outside tests, `*.constant.ts`, and `common/`. Raw errors carry no dictionary key, so they cannot be localized or toasted. | `throw new Err("task.error.<key>")` plus an `[en, ko]` entry in the module dictionary's `.error({})` |
265
- | Hand-order Tailwind classes, or reorder them to "fix" a diff | `useSortedClasses` is an error and also sorts the string arguments to `clsx()` and `cva()`. Sorter output like `font-bold text-2xl` looks wrong but is correct. | Write classes in any order and let `akan lint` sort them |
264
+ | `return` a value from a store action | `no-return-in-store-action.grit` bans it. Every method of a `store(...)` class dispatches through `st.do.<action>()`, which is typed `void` / `Promise<void>`, so the value never reaches the caller. | `this.set({ ... })` with the result; a bare `return;` guard, a `return` inside a nested callback, a getter, and a `static` helper all stay legal |
265
+ | `throw new Error("...")` | `no-throw-raw-error.grit` bans raw errors outside tests, `*.constant.ts`, `common/`, and `apps/akan/env/`. Raw errors carry no dictionary key, so they cannot be localized or toasted. | `throw new Err("task.error.<key>")` plus an `[en, ko]` entry in the module dictionary's `.error({})` |
266
+ | Hand-order Tailwind classes, or reorder them to "fix" a diff | `useSortedClasses` is an error and also sorts the string arguments to `cn()`. Sorter output like `font-bold text-2xl` looks wrong but is correct. | Write classes in any order and let `akan lint` sort them |
267
+ | A colour outside the semantic vocabulary — `bg-red-500`, `bg-[#3b82f6]`, `btn-primary`, `text-base-content`, `style={{ color: "#fff" }}` | The theme closes the vocabulary, so these produce **no CSS at all** — the element renders unstyled, and without the lint rules there is no error and no warning either. Raw-palette, arbitrary-colour, daisyUI-legacy and inline-colour rules all catch this. | Semantic tokens: `bg-primary`, `text-foreground/70`, `border-border`. A genuinely fixed colour takes a `// biome-ignore lint/plugin: <reason>` |
266
268
  | `import` a third-party package inside a page, a barrel, or a module file | `no-import-external-library.grit` covers `page/**`, all barrels, and every `*.{constant,dictionary,document,service,signal,store}.ts` and `*.{Template,Unit,Util,View,Zone}.tsx`. | Re-export the symbol from a one-line shim in `base/`, `webkit/`, or `ui/` first, then import that |
267
269
  | Import server APIs (`fs`, `Bun`, `process.env`) in `ui/`, `webkit/`, or `common/` | Server-only imports in client code cause build failures. | Keep server dependencies in `lib/`, `srvkit/`, or `private/` only |
268
270
  | Skip running `akan sync` after deleting a file | Deleted files remain referenced in barrel exports, causing import errors everywhere. | Run `akan sync <name>` after every file add, remove, or rename |
@@ -421,11 +423,14 @@ is convention that keeps hand-written code reading like generated code.
421
423
  `.Template.tsx` files contain zero `useState`: forms are store-driven with `Field.*`, `value={taskForm.x}`, and
422
424
  `onChange={st.do.setXOnTask}` passed by reference.
423
425
  - Read with `st.use.*` and write with `st.do.*`. Client components do not call `fetch.*`.
424
- - Static class strings stay plain strings. Use `clsx` only for a conditional or to merge an incoming `className`,
425
- and merge the caller last: `clsx("base", conditional, className)`. `clsx` comes from `akanjs/client`. No
426
- `twMerge`, no `cn()`.
427
- - Use daisyUI semantic tokens with opacity modifiers (`text-base-content/60`, `bg-base-100/70`). Never `dark:`
428
- theming is the daisyUI theme block in `page/*/styles.css`.
426
+ - Reach for a recipe before writing a look by hand: `buttonRecipe`, `badgeRecipe` and `inputRecipe` from
427
+ `akanjs/ui` carry the button, badge and field surfaces. Call them as `buttonRecipe(variants?, className?)` —
428
+ the second argument merges internally and takes an array, so never wrap it in `cn()`.
429
+ - Static class strings stay plain strings. Reach for `cn` only for a conditional or to merge an incoming
430
+ `className`, and merge the caller last: `cn("base", conditional, className)`. `cn` comes from `akanjs/client`
431
+ and is the only class-combining function — no `clsx`, no raw `twMerge`.
432
+ - Use semantic tokens with opacity modifiers (`text-foreground/60`, `bg-background/70`, `border-border`). Never
433
+ `dark:` — theming is the token block in `page/*/styles.css`, where each token has a `-foreground` pair.
429
434
  - Hoist enum→class lookups to a module-scope `as const` map typed `{ [key in cnst.TaskStatus["value"]]: string }`,
430
435
  not `Record<...>`.
431
436
 
@@ -143,7 +143,8 @@
143
143
  "!**/*.spec.ts",
144
144
  "!**/*.spec.tsx",
145
145
  "!**/*.constant.ts",
146
- "!**/common/**"
146
+ "!**/common/**",
147
+ "!apps/akan/env/**"
147
148
  ],
148
149
  "plugins": ["./node_modules/@akanjs/devkit/lint/no-throw-raw-error.grit"]
149
150
  },
@@ -162,6 +163,10 @@
162
163
  "includes": ["**/*.constant.ts", "**/*.document.ts", "**/*.service.ts", "**/*.store.ts"],
163
164
  "plugins": ["./node_modules/@akanjs/devkit/lint/no-js-private-class-method.grit"]
164
165
  },
166
+ {
167
+ "includes": ["**/*.store.ts"],
168
+ "plugins": ["./node_modules/@akanjs/devkit/lint/no-return-in-store-action.grit"]
169
+ },
165
170
  {
166
171
  "includes": ["**/*.signal.ts"],
167
172
  "plugins": ["./node_modules/@akanjs/devkit/lint/no-redeclare-predefined-endpoint.grit"]
@@ -232,6 +237,25 @@
232
237
  "**/*.Zone.tsx"
233
238
  ],
234
239
  "plugins": ["./node_modules/@akanjs/devkit/lint/no-import-external-library.grit"]
240
+ },
241
+ {
242
+ "includes": [
243
+ "apps/**/*.ts",
244
+ "apps/**/*.tsx",
245
+ "libs/**/*.ts",
246
+ "libs/**/*.tsx",
247
+ "!**/*.test.ts",
248
+ "!**/*.test.tsx",
249
+ "!**/*.spec.ts",
250
+ "!**/*.spec.tsx"
251
+ ],
252
+ "plugins": [
253
+ "./node_modules/@akanjs/devkit/lint/no-raw-palette-class.grit",
254
+ "./node_modules/@akanjs/devkit/lint/no-arbitrary-color.grit",
255
+ "./node_modules/@akanjs/devkit/lint/no-daisyui-legacy-class.grit",
256
+ "./node_modules/@akanjs/devkit/lint/no-inline-color.grit",
257
+ "./node_modules/@akanjs/devkit/lint/no-interpolated-arbitrary-class.grit"
258
+ ]
235
259
  }
236
260
  ]
237
261
  }
@@ -49,8 +49,11 @@ See `docs/GENERATED.md` for the generated file list.
49
49
 
50
50
  `AGENTS.md` holds the full style guide. The rules agents break most often:
51
51
 
52
- - **Never hand-order Tailwind classes** — the linter sorts them, including inside `clsx()`, and its output looks
52
+ - **Never hand-order Tailwind classes** — the linter sorts them, including inside `cn()`, and its output looks
53
53
  unnatural on purpose.
54
+ - **Never use a colour outside the semantic vocabulary** — `bg-red-500`, `bg-[#3b82f6]` and `text-base-content`
55
+ compile to no CSS at all, so the element renders unstyled with no error. Use `bg-primary`, `text-foreground/70`
56
+ and the other tokens defined in `page/*/styles.css`.
54
57
  - **Never `throw new Error`** — throw `new Err("<module>.error.<key>")` with an `[en, ko]` entry in the module
55
58
  dictionary. `common/` cannot import `Err`, so keep throwing code out of it.
56
59
  - **Never import a third-party package** from a page, a barrel, or a module file. Re-export it through a one-line
@@ -1,30 +1,30 @@
1
1
  // @bun
2
2
  import {
3
3
  WorkflowRunner
4
- } from "./index-c94nq3c1.js";
4
+ } from "./index-5pmx7bkg.js";
5
5
  import {
6
6
  PrimitiveScript
7
- } from "./index-pfrt7qwh.js";
7
+ } from "./index-bz2sfzzt.js";
8
8
  import {
9
9
  ModuleScript
10
- } from "./index-60a3jfcz.js";
11
- import"./index-hrwzz2wf.js";
10
+ } from "./index-vtj3zps1.js";
11
+ import"./index-4hek879p.js";
12
12
  import {
13
13
  ScalarScript
14
- } from "./index-wrrb8rxk.js";
14
+ } from "./index-gmy45vz2.js";
15
15
  import"./index-ss469dec.js";
16
16
  import"./index-0cj2zxbm.js";
17
- import"./index-jn9vfpwz.js";
17
+ import"./index-mssqn2sq.js";
18
18
  import {
19
19
  createWorkflowStepRegistry
20
- } from "./index-m4kpmmtj.js";
21
- import"./index-qp089jp0.js";
20
+ } from "./index-2c3e2xh8.js";
21
+ import"./index-7myvn0f0.js";
22
22
  import {
23
23
  Workspace,
24
24
  command,
25
25
  script
26
- } from "./index-jkynkyfk.js";
27
- import"./index-47qxw1tz.js";
26
+ } from "./index-6rhabeev.js";
27
+ import"./index-vg0sj9nc.js";
28
28
  import"./index-mxvakhsm.js";
29
29
  import"./index-xys926f2.js";
30
30
  import"./index-67546d0j.js";
@@ -1,48 +1,48 @@
1
1
  // @bun
2
2
  import {
3
3
  ContextScript
4
- } from "./index-p69fcwe1.js";
5
- import"./index-6npsfpxr.js";
6
- import"./index-c94nq3c1.js";
7
- import"./index-pfrt7qwh.js";
8
- import"./index-60a3jfcz.js";
9
- import"./index-hrwzz2wf.js";
4
+ } from "./index-w6wbb612.js";
5
+ import"./index-ztpw544k.js";
6
+ import"./index-5pmx7bkg.js";
7
+ import"./index-bz2sfzzt.js";
8
+ import"./index-vtj3zps1.js";
9
+ import"./index-4hek879p.js";
10
10
  import {
11
11
  CloudScript
12
- } from "./index-mn96y1nk.js";
12
+ } from "./index-js368gk9.js";
13
13
  import {
14
14
  getLatestPackageVersion,
15
15
  getNpmRegistryUrl
16
- } from "./index-p6txr1ss.js";
16
+ } from "./index-p3f4q532.js";
17
17
  import {
18
18
  PackageScript
19
- } from "./index-meh7mmz9.js";
20
- import"./index-wrrb8rxk.js";
19
+ } from "./index-azv0xjb5.js";
20
+ import"./index-gmy45vz2.js";
21
21
  import"./index-ss469dec.js";
22
- import"./index-mterpj70.js";
22
+ import"./index-xhgtkekh.js";
23
23
  import {
24
24
  GlobalConfig
25
25
  } from "./index-0cj2zxbm.js";
26
26
  import {
27
27
  AgentScript
28
- } from "./index-nfxq39kj.js";
29
- import"./index-jn9vfpwz.js";
30
- import"./index-m4kpmmtj.js";
31
- import"./index-qp089jp0.js";
28
+ } from "./index-gex7c8kd.js";
29
+ import"./index-mssqn2sq.js";
30
+ import"./index-2c3e2xh8.js";
31
+ import"./index-7myvn0f0.js";
32
32
  import {
33
33
  ApplicationScript
34
- } from "./index-nx1vbtsc.js";
34
+ } from "./index-5dw57f0d.js";
35
35
  import"./index-76rn3g2c.js";
36
36
  import {
37
37
  LibraryScript
38
- } from "./index-exhpp31y.js";
38
+ } from "./index-a1e0j63x.js";
39
39
  import {
40
40
  Exec,
41
41
  Workspace,
42
42
  command,
43
43
  runner,
44
44
  script
45
- } from "./index-jkynkyfk.js";
45
+ } from "./index-6rhabeev.js";
46
46
  import"./index-fgc8r6dj.js";
47
47
  import {
48
48
  ThemeValidator,
@@ -59,7 +59,7 @@ import {
59
59
  collectScopeRecipeSources,
60
60
  extractAgentBlock,
61
61
  renderScopeAgentBlock
62
- } from "./index-47qxw1tz.js";
62
+ } from "./index-vg0sj9nc.js";
63
63
  import"./index-mxvakhsm.js";
64
64
  import {
65
65
  collectRecipeSources,