@akanjs/cli 3.0.0-beta.9 → 3.0.1

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 (224) hide show
  1. package/.build-stamp +1 -1
  2. package/CodeAgent-zfab7pkn.js +9 -0
  3. package/CodeAgentRpcHost-p7h6n2hp.js +7 -0
  4. package/CodeAgentRpcListener-7p7z5dd7.js +97 -0
  5. package/CodeTui-0zhnr0pw.js +1457 -0
  6. package/README.ko.md +83 -28
  7. package/README.md +70 -27
  8. package/TunnelShare-cwh9ezsm.js +9 -0
  9. package/{agent.command-0q17pnrs.js → agent.command-aja6z9mn.js} +8 -9
  10. package/akanCode.js +102 -0
  11. package/application.command-049ehgx3.js +246 -0
  12. package/{applicationBuildRunner-kxwbssgn.js → applicationBuildRunner-75n5rpwp.js} +121 -77
  13. package/buildBatch.proc.js +120 -32
  14. package/cloud.command-gw4kqxt8.js +95 -0
  15. package/cloud.script-c723cpcb.js +20 -0
  16. package/code.command-x9t6z5nw.js +154 -0
  17. package/commandManifest.json +1 -1
  18. package/consoleToStderr-h5bryj94.js +7 -0
  19. package/context.command-yfbe1rtd.js +48 -0
  20. package/context.runner-erfe68j5.js +21 -0
  21. package/{dependencyScanner-shs82ynp.js → dependencyScanner-06z2dmrr.js} +2 -2
  22. package/{devTui-m1atgkc9.js → devTui-q7k7bakd.js} +122 -40
  23. package/fileSys-wzzrntkw.js +9 -0
  24. package/guideline.command-kq9gp690.js +42 -0
  25. package/guidelines/agentRule/agentRule.instruction.md +154 -26
  26. package/guidelines/conventions/conventions.instruction.md +138 -48
  27. package/guidelines/mcpRule/mcpRule.instruction.md +7 -5
  28. package/guidelines/queryRule/queryRule.instruction.md +21 -7
  29. package/guidelines/runtimeRule/runtimeRule.instruction.md +291 -6
  30. package/guidelines/ssrRule/ssrRule.instruction.md +4 -2
  31. package/guidelines/transportRule/transportRule.instruction.md +10 -8
  32. package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +20 -0
  33. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +66 -3
  34. package/incrementalBuilder.proc.js +564 -109
  35. package/{index-2tv3fdx4.js → index-150s07n8.js} +1230 -1459
  36. package/{index-vyvre9en.js → index-25fvrxmy.js} +6 -2
  37. package/{index-kcxmv48c.js → index-2ahj896a.js} +45 -79
  38. package/index-2wc41k5w.js +49 -0
  39. package/index-3hx1z96c.js +87 -0
  40. package/{index-q0y2jq9j.js → index-52w0fvh8.js} +21 -4
  41. package/{index-04bk599g.js → index-5g4rkrvt.js} +10 -17
  42. package/index-5pvxf7z0.js +53 -0
  43. package/index-5q14pwzd.js +69 -0
  44. package/{index-vxtad5bd.js → index-66yspb67.js} +5 -8
  45. package/index-7md2g9vw.js +6 -0
  46. package/index-7p4c0yer.js +1058 -0
  47. package/{index-d43r08tf.js → index-8b639zes.js} +77 -150
  48. package/{index-ktb5njgy.js → index-8kvy8qb4.js} +49 -99
  49. package/index-94s080qm.js +266 -0
  50. package/index-9dp031by.js +12 -0
  51. package/{index-0g7r8xz3.js → index-a37by9hn.js} +114 -232
  52. package/{index-k2j1hc4r.js → index-b95yhqjr.js} +12 -12
  53. package/{index-3d9y066c.js → index-bjwxs904.js} +9 -8
  54. package/{index-2xp0kfkt.js → index-br8pkrk1.js} +37 -25
  55. package/index-c14nsvnv.js +700 -0
  56. package/index-c6eggbee.js +123 -0
  57. package/index-d2242ksy.js +99 -0
  58. package/{index-92zztqy1.js → index-dy0jx9ay.js} +2 -17
  59. package/{index-a64esmtb.js → index-fkvb79qe.js} +523 -1022
  60. package/index-h54yj9wr.js +1119 -0
  61. package/{index-by5gpp8x.js → index-hj6w4ka1.js} +2 -1
  62. package/{index-y6n8nmny.js → index-kn5d4jmg.js} +75 -203
  63. package/index-m3xsb1ms.js +4300 -0
  64. package/{index-gyd220p2.js → index-mb59b8x0.js} +554 -577
  65. package/{index-j9yhg404.js → index-mzjb6zp4.js} +4 -7
  66. package/index-p6pbz9n5.js +25 -0
  67. package/{index-sj5vxr8f.js → index-qe71g4ze.js} +983 -898
  68. package/index-rfcz04w9.js +187 -0
  69. package/{index-hwkygn9s.js → index-senscydg.js} +331 -36
  70. package/{index-ffvk10zz.js → index-vs8mefhy.js} +107 -241
  71. package/index-wa5jbxj1.js +760 -0
  72. package/index-y5ga5w9t.js +2729 -0
  73. package/{index-9077wzd2.js → index-y7hx1ygz.js} +43 -26
  74. package/{index-h7yw2z9n.js → index-zzvvc845.js} +8 -14
  75. package/index.js +23 -22
  76. package/{library.command-qzzbj6d8.js → library.command-keqjevpp.js} +4 -5
  77. package/{localRegistry.command-vyrgg4xw.js → localRegistry.command-pydeq5zf.js} +23 -43
  78. package/{module.command-rq5hq3ax.js → module.command-dkrnqx3v.js} +8 -12
  79. package/{package.command-d9hd6v9n.js → package.command-wmc0ys5y.js} +6 -7
  80. package/package.json +15 -7
  81. package/{page.command-126d56te.js → page.command-tf3erhrv.js} +4 -5
  82. package/{primitive.command-taxd1538.js → primitive.command-7hqpegj4.js} +9 -23
  83. package/prompter-76k56b37.js +8 -0
  84. package/{quality.command-6gsna0a3.js → quality.command-8122axq3.js} +205 -377
  85. package/{recipeScanner-fpagtgc1.js → recipeScanner-4b69ybe0.js} +1 -1
  86. package/{repair.command-tq2dgy72.js → repair.command-mcy12h0n.js} +11 -35
  87. package/{routeSourceValidator-apyqw7wk.js → routeSourceValidator-7ycnfz0e.js} +0 -6
  88. package/{scalar.command-3bcmrrkv.js → scalar.command-vvvbzttc.js} +7 -11
  89. package/skills/akan-code/SKILL.md +130 -0
  90. package/skills/akan-debug/SKILL.md +42 -0
  91. package/skills/akan-deps/SKILL.md +50 -0
  92. package/skills/akan-err/SKILL.md +39 -0
  93. package/skills/akan-module/SKILL.md +45 -0
  94. package/skills/akan-scaffold/SKILL.md +76 -0
  95. package/skills/akan-scalar/SKILL.md +52 -0
  96. package/skills/akan-service/SKILL.md +34 -0
  97. package/skills/akan-store/SKILL.md +67 -0
  98. package/skills/akan-ui/SKILL.md +63 -0
  99. package/skills/akan-validate/SKILL.md +44 -0
  100. package/{subspace.command-eddzqpx3.js → subspace.command-pzvqfy5h.js} +53 -62
  101. package/templates/__scalar/__model__/__model__.abstract.md.template +8 -0
  102. package/templates/app/page/_index.tsx +257 -258
  103. package/templates/app/page/_layout.tsx +5 -1
  104. package/templates/app/page/_overrides.tsx +12 -0
  105. package/templates/app/page/styles.css.template +316 -14
  106. package/templates/app/public/apple-touch-icon.png +0 -0
  107. package/templates/app/public/favicon.ico +0 -0
  108. package/templates/app/public/jelly/cloud.webp +0 -0
  109. package/templates/app/public/jelly/comet.webp +0 -0
  110. package/templates/app/public/jelly/moon.webp +0 -0
  111. package/templates/app/public/jelly/planet.webp +0 -0
  112. package/templates/app/public/jelly/rocket.webp +0 -0
  113. package/templates/app/public/jelly/star.webp +0 -0
  114. package/templates/app/public/jelly/sugar.webp +0 -0
  115. package/templates/app/public/logo.png +0 -0
  116. package/templates/app/ui/Recipe/index.ts +9 -0
  117. package/templates/app/ui/Recipe/jellyButton.ts +63 -0
  118. package/templates/appSample/lib/__scalar/workHistory/workHistory.abstract.ts +8 -39
  119. package/templates/appSample/lib/_noti/noti.abstract.ts +6 -29
  120. package/templates/appSample/lib/task/Task.Unit.tsx +1 -1
  121. package/templates/appSample/lib/task/Task.Util.tsx +10 -13
  122. package/templates/appSample/lib/task/Task.View.tsx +2 -2
  123. package/templates/appSample/lib/task/Task.Zone.tsx +5 -2
  124. package/templates/appSample/lib/task/task.abstract.ts +12 -32
  125. package/templates/appSample/lib/task/task.signal.spec.ts +1 -15
  126. package/templates/appSample/lib/task/task.signal.test.ts +15 -1
  127. package/templates/appSample/lib/task/task.signal.ts +10 -8
  128. package/templates/appSample/page/task/[taskId]/_index.tsx +6 -6
  129. package/templates/appSample/page/task/[taskId]/edit.tsx +5 -4
  130. package/templates/appSample/page/task/_index.tsx +4 -3
  131. package/templates/appSample/page/task/_layout.tsx +1 -1
  132. package/templates/appSample/page/task/new.tsx +5 -4
  133. package/templates/appSample/srvkit/{AuthGuard.ts → guards.ts} +7 -4
  134. package/templates/appSample/srvkit/{SessionInternalArg.ts → internalArgs.ts} +6 -4
  135. package/templates/appSample/ui/GlobalLoading.tsx +2 -1
  136. package/templates/appSample/ui/QuantityControl.tsx +3 -3
  137. package/templates/client.ts +7 -30
  138. package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -1
  139. package/templates/crudPages/[__model__Id]/page.tsx +2 -1
  140. package/templates/crudPages/new/page.tsx +2 -1
  141. package/templates/crudPages/page.tsx +2 -1
  142. package/templates/crudSinglePage/page.tsx +2 -1
  143. package/templates/lib/__lib/lib.dictionary.ts +0 -2
  144. package/templates/lib/__lib/lib.document.ts +0 -2
  145. package/templates/lib/sig.ts +8 -30
  146. package/templates/localDev/docker-compose.yaml.template +3 -14
  147. package/templates/module/__model__.signal.ts +12 -4
  148. package/templates/pkgRoot/tsconfig.json.template +2 -7
  149. package/templates/server.ts +1 -3
  150. package/templates/service/__model__.abstract.md.template +8 -0
  151. package/templates/workspaceRoot/.gitignore.template +0 -1
  152. package/templates/workspaceRoot/AGENTS.md.template +6 -0
  153. package/templates/workspaceRoot/package.json.template +1 -3
  154. package/tunnel.command-82zz5xnq.js +129 -0
  155. package/{typeChecker-3xgrzc2v.js → typeChecker-px49mezc.js} +1 -1
  156. package/typecheck.proc.js +1 -1
  157. package/workflow.command-y8x3kgjv.js +79 -0
  158. package/{workspace.command-06wvstgr.js → workspace.command-jvsb7brc.js} +79 -109
  159. package/abstractCompactor-gmkc0z8j.js +0 -102
  160. package/application.command-18y0s485.js +0 -204
  161. package/applicationReleasePackager-4yasxwv9.js +0 -244
  162. package/capacitorApp-36rbr858.js +0 -12
  163. package/cloud.command-av97ndh6.js +0 -94
  164. package/cloud.script-cm11xjdz.js +0 -20
  165. package/context.command-5v37ef3n.js +0 -81
  166. package/devTuiView-0hc2emhe.js +0 -9
  167. package/getDirname-dr3jz1xg.js +0 -7
  168. package/guideline.command-4pz9g1rt.js +0 -360
  169. package/guidelines/agentRule/agentRule.generate.json +0 -31
  170. package/guidelines/componentRule/componentRule.generate.json +0 -31
  171. package/guidelines/conventions/conventions.generate.json +0 -25
  172. package/guidelines/cssRule/cssRule.generate.json +0 -31
  173. package/guidelines/docPageRule/docPageRule.generate.json +0 -31
  174. package/guidelines/docPageRule/docPageRule.instruction.md +0 -25
  175. package/guidelines/docSyncRule/docSyncRule.generate.json +0 -31
  176. package/guidelines/docSyncRule/docSyncRule.instruction.md +0 -25
  177. package/guidelines/enumConstant/enumConstant.generate.json +0 -31
  178. package/guidelines/enumConstant/enumConstant.instruction.md +0 -28
  179. package/guidelines/fieldRule/fieldRule.generate.json +0 -31
  180. package/guidelines/framework/framework.generate.json +0 -32
  181. package/guidelines/mcpRule/mcpRule.generate.json +0 -35
  182. package/guidelines/modelConstant/modelConstant.generate.json +0 -32
  183. package/guidelines/modelDictionary/modelDictionary.generate.json +0 -32
  184. package/guidelines/modelDocument/modelDocument.generate.json +0 -31
  185. package/guidelines/modelService/modelService.generate.json +0 -31
  186. package/guidelines/modelSignal/modelSignal.generate.json +0 -31
  187. package/guidelines/modelStore/modelStore.generate.json +0 -31
  188. package/guidelines/modelTemplate/modelTemplate.generate.json +0 -31
  189. package/guidelines/modelUnit/modelUnit.generate.json +0 -31
  190. package/guidelines/modelUtil/modelUtil.generate.json +0 -31
  191. package/guidelines/modelView/modelView.generate.json +0 -31
  192. package/guidelines/modelZone/modelZone.generate.json +0 -31
  193. package/guidelines/moduleCodegen/moduleCodegen.generate.json +0 -31
  194. package/guidelines/moduleCodegen/moduleCodegen.instruction.md +0 -28
  195. package/guidelines/moduleOverview/moduleOverview.generate.json +0 -31
  196. package/guidelines/queryRule/queryRule.generate.json +0 -31
  197. package/guidelines/recipeRule/recipeRule.generate.json +0 -31
  198. package/guidelines/runtimeRule/runtimeRule.generate.json +0 -25
  199. package/guidelines/scalarConstant/scalarConstant.generate.json +0 -32
  200. package/guidelines/scalarDictionary/scalarDictionary.generate.json +0 -32
  201. package/guidelines/scalarModule/scalarModule.generate.json +0 -31
  202. package/guidelines/sharedUiUsage/sharedUiUsage.generate.json +0 -31
  203. package/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +0 -25
  204. package/guidelines/ssrRule/ssrRule.generate.json +0 -31
  205. package/guidelines/transportRule/transportRule.generate.json +0 -31
  206. package/guidelines/utilUiUsage/utilUiUsage.generate.json +0 -31
  207. package/guidelines/utilUiUsage/utilUiUsage.instruction.md +0 -25
  208. package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +0 -24
  209. package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +0 -33
  210. package/index-47pj3aee.js +0 -76
  211. package/index-5ystnsd5.js +0 -841
  212. package/index-6wwzs1bc.js +0 -7
  213. package/index-a17x49vg.js +0 -229
  214. package/index-m0xccmmm.js +0 -228
  215. package/index-meh558jy.js +0 -65
  216. package/index-rtxxan88.js +0 -471
  217. package/index-te54x9zm.js +0 -338
  218. package/index-w8kmx1b6.js +0 -2176
  219. package/index-wt7qrtd4.js +0 -1516
  220. package/templates/__scalar/__model__/__model__.abstract.md +0 -28
  221. package/templates/module/__model__.abstract.md +0 -28
  222. package/templates/service/__model__.abstract.md +0 -28
  223. package/templates/workspaceRoot/patches/react-dom@19.2.7.patch.template +0 -62
  224. package/workflow.command-gtdnzvbz.js +0 -108
@@ -1,17 +1,319 @@
1
1
  @import "tailwindcss";
2
2
  @import "akanjs/ui/styles.css";
3
3
 
4
- /* The theme system (brand-neutral default palette, @theme inline mapping, dark variant, and runtime
5
- data-theme switching) is fully provided by akanjs/ui/styles.css. This app works from the import alone.
6
-
7
- To use this app's own brand colors, override the tokens like this:
8
-
9
- :root,
10
- [data-theme="dark"] {
11
- --primary: #xxxxxx;
12
- --primary-foreground: #ffffff;
13
- }
14
- [data-theme="light"] {
15
- --primary: #xxxxxx;
16
- }
17
- */
4
+ /* The jelly star palette. akanjs/ui/styles.css owns the theme system (token mapping, dark variant, runtime
5
+ data-theme switching), so a rebrand only overrides the token values below. The star red (--jelly) is a fill
6
+ color; --primary carries white text, so it is one step darker to keep 4.5:1 contrast. */
7
+ :root,
8
+ [data-theme="light"] {
9
+ --background: #f1f1ee;
10
+ --foreground: #0d0d0e;
11
+ --primary: #e02d27;
12
+ --primary-foreground: #ffffff;
13
+ --secondary: #0d0d0e;
14
+ --secondary-foreground: #f6f6f3;
15
+ --accent: #7650d8;
16
+ --accent-foreground: #ffffff;
17
+ --neutral: #26262a;
18
+ --neutral-foreground: #f6f6f3;
19
+ --info: #1f6fe0;
20
+ --info-foreground: #ffffff;
21
+ --success: #3f8f1f;
22
+ --success-foreground: #ffffff;
23
+ --warning: #f2b51c;
24
+ --warning-foreground: #0d0d0e;
25
+ --destructive: #c4161c;
26
+ --destructive-foreground: #ffffff;
27
+ --open: #5aa82a;
28
+ --open-foreground: #0d0d0e;
29
+ --muted: #e6e6e1;
30
+ --muted-foreground: #66666b;
31
+ --card: #fbfbf9;
32
+ --card-foreground: #0d0d0e;
33
+ --popover: #ffffff;
34
+ --popover-foreground: #0d0d0e;
35
+ --border: #dcdcd6;
36
+ --input: #d4d4ce;
37
+ --ring: #e02d27;
38
+ --jelly: #ef3a2d;
39
+ --studio-shadow: color-mix(in oklab, #3a2a20 16%, transparent);
40
+ --sky-top: #dfe5f7;
41
+ --sky-bottom: #f6eadf;
42
+ }
43
+
44
+ [data-theme="dark"] {
45
+ --background: #0f1129;
46
+ --foreground: #f3f1fb;
47
+ --primary: #e02d27;
48
+ --primary-foreground: #ffffff;
49
+ --secondary: #f3f1fb;
50
+ --secondary-foreground: #0f1129;
51
+ --accent: #a585e0;
52
+ --accent-foreground: #0f1129;
53
+ --neutral: #262a4d;
54
+ --neutral-foreground: #f3f1fb;
55
+ --info: #4b8ef0;
56
+ --info-foreground: #0f1129;
57
+ --success: #7cc23a;
58
+ --success-foreground: #0f1129;
59
+ --warning: #f6c437;
60
+ --warning-foreground: #0f1129;
61
+ --destructive: #e5383b;
62
+ --destructive-foreground: #ffffff;
63
+ --open: #7cc23a;
64
+ --open-foreground: #0f1129;
65
+ --muted: #1a1d3b;
66
+ --muted-foreground: #a6a8c9;
67
+ --card: #161935;
68
+ --card-foreground: #f3f1fb;
69
+ --popover: #1b1e40;
70
+ --popover-foreground: #f3f1fb;
71
+ --border: #2b2f57;
72
+ --input: #33376a;
73
+ --ring: #f0392e;
74
+ --jelly: #f2402f;
75
+ --studio-shadow: color-mix(in oklab, #02030f 65%, transparent);
76
+ --sky-top: #25215f;
77
+ --sky-bottom: #2d1749;
78
+ }
79
+
80
+ :root {
81
+ --planet: #1f6fe0;
82
+ --rocket: #82c43c;
83
+ --moon: #f6e27a;
84
+ --cloud: #a585e0;
85
+ --comet: #e3228e;
86
+ }
87
+
88
+ @theme inline {
89
+ --color-jelly: var(--jelly);
90
+ --color-planet: var(--planet);
91
+ --color-rocket: var(--rocket);
92
+ --color-moon: var(--moon);
93
+ --color-cloud: var(--cloud);
94
+ --color-comet: var(--comet);
95
+ --radius-box: 1.5rem;
96
+ --radius-field: 0.875rem;
97
+ }
98
+
99
+ /* A sampled damped spring: overshoots the target by 18%, wobbles twice and settles. */
100
+ @theme {
101
+ --ease-jelly: linear(0, 0.42 6%, 0.86 13%, 1.12 21%, 1.18 26%, 1.13 32%, 1 41%, 0.95 48%, 0.97 56%, 1.01 66%, 1.005 78%, 1);
102
+ }
103
+
104
+ /* html and body both paint a background color, so body's background is not propagated to the canvas: the sky
105
+ sits on body, and isolation keeps the grain layer above body's own background. */
106
+ @layer base {
107
+ body {
108
+ isolation: isolate;
109
+ background-image:
110
+ radial-gradient(120% 60% at 50% -14%, var(--sky-top), transparent 64%),
111
+ radial-gradient(110% 55% at 50% 114%, var(--sky-bottom), transparent 68%);
112
+ background-attachment: fixed;
113
+ }
114
+
115
+ body::before {
116
+ content: "";
117
+ position: fixed;
118
+ inset: 0;
119
+ z-index: -1;
120
+ pointer-events: none;
121
+ opacity: 0.06;
122
+ mix-blend-mode: multiply;
123
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E");
124
+ }
125
+
126
+ [data-theme="dark"] body::before {
127
+ opacity: 0.1;
128
+ mix-blend-mode: overlay;
129
+ }
130
+
131
+ h1,
132
+ h2 {
133
+ letter-spacing: -0.035em;
134
+ }
135
+
136
+ ::selection {
137
+ background-color: color-mix(in oklab, var(--jelly) 24%, transparent);
138
+ }
139
+ }
140
+
141
+ @keyframes jelly-intro {
142
+ from {
143
+ opacity: 0;
144
+ translate: 0 1.25rem;
145
+ filter: blur(6px);
146
+ }
147
+ }
148
+
149
+ @keyframes jelly-breathe {
150
+ 0%,
151
+ 100% {
152
+ scale: 1 1;
153
+ }
154
+ 50% {
155
+ scale: 1.035 0.965;
156
+ }
157
+ }
158
+
159
+ @keyframes jelly-wobble {
160
+ 0% {
161
+ scale: 1 1;
162
+ }
163
+ 16% {
164
+ scale: 1.16 0.86;
165
+ }
166
+ 32% {
167
+ scale: 0.9 1.1;
168
+ }
169
+ 48% {
170
+ scale: 1.06 0.95;
171
+ }
172
+ 64% {
173
+ scale: 0.97 1.03;
174
+ }
175
+ 82% {
176
+ scale: 1.01 0.99;
177
+ }
178
+ 100% {
179
+ scale: 1 1;
180
+ }
181
+ }
182
+
183
+ @keyframes jelly-float {
184
+ 0%,
185
+ 100% {
186
+ translate: 0 0;
187
+ rotate: calc(var(--float-tilt, 4deg) * -1);
188
+ }
189
+ 50% {
190
+ translate: 0 calc(var(--float-rise, 0.9rem) * -1);
191
+ rotate: var(--float-tilt, 4deg);
192
+ }
193
+ }
194
+
195
+ @utility intro-rise {
196
+ @media (prefers-reduced-motion: no-preference) {
197
+ animation: jelly-intro 1.1s cubic-bezier(0.16, 1, 0.3, 1) both;
198
+ animation-delay: var(--intro-delay, 0ms);
199
+ }
200
+ }
201
+
202
+ @utility jelly-breathe {
203
+ transform-origin: 50% 100%;
204
+ @media (prefers-reduced-motion: no-preference) {
205
+ animation: jelly-breathe 3.2s ease-in-out infinite;
206
+ }
207
+ }
208
+
209
+ @utility jelly-wobble {
210
+ transform-origin: 50% 100%;
211
+ @media (prefers-reduced-motion: no-preference) {
212
+ animation: jelly-wobble 0.9s ease-out both;
213
+ }
214
+ }
215
+
216
+ @utility jelly-float {
217
+ @media (prefers-reduced-motion: no-preference) {
218
+ animation: jelly-float var(--float-duration, 6s) ease-in-out var(--float-delay, 0s) infinite;
219
+ }
220
+ }
221
+
222
+ @utility squish {
223
+ transition:
224
+ scale 700ms var(--ease-jelly),
225
+ translate 700ms var(--ease-jelly);
226
+ &:hover {
227
+ scale: 1.04 0.97;
228
+ }
229
+ &:active {
230
+ scale: 1.08 0.9;
231
+ transition-duration: 90ms;
232
+ }
233
+ }
234
+
235
+ @utility tint-* {
236
+ --tint: --value(--color-*);
237
+ }
238
+
239
+ /* A gummy surface. public/jelly/sugar.webp is a high-pass of the logo star's sugar coating (128 gray = no change),
240
+ laid on in hard-light so every tint gets the same sugar grain. */
241
+ @utility jelly {
242
+ --jelly-tint: var(--tint, var(--primary));
243
+ --jelly-deep: color-mix(in oklab, var(--jelly-tint) 70%, black);
244
+ --jelly-haze: color-mix(in oklab, var(--jelly-tint) 55%, white);
245
+ background-color: var(--jelly-tint);
246
+ background-image:
247
+ url("/jelly/sugar.webp"),
248
+ radial-gradient(120% 95% at 26% -8%, color-mix(in oklab, white 26%, transparent), transparent 58%),
249
+ radial-gradient(110% 90% at 60% 125%, color-mix(in oklab, var(--jelly-deep) 30%, transparent), transparent 60%);
250
+ background-size:
251
+ 100px 100px,
252
+ 100% 100%,
253
+ 100% 100%;
254
+ background-repeat: repeat, no-repeat, no-repeat;
255
+ background-blend-mode: hard-light, normal, normal;
256
+ box-shadow:
257
+ inset 0 0 0 1px color-mix(in oklab, var(--jelly-haze) 40%, transparent),
258
+ inset 0 0 8px 1px color-mix(in oklab, white 20%, transparent),
259
+ inset 0 -3px 6px color-mix(in oklab, var(--jelly-deep) 28%, transparent),
260
+ 0 6px 10px -6px color-mix(in oklab, var(--jelly-deep) 65%, transparent),
261
+ 0 1px 2px color-mix(in oklab, black 12%, transparent);
262
+ }
263
+
264
+ @utility jelly-glass {
265
+ --jelly-tint: var(--tint, var(--card));
266
+ background-color: color-mix(in oklab, var(--card) 95%, var(--jelly-tint));
267
+ background-image:
268
+ radial-gradient(120% 70% at 20% -20%, color-mix(in oklab, white 55%, transparent), transparent 60%),
269
+ radial-gradient(90% 60% at 100% 120%, color-mix(in oklab, var(--jelly-tint) 9%, transparent), transparent 70%);
270
+ box-shadow:
271
+ inset 0 1px 0 color-mix(in oklab, white 70%, transparent),
272
+ inset 0 -1px 0 color-mix(in oklab, var(--jelly-tint) 14%, transparent),
273
+ 0 22px 44px -28px var(--studio-shadow),
274
+ 0 2px 6px -3px var(--studio-shadow);
275
+ @variant dark {
276
+ background-color: color-mix(in oklab, var(--card) 92%, var(--jelly-tint));
277
+ background-image:
278
+ radial-gradient(120% 70% at 20% -20%, color-mix(in oklab, white 7%, transparent), transparent 60%),
279
+ radial-gradient(90% 60% at 100% 120%, color-mix(in oklab, var(--jelly-tint) 14%, transparent), transparent 70%);
280
+ box-shadow:
281
+ inset 0 1px 0 color-mix(in oklab, white 11%, transparent),
282
+ inset 0 -1px 0 color-mix(in oklab, var(--jelly-tint) 18%, transparent),
283
+ 0 22px 44px -28px var(--studio-shadow),
284
+ 0 2px 6px -3px var(--studio-shadow);
285
+ }
286
+ }
287
+
288
+ /* The same sugar, clipped to the glyphs of plain text-primary text. Clipping replaces the element's background, so
289
+ elements with a surface of their own (bg-*, jelly, glass) and currentColor drawings are skipped, and icons inside
290
+ get their color back. */
291
+ .text-primary:not(svg, [class*="bg-"], [class*="jelly"], [class*="glass"], [class*="-current"]) {
292
+ background-color: var(--primary);
293
+ background-image:
294
+ url("/jelly/sugar.webp"),
295
+ linear-gradient(
296
+ to bottom,
297
+ color-mix(in oklab, black 8%, var(--primary)),
298
+ color-mix(in oklab, white 14%, var(--primary)) 22%,
299
+ var(--primary) 60%,
300
+ color-mix(in oklab, black 8%, var(--primary))
301
+ );
302
+ background-size:
303
+ 100px 100px,
304
+ 100% 1lh;
305
+ background-origin: content-box;
306
+ background-blend-mode: hard-light, normal;
307
+ -webkit-background-clip: text;
308
+ background-clip: text;
309
+ color: transparent;
310
+ text-decoration-color: var(--primary);
311
+ & :is(svg, [class*="-current"]) {
312
+ color: var(--primary);
313
+ }
314
+ /* A heading's tight leading pushes descenders out of the box, where a text-clipped background is never painted. */
315
+ :is(h1, h2, h3, h4, h5, h6) & {
316
+ padding-block: 0.15em;
317
+ margin-block: -0.15em;
318
+ }
319
+ }
Binary file
Binary file
@@ -0,0 +1,9 @@
1
+ import type { AppInfo, LibInfo } from "akanjs";
2
+
3
+ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
4
+ return {
5
+ filename: "index.ts",
6
+ content: `export { type JellyButtonVariants, jellyButtonRecipe } from "./jellyButton";
7
+ `,
8
+ };
9
+ }
@@ -0,0 +1,63 @@
1
+ import type { AppInfo, LibInfo } from "akanjs";
2
+
3
+ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
4
+ return {
5
+ filename: "jellyButton.ts",
6
+ content: `import { recipe, tv } from "akanjs/ui";
7
+
8
+ /** Sugared gummy button with the same variants as akanjs's \`buttonRecipe\`; \`page/_overrides.tsx\` binds it to every akanjs/ui Button. ghost/outline/link stay surfaceless. */
9
+ export const jellyButtonRecipe = recipe(
10
+ tv({
11
+ base: "squish inline-flex cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-full font-bold focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
12
+ variants: {
13
+ variant: {
14
+ default: "text-foreground",
15
+ primary: "tint-primary text-primary-foreground",
16
+ secondary: "tint-secondary text-secondary-foreground",
17
+ accent: "tint-accent text-accent-foreground",
18
+ neutral: "tint-neutral text-neutral-foreground",
19
+ outline: "border border-foreground/12 bg-background/70 text-foreground hover:bg-foreground/5",
20
+ ghost: "text-foreground/75 hover:bg-foreground/6 hover:text-foreground",
21
+ destructive: "tint-destructive text-destructive-foreground",
22
+ success: "tint-success text-success-foreground",
23
+ warning: "tint-warning text-warning-foreground",
24
+ info: "tint-info text-info-foreground",
25
+ link: "text-primary underline-offset-4 hover:underline",
26
+ },
27
+ size: {
28
+ xs: "h-6 px-2.5 text-xs",
29
+ sm: "h-8 px-3.5 text-sm",
30
+ md: "h-10 px-5 text-sm",
31
+ lg: "h-12 px-7 text-base",
32
+ icon: "h-10 w-10 px-0",
33
+ },
34
+ shape: {
35
+ default: "",
36
+ square: "aspect-square px-0",
37
+ circle: "aspect-square px-0",
38
+ },
39
+ outline: { true: "border bg-transparent", false: "" },
40
+ },
41
+ compoundVariants: [
42
+ { variant: "default", outline: false, class: "jelly-glass" },
43
+ {
44
+ variant: ["primary", "secondary", "accent", "neutral", "destructive", "success", "warning", "info"],
45
+ outline: false,
46
+ class: "jelly",
47
+ },
48
+ { variant: "primary", outline: true, class: "border-primary text-primary hover:bg-primary/8" },
49
+ { variant: "secondary", outline: true, class: "border-secondary text-secondary hover:bg-secondary/8" },
50
+ { variant: "accent", outline: true, class: "border-accent text-accent hover:bg-accent/8" },
51
+ { variant: "neutral", outline: true, class: "border-neutral text-neutral hover:bg-neutral/8" },
52
+ { variant: "destructive", outline: true, class: "border-destructive text-destructive hover:bg-destructive/8" },
53
+ { variant: "success", outline: true, class: "border-success text-success hover:bg-success/8" },
54
+ { variant: "warning", outline: true, class: "border-warning text-warning hover:bg-warning/8" },
55
+ { variant: "info", outline: true, class: "border-info text-info hover:bg-info/8" },
56
+ ],
57
+ defaultVariants: { variant: "primary", size: "md", shape: "default" },
58
+ }),
59
+ );
60
+ export type JellyButtonVariants = NonNullable<Parameters<typeof jellyButtonRecipe>[0]>;
61
+ `,
62
+ };
63
+ }
@@ -3,45 +3,14 @@ import type { AppInfo, LibInfo } from "akanjs";
3
3
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
4
4
  return {
5
5
  filename: "workHistory.abstract.md",
6
- content: `# WorkHistory Scalar Abstract
7
-
8
- ## Akan.js Module Pattern
9
-
10
- WorkHistory is a **scalar module** — a reusable value type under lib/__scalar/.
11
- Scalar modules are embedded into models via field([ScalarType]), not stored independently.
12
- They live under the double-underscore prefix to distinguish them from database models.
13
-
14
- Standard scalar layers:
15
- - workHistory.constant.ts — enum (WorkHistoryAction) + entry class (WorkHistory) defined via via() + enumOf()
16
- - workHistory.dictionary.ts — i18n via scalarDictionary() (fewer layers than modelDictionary)
17
- - workHistory.abstract.md — embedding rules and intent
18
-
19
- ## Convention: lib/__scalar/<type>/ directory naming
20
-
21
- - Scalar modules use double-underscore prefix: lib/__scalar/workHistory/
22
- - Files drop the underscores: workHistory.constant.ts, not __workHistory.constant.ts
23
- - Models embed scalars via field([WorkHistory]) — list-of-scalar embedding
24
-
25
- ## Embedding Example (in task.constant.ts)
26
-
27
- TaskObject embeds a list of WorkHistory:
28
- import { WorkHistory } from "../../__scalar/workHistory/workHistory.constant";
29
- export class TaskObject extends via(TaskInput, (field) => ({
30
- workHistory: field([WorkHistory]),
31
- }))
32
-
33
- Each status change (create, start, complete) pushes a new entry.
34
-
35
- ## Agent Notes
36
-
37
- - Read this abstract before modifying the WorkHistory scalar.
38
- - Update when new action types or fields are added.
39
- - Do not duplicate workHistory fields in individual models; always reuse this scalar.
40
-
41
- ## Related Modules
42
-
43
- - lib/task/ — database module embedding workHistory as a list field
44
- - lib/_noti/ — pure service module (different module type, no scalar usage)
6
+ content: `# workHistory Abstract
7
+ One step in a task's history: which move happened, when, and an optional note.
8
+
9
+ ## Rules
10
+ - Entries are only appended — by \`Task\`'s chain methods and by the task service on create — and never edited or
11
+ removed, so the list reads as the task's moves in order.
12
+ - \`at\` is the moment the entry was built when the writer gives none.
13
+ - \`note\` is empty on every entry the app writes itself.
45
14
  `,
46
15
  };
47
16
  }
@@ -3,36 +3,13 @@ import type { AppInfo, LibInfo } from "akanjs";
3
3
  export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { appName: string }) {
4
4
  return {
5
5
  filename: "noti.abstract.md",
6
- content: `# Noti Abstract
6
+ content: `# noti Service Abstract
7
+ Noti holds the in-app notification list on the client: the messages the app shows, an unread count, and dismissal.
7
8
 
8
- ## Akan.js Module Pattern
9
-
10
- Noti is a **pure service module** — not a database module. It demonstrates the Akan.js convention
11
- for modules that orchestrate behavior without owning a persistent document model.
12
-
13
- Both module types follow the same layer pattern, but service modules have fewer layers:
14
- no constant.ts (no data shape), no document.ts (no DB queries), no UI components.
15
-
16
- - noti.service.ts — business logic via serve("noti" as const, ...) (named service, no DB binding)
17
- - noti.signal.ts — real-time pubsub endpoint bound via endpoint(srv.noti, ...)
18
- - noti.store.ts — client state via store("noti" as const, ...) (named store, no signal binding)
19
- - noti.dictionary.ts — i18n via serviceDictionary() (no model field labels)
20
-
21
- ## Convention: lib/_<service>/ directory naming
22
-
23
- - Service modules live under lib/_<service>/ — the underscore prefix signals "this is a service, not a database model."
24
- - Files drop the underscore: lib/_noti/noti.service.ts, not lib/_noti/_noti.service.ts.
25
- - Scan registers into the same barrel files: srv.ts, sig.ts, st.ts, dict.ts.
26
-
27
- ## Convention: named serve/store (no DB binding)
28
-
29
- - serve("noti" as const, ...) — service name passed as string, no db.<module> binding.
30
- - store("noti" as const, ...) — store name passed as string, no sig.<module> binding.
31
-
32
- ## Related Modules
33
-
34
- - lib/task/ — database module reference (compare structure differences)
35
- - lib/__scalar/workHistory/ — reusable scalar field modules (double-underscore prefix, embedded in models)
9
+ ## Rules
10
+ - Notifications live only in the client store; the server side declares nothing yet, so a reload starts empty.
11
+ - \`unreadCount\` counts additions since the last \`markAllRead()\`, not the list's length — removing a notification
12
+ does not lower it.
36
13
  `,
37
14
  };
38
15
  }
@@ -30,7 +30,7 @@ export const Card = ({ task, className, href }: CardProps) => {
30
30
  return (
31
31
  <Layout.Unit
32
32
  className={cn(
33
- "rounded-lg border border-foreground/10 bg-background p-4 transition-shadow hover:shadow-md",
33
+ "jelly-glass block rounded-box p-5 transition-transform duration-300 ease-jelly hover:-translate-y-0.5",
34
34
  className,
35
35
  )}
36
36
  href={href}
@@ -5,7 +5,8 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
5
5
  filename: "Task.Util.tsx",
6
6
  content: `"use client";
7
7
  import { fetch, st, usePage } from "@apps/${dict.appName}/client";
8
- import { buttonRecipe, Dropdown, Model } from "akanjs/ui";
8
+ import { jellyButtonRecipe } from "@apps/${dict.appName}/ui";
9
+ import { Dropdown, Model } from "akanjs/ui";
9
10
 
10
11
  // ===== Task.Util.tsx =====
11
12
  // Convention: lib/<module>/ — PascalCase .tsx, Util suffix = action buttons/utility components.
@@ -19,10 +20,7 @@ interface StartProps {
19
20
  }
20
21
 
21
22
  export const Start = ({ taskId }: StartProps) => (
22
- <button
23
- className={buttonRecipe({ size: "xs" }, "border-primary/20 bg-primary/10 text-primary hover:bg-primary hover:text-primary-foreground")}
24
- onClick={() => st.do.startTask(taskId)}
25
- >
23
+ <button className={jellyButtonRecipe({ variant: "primary", size: "xs" })} onClick={() => st.do.startTask(taskId)}>
26
24
  {usePage().l("task.taskStart")}
27
25
  </button>
28
26
  );
@@ -32,10 +30,7 @@ interface CompleteProps {
32
30
  }
33
31
 
34
32
  export const Complete = ({ taskId }: CompleteProps) => (
35
- <button
36
- className={buttonRecipe({ size: "xs" }, "border-success/20 bg-success/10 text-success hover:bg-success hover:text-success-foreground")}
37
- onClick={() => st.do.completeTask(taskId)}
38
- >
33
+ <button className={jellyButtonRecipe({ variant: "success", size: "xs" })} onClick={() => st.do.completeTask(taskId)}>
39
34
  {usePage().l("task.taskComplete")}
40
35
  </button>
41
36
  );
@@ -46,7 +41,9 @@ interface RemoveProps {
46
41
 
47
42
  export const Remove = ({ taskId }: RemoveProps) => (
48
43
  <Model.Remove modelId={taskId} slice={fetch.slice.task}>
49
- <button className={buttonRecipe({ variant: "ghost", size: "xs" }, "text-destructive")}>{usePage().l("task.taskRemove")}</button>
44
+ <button className={jellyButtonRecipe({ variant: "ghost", size: "xs" }, "text-destructive")}>
45
+ {usePage().l("task.taskRemove")}
46
+ </button>
50
47
  </Model.Remove>
51
48
  );
52
49
 
@@ -59,9 +56,9 @@ export const Toolbox = ({ taskId, status }: ToolboxProps) => {
59
56
  const { l } = usePage();
60
57
  return (
61
58
  <Dropdown
62
- buttonClassName={buttonRecipe({ variant: "ghost", size: "xs" })}
59
+ buttonClassName={jellyButtonRecipe({ variant: "ghost", size: "xs" })}
63
60
  value={<span>···</span>}
64
- dropdownClassName="w-40 rounded-box border border-foreground/10 bg-background p-2"
61
+ dropdownClassName="jelly-glass w-40 rounded-box p-2"
65
62
  content={
66
63
  <>
67
64
  {status === "todo" && (
@@ -96,7 +93,7 @@ export const Toolbox = ({ taskId, status }: ToolboxProps) => {
96
93
  // New Task Button: Model.NewWrapper — triggers new Task creation form
97
94
  // export const NewTask = () => (
98
95
  // <Model.NewWrapper partial={{}}>
99
- // <button className={buttonRecipe({ variant: "primary", size: "sm" })}>+ New Task</button>
96
+ // <button className={jellyButtonRecipe({ variant: "primary", size: "sm" })}>+ New Task</button>
100
97
  // </Model.NewWrapper>
101
98
  // );
102
99
  `,
@@ -29,12 +29,12 @@ export const General = ({ className, task }: GeneralProps) => {
29
29
  return (
30
30
  <div className={cn("flex w-full flex-col gap-4", className)}>
31
31
  <div>
32
- <h1 className="font-bold text-2xl text-foreground">{task.title}</h1>
32
+ <h1 className="font-black text-4xl text-foreground">{task.title}</h1>
33
33
  <div className={cn("mt-1 font-medium text-sm", statusColor)}>{l(\`taskStatus.\${task.status}\`)}</div>
34
34
  </div>
35
35
 
36
36
  {task.content && (
37
- <div className="rounded-lg border border-foreground/10 bg-background p-4">
37
+ <div className="jelly-glass rounded-box p-5">
38
38
  <p className="whitespace-pre-wrap text-foreground/80 text-sm">{task.content}</p>
39
39
  </div>
40
40
  )}
@@ -5,8 +5,9 @@ export default function getContent(scanInfo: AppInfo | LibInfo | null, dict: { a
5
5
  filename: "Task.Zone.tsx",
6
6
  content: `"use client";
7
7
  import { type cnst, Task, usePage } from "@apps/${dict.appName}/client";
8
+ import { jellyButtonRecipe } from "@apps/${dict.appName}/ui";
8
9
  import type { ClientInit, ClientView } from "akanjs/fetch";
9
- import { Link, Load, buttonRecipe } from "akanjs/ui";
10
+ import { Link, Load } from "akanjs/ui";
10
11
 
11
12
  // ===== Task.Zone.tsx =====
12
13
  // Convention: lib/<module>/ — PascalCase .tsx, Zone suffix = composition layer between pages and UI.
@@ -30,7 +31,9 @@ export const Card = ({ className, init }: CardProps) => {
30
31
  <div className="flex flex-col items-center gap-4 py-16 text-center">
31
32
  <div className="text-foreground/40 text-lg">{l("task.taskNoTasks")}</div>
32
33
  <Link href="/task/new">
33
- <button className={buttonRecipe({ variant: "primary", size: "sm" })}>{l("task.taskCreateFirst")}</button>
34
+ <button className={jellyButtonRecipe({ variant: "primary", size: "sm" })}>
35
+ {l("task.taskCreateFirst")}
36
+ </button>
34
37
  </Link>
35
38
  </div>
36
39
  )}