@akanjs/cli 3.0.0-alpha.8 → 3.0.0-alpha.81
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 +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/{abstractCompactor-e5yq60qz.js → abstractCompactor-pwc6d6yk.js} +3 -5
- package/{agent.command-pggr92jj.js → agent.command-180hh0ye.js} +11 -12
- package/{application.command-692yap1d.js → application.command-4fq5pmdd.js} +59 -35
- package/{applicationBuildRunner-ha3y8ew8.js → applicationBuildRunner-tavpx3fv.js} +22 -20
- package/{applicationReleasePackager-gg8ccbeh.js → applicationReleasePackager-ktjt0erc.js} +8 -9
- package/buildBatch.proc.js +12 -13
- package/capacitorApp-kwa67kzs.js +12 -0
- package/{cloud.command-wqfsyzv2.js → cloud.command-wm3mtfve.js} +15 -17
- package/commandManifest.json +1 -1
- package/{context.command-9bxtdn0w.js → context.command-dk2m2sjx.js} +19 -22
- package/dependencyScanner-c64m6fxp.js +8 -0
- package/getDirname-dr3jz1xg.js +7 -0
- package/{guideline.command-nfqahxex.js → guideline.command-w6ddv13r.js} +16 -17
- package/guidelines/agentRule/agentRule.generate.json +31 -0
- package/guidelines/agentRule/agentRule.instruction.md +525 -0
- package/guidelines/conventions/conventions.generate.json +25 -0
- package/guidelines/conventions/conventions.instruction.md +847 -0
- package/guidelines/cssRule/cssRule.instruction.md +7 -0
- package/guidelines/framework/framework.generate.json +3 -2
- package/guidelines/framework/framework.instruction.md +1 -9
- package/guidelines/mcpRule/mcpRule.generate.json +25 -0
- package/guidelines/mcpRule/mcpRule.instruction.md +217 -0
- package/guidelines/queryRule/queryRule.generate.json +31 -0
- package/guidelines/queryRule/queryRule.instruction.md +143 -0
- package/guidelines/runtimeRule/runtimeRule.generate.json +25 -0
- package/guidelines/runtimeRule/runtimeRule.instruction.md +176 -0
- package/guidelines/ssrRule/ssrRule.instruction.md +49 -5
- package/guidelines/transportRule/transportRule.generate.json +31 -0
- package/guidelines/transportRule/transportRule.instruction.md +60 -0
- package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +24 -0
- package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +263 -0
- package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +33 -0
- package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +402 -0
- package/incrementalBuilder.proc.js +21 -22
- package/{index-4hek879p.js → index-1kzsn94d.js} +1 -1
- package/{index-p3f4q532.js → index-1tgp56ke.js} +31 -30
- package/index-3d9y066c.js +76 -0
- package/{index-76rn3g2c.js → index-47pj3aee.js} +4 -4
- package/{index-gex7c8kd.js → index-5n0hf8r9.js} +65 -38
- package/{index-mssqn2sq.js → index-5y7qba1c.js} +79 -33
- package/index-6wwzs1bc.js +7 -0
- package/{index-wnp7hwq7.js → index-92zztqy1.js} +7 -7
- package/{index-fgc8r6dj.js → index-a5vmm6x4.js} +3 -1
- package/{index-azv0xjb5.js → index-a8h184wr.js} +15 -11
- package/{index-67546d0j.js → index-ayy5ecax.js} +1 -1
- package/{index-xhgtkekh.js → index-b2nt0w0k.js} +27 -27
- package/{index-xys926f2.js → index-by5gpp8x.js} +4 -4
- package/{index-bz2sfzzt.js → index-cd5x18qh.js} +32 -32
- package/{index-bjpxzr6s.js → index-ctphds8v.js} +1 -1
- package/{index-w6wbb612.js → index-dq6wq1tv.js} +94 -61
- package/{index-6rhabeev.js → index-ft1sfjz0.js} +36 -25
- package/{index-7myvn0f0.js → index-h7yw2z9n.js} +7 -7
- package/{index-5pmx7bkg.js → index-j9vnq8tr.js} +18 -18
- package/{index-vg0sj9nc.js → index-k1n0h7dk.js} +840 -201
- package/{index-vtj3zps1.js → index-k86zc21w.js} +57 -57
- package/{index-5dw57f0d.js → index-m7e0f1sy.js} +155 -76
- package/index-m9c7k0gm.js +159 -0
- package/{index-46tjzh6s.js → index-mfm35dhh.js} +29 -29
- package/{index-xjd3rqzj.js → index-n68jx79w.js} +6 -15
- package/{index-ztpw544k.js → index-qcracvc9.js} +8 -8
- package/{index-2c3e2xh8.js → index-saheq2bs.js} +4 -4
- package/{index-gmy45vz2.js → index-v0s24t8j.js} +14 -14
- package/{index-0cj2zxbm.js → index-wet2ytnr.js} +12 -11
- package/{index-j9cxndc0.js → index-x23688ar.js} +12 -7
- package/{index-a1e0j63x.js → index-xxe90kqy.js} +58 -25
- package/{index-js368gk9.js → index-ypvdw8nr.js} +13 -13
- package/{index-qb61h0k7.js → index-z3c9mmw4.js} +1098 -1360
- package/index.js +22 -24
- package/{library.command-md9715jz.js → library.command-wpedct6c.js} +11 -9
- package/{localRegistry.command-exkbamyj.js → localRegistry.command-gk773cte.js} +20 -22
- package/{module.command-w5aaddxk.js → module.command-8n4kct3e.js} +13 -15
- package/{package.command-yfkrcy0z.js → package.command-fcbd0b1d.js} +8 -9
- package/package.json +5 -7
- package/{page.command-echbavp4.js → page.command-x4379grq.js} +7 -8
- package/{primitive.command-9fbhspw2.js → primitive.command-8etmnqhq.js} +13 -15
- package/{quality.command-3pnt9yep.js → quality.command-hfx7z8yr.js} +226 -104
- package/recipeScanner-fpagtgc1.js +11 -0
- package/{repair.command-carj4vax.js → repair.command-j0fs5qkz.js} +12 -13
- package/{routeSourceValidator-e4jmbfcx.js → routeSourceValidator-ze6x894c.js} +0 -2
- package/{scalar.command-51ryzypc.js → scalar.command-2emk89eh.js} +11 -13
- package/subspace.command-3w3s1zas.js +714 -0
- package/templates/app/env/env.client.debug.ts.template +1 -5
- package/templates/app/env/env.client.develop.ts.template +1 -5
- package/templates/app/env/env.client.local.ts.template +1 -5
- package/templates/app/env/env.client.main.ts.template +1 -5
- package/templates/app/env/env.client.testing.ts.template +1 -5
- package/templates/app/env/env.client.type.ts +2 -6
- package/templates/app/env/env.server.debug.ts.template +1 -5
- package/templates/app/env/env.server.develop.ts.template +1 -5
- package/templates/app/env/env.server.local.ts.template +1 -5
- package/templates/app/env/env.server.main.ts.template +1 -5
- package/templates/app/main.ts +3 -1
- package/templates/appSample/lib/task/task.signal.ts +11 -6
- package/templates/appSample/srvkit/AuthGuard.ts +9 -5
- package/templates/appSample/srvkit/SessionInternalArg.ts +4 -3
- package/templates/crudPages/[__model__Id]/edit/page.tsx +6 -6
- package/templates/crudPages/[__model__Id]/page.tsx +10 -13
- package/templates/crudPages/new/page.tsx +6 -6
- package/templates/crudPages/page.tsx +9 -9
- package/templates/crudSinglePage/page.tsx +11 -7
- package/templates/env/_env.server.type.ts +7 -5
- package/templates/lib/db.ts +1 -1
- package/templates/lib/dict.ts +1 -1
- package/templates/lib/sig.ts +1 -1
- package/templates/lib/srv.ts +6 -2
- package/templates/module/__Model__.Util.tsx +1 -1
- package/templates/module/__Model__.Zone.tsx +3 -5
- package/templates/module/__model__.dictionary.ts +4 -1
- package/templates/module/__model__.signal.ts +2 -3
- package/templates/module/__model__.store.ts +1 -2
- package/templates/workspaceRoot/.gitignore.template +0 -1
- package/templates/workspaceRoot/AGENTS.md.template +4 -972
- package/templates/workspaceRoot/CLAUDE.md.template +19 -0
- package/templates/workspaceRoot/biome.json.template +4 -244
- package/templates/workspaceRoot/docs/AI-DEVELOPMENT.md.template +10 -14
- package/templates/workspaceRoot/docs/GENERATED.md.template +12 -10
- package/templates/workspaceRoot/package.json.template +2 -4
- package/typeChecker-3xgrzc2v.js +7 -0
- package/typecheck.proc.js +4 -5
- package/{workflow.command-91wmvm8k.js → workflow.command-cvpmzwjg.js} +21 -23
- package/{workspace.command-wa10mfd9.js → workspace.command-4ztb4fdh.js} +108 -91
- package/capacitorApp-p0z5yab2.js +0 -60
- package/dependencyScanner-f6grrep3.js +0 -9
- package/index-mxvakhsm.js +0 -66
- package/index-r24hmh0q.js +0 -4
- package/recipeScanner-tghkzrrt.js +0 -12
- package/templates/workspaceRoot/.cursor/rules/akan-page-routing.mdc.template +0 -43
- package/templates/workspaceRoot/.cursor/rules/akan-sync-conventions.mdc.template +0 -34
- package/templates/workspaceRoot/.cursor/rules/application-test-commands.mdc.template +0 -16
- package/templates/workspaceRoot/.cursor/rules/change-scope.mdc.template +0 -12
- package/templates/workspaceRoot/.cursor/rules/client-server-boundaries.mdc.template +0 -18
- package/templates/workspaceRoot/.cursor/rules/coding-comments.mdc.template +0 -25
- package/templates/workspaceRoot/.cursor/rules/coding-style.mdc.template +0 -44
- package/templates/workspaceRoot/.cursor/rules/domain-module-conventions.mdc.template +0 -17
- package/templates/workspaceRoot/.cursor/rules/format-lint.mdc.template +0 -12
- package/templates/workspaceRoot/.cursor/rules/lint-enforced-rules.mdc.template +0 -19
- package/templates/workspaceRoot/.cursor/rules/module-file-playbook.mdc.template +0 -62
- package/templates/workspaceRoot/.cursor/rules/naming-conventions.mdc.template +0 -15
- package/templates/workspaceRoot/.cursor/rules/react-component-style.mdc.template +0 -21
- package/templates/workspaceRoot/.cursor/rules/repo-overview.mdc.template +0 -17
- package/templates/workspaceRoot/.cursor/rules/scalar-modeling.mdc.template +0 -99
- package/templates/workspaceRoot/.cursor/rules/secrets-and-env.mdc.template +0 -13
- package/templates/workspaceRoot/.cursor/rules/service-signal-conventions.mdc.template +0 -83
- package/templates/workspaceRoot/.cursor/rules/srvkit-adapters-and-guards.mdc.template +0 -50
- package/templates/workspaceRoot/.cursor/rules/ssr-first.mdc.template +0 -59
- package/templates/workspaceRoot/.cursor/rules/typescript-imports.mdc.template +0 -16
- package/typeChecker-kravn7ns.js +0 -8
- /package/{index-0wae5ebk.js → index-meh558jy.js} +0 -0
- /package/{index-ss469dec.js → index-nz8prx9g.js} +0 -0
|
@@ -1,87 +1,84 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
} from "./index-
|
|
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";
|
|
3
|
+
FileSys
|
|
4
|
+
} from "./index-ayy5ecax.js";
|
|
10
5
|
import {
|
|
11
|
-
|
|
12
|
-
} from "./index-
|
|
6
|
+
GlobalConfig
|
|
7
|
+
} from "./index-wet2ytnr.js";
|
|
13
8
|
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
Exec,
|
|
10
|
+
Workspace,
|
|
11
|
+
runner,
|
|
12
|
+
script,
|
|
13
|
+
command
|
|
14
|
+
} from "./index-ft1sfjz0.js";
|
|
17
15
|
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
extractAgentBlock,
|
|
17
|
+
collectScopeRecipeSources,
|
|
18
|
+
renderScopeAgentBlock,
|
|
19
|
+
WorkspaceExecutor,
|
|
20
|
+
SysExecutor,
|
|
21
|
+
AppExecutor,
|
|
22
|
+
LibExecutor,
|
|
23
|
+
PkgExecutor
|
|
24
|
+
} from "./index-k1n0h7dk.js";
|
|
25
|
+
import"./index-6wwzs1bc.js";
|
|
23
26
|
import {
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
countBlocking,
|
|
28
|
+
formatStyleContract,
|
|
29
|
+
ThemeValidator
|
|
30
|
+
} from "./index-n68jx79w.js";
|
|
31
|
+
import {
|
|
32
|
+
collectRecipeSources2,
|
|
33
|
+
scanRecipes2
|
|
34
|
+
} from "./index-by5gpp8x.js";
|
|
35
|
+
import"./index-saheq2bs.js";
|
|
36
|
+
import"./index-5y7qba1c.js";
|
|
37
|
+
import"./index-h7yw2z9n.js";
|
|
26
38
|
import {
|
|
27
39
|
AgentScript
|
|
28
|
-
} from "./index-
|
|
29
|
-
import"./index-mssqn2sq.js";
|
|
30
|
-
import"./index-2c3e2xh8.js";
|
|
31
|
-
import"./index-7myvn0f0.js";
|
|
40
|
+
} from "./index-5n0hf8r9.js";
|
|
32
41
|
import {
|
|
33
42
|
ApplicationScript
|
|
34
|
-
} from "./index-
|
|
35
|
-
import"./index-76rn3g2c.js";
|
|
43
|
+
} from "./index-m7e0f1sy.js";
|
|
36
44
|
import {
|
|
37
45
|
LibraryScript
|
|
38
|
-
} from "./index-
|
|
46
|
+
} from "./index-xxe90kqy.js";
|
|
47
|
+
import"./index-ctphds8v.js";
|
|
48
|
+
import"./index-mfm35dhh.js";
|
|
39
49
|
import {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
command,
|
|
43
|
-
runner,
|
|
44
|
-
script
|
|
45
|
-
} from "./index-6rhabeev.js";
|
|
46
|
-
import"./index-fgc8r6dj.js";
|
|
50
|
+
PackageScript
|
|
51
|
+
} from "./index-a8h184wr.js";
|
|
47
52
|
import {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
} from "./index-xjd3rqzj.js";
|
|
52
|
-
import"./index-bjpxzr6s.js";
|
|
53
|
+
getNpmRegistryUrl,
|
|
54
|
+
getLatestPackageVersion
|
|
55
|
+
} from "./index-1tgp56ke.js";
|
|
53
56
|
import {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
PkgExecutor,
|
|
57
|
-
SysExecutor,
|
|
58
|
-
WorkspaceExecutor,
|
|
59
|
-
collectScopeRecipeSources,
|
|
60
|
-
extractAgentBlock,
|
|
61
|
-
renderScopeAgentBlock
|
|
62
|
-
} from "./index-vg0sj9nc.js";
|
|
63
|
-
import"./index-mxvakhsm.js";
|
|
64
|
-
import {
|
|
65
|
-
collectRecipeSources,
|
|
66
|
-
scanRecipes
|
|
67
|
-
} from "./index-xys926f2.js";
|
|
68
|
-
import"./index-46tjzh6s.js";
|
|
57
|
+
CloudScript
|
|
58
|
+
} from "./index-ypvdw8nr.js";
|
|
69
59
|
import {
|
|
70
|
-
|
|
71
|
-
} from "./index-
|
|
72
|
-
import"./index-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
import
|
|
76
|
-
import
|
|
60
|
+
ContextScript
|
|
61
|
+
} from "./index-dq6wq1tv.js";
|
|
62
|
+
import"./index-b2nt0w0k.js";
|
|
63
|
+
import"./index-qcracvc9.js";
|
|
64
|
+
import"./index-j9vnq8tr.js";
|
|
65
|
+
import"./index-k86zc21w.js";
|
|
66
|
+
import"./index-1kzsn94d.js";
|
|
67
|
+
import"./index-cd5x18qh.js";
|
|
68
|
+
import"./index-v0s24t8j.js";
|
|
69
|
+
import"./index-m9c7k0gm.js";
|
|
77
70
|
|
|
78
71
|
// pkgs/@akanjs/cli/workspace/workspace.runner.ts
|
|
79
72
|
import path from "path";
|
|
73
|
+
|
|
74
|
+
// pkgs/@akanjs/devkit/biomeBase.ts
|
|
75
|
+
var biomeVersion = "2.5.8";
|
|
76
|
+
|
|
77
|
+
// pkgs/@akanjs/cli/workspace/workspace.runner.ts
|
|
80
78
|
var defaultWorkspacePeerDependencies = new Set([
|
|
81
79
|
"@react-spring/web",
|
|
82
80
|
"@use-gesture/react",
|
|
83
81
|
"chance",
|
|
84
|
-
"croner",
|
|
85
82
|
"react",
|
|
86
83
|
"react-dom",
|
|
87
84
|
"react-icons",
|
|
@@ -93,6 +90,7 @@ var defaultWorkspacePeerDependencies = new Set([
|
|
|
93
90
|
"tailwindcss",
|
|
94
91
|
"typescript"
|
|
95
92
|
]);
|
|
93
|
+
var defaultMaxDiagnostics = 200;
|
|
96
94
|
|
|
97
95
|
class WorkspaceRunner extends runner("workspace") {
|
|
98
96
|
async generateAgentRules(workspace, { overwrite = false, cursorRules = true } = {}) {
|
|
@@ -113,17 +111,14 @@ class WorkspaceRunner extends runner("workspace") {
|
|
|
113
111
|
dict,
|
|
114
112
|
overwrite
|
|
115
113
|
}));
|
|
116
|
-
if (
|
|
117
|
-
|
|
118
|
-
return [
|
|
119
|
-
...created,
|
|
120
|
-
...await workspace.applyTemplate({
|
|
114
|
+
if (cursorRules)
|
|
115
|
+
created.push(...await workspace.applyTemplate({
|
|
121
116
|
basePath: ".cursor/rules",
|
|
122
117
|
template: "workspaceRoot/.cursor/rules/akan.mdc.template",
|
|
123
118
|
dict,
|
|
124
119
|
overwrite
|
|
125
|
-
})
|
|
126
|
-
|
|
120
|
+
}));
|
|
121
|
+
return created;
|
|
127
122
|
}
|
|
128
123
|
async createWorkspace(repoName, appName, {
|
|
129
124
|
dirname = ".",
|
|
@@ -137,10 +132,7 @@ class WorkspaceRunner extends runner("workspace") {
|
|
|
137
132
|
const normalizedRegistryUrl = registryUrl ? getNpmRegistryUrl(registryUrl) : undefined;
|
|
138
133
|
const workspace = WorkspaceExecutor.fromRoot({ workspaceRoot, repoName });
|
|
139
134
|
const templateSpinner = workspace.spinning(`Creating workspace template files in ${dirname}/${repoName}...`);
|
|
140
|
-
const
|
|
141
|
-
getLatestPackageVersion("@biomejs/biome", "latest", normalizedRegistryUrl),
|
|
142
|
-
getLatestPackageVersion("@types/bun", "latest", normalizedRegistryUrl)
|
|
143
|
-
]);
|
|
135
|
+
const latestTypesBunVersion = await getLatestPackageVersion("@types/bun", "latest", normalizedRegistryUrl);
|
|
144
136
|
await workspace.applyTemplate({
|
|
145
137
|
basePath: ".",
|
|
146
138
|
template: "workspaceRoot",
|
|
@@ -164,7 +156,7 @@ class WorkspaceRunner extends runner("workspace") {
|
|
|
164
156
|
},
|
|
165
157
|
devDependencies: {
|
|
166
158
|
...rootPackageJson.devDependencies,
|
|
167
|
-
"@biomejs/biome":
|
|
159
|
+
"@biomejs/biome": biomeVersion,
|
|
168
160
|
"@types/bun": latestTypesBunVersion,
|
|
169
161
|
"@akanjs/devkit": akanVersion,
|
|
170
162
|
...typescript ? { typescript } : {}
|
|
@@ -236,24 +228,35 @@ class WorkspaceRunner extends runner("workspace") {
|
|
|
236
228
|
}
|
|
237
229
|
throw new Error(`[workspace] failed to locate akanjs package.json from ${import.meta.dir}`);
|
|
238
230
|
}
|
|
239
|
-
async lint(exec, workspace, { fix = true } = {}) {
|
|
231
|
+
async lint(exec, workspace, { fix = true, maxDiagnostics = defaultMaxDiagnostics } = {}) {
|
|
232
|
+
const configPath = await WorkspaceRunner.resolveBiomeConfigPath(workspace);
|
|
240
233
|
await workspace.spawn("./node_modules/.bin/biome", [
|
|
241
234
|
"check",
|
|
242
235
|
...fix ? ["--write"] : [],
|
|
243
236
|
"--no-errors-on-unmatched",
|
|
237
|
+
`--max-diagnostics=${maxDiagnostics > 0 ? maxDiagnostics : "none"}`,
|
|
238
|
+
...configPath ? ["--config-path", configPath] : [],
|
|
244
239
|
exec.cwdPath
|
|
245
240
|
]);
|
|
246
241
|
await this.#enforceStyleContract(exec);
|
|
247
242
|
await this.#enforceRecipeGate(exec);
|
|
248
243
|
await this.#enforceAgentsIndex(exec);
|
|
249
244
|
}
|
|
245
|
+
static async resolveBiomeConfigPath(workspace) {
|
|
246
|
+
for (const fileName of ["biome.json", "biome.jsonc"]) {
|
|
247
|
+
const configPath = path.join(workspace.workspaceRoot, fileName);
|
|
248
|
+
if (await Bun.file(configPath).exists())
|
|
249
|
+
return configPath;
|
|
250
|
+
}
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
250
253
|
async#enforceAgentsIndex(exec) {
|
|
251
254
|
if (!(exec instanceof SysExecutor))
|
|
252
255
|
return;
|
|
253
256
|
const scope = { type: exec.type, name: exec.name };
|
|
254
257
|
const scanInfo = await exec.scan({ write: false });
|
|
255
258
|
const sources = await collectScopeRecipeSources(exec.workspace.workspaceRoot, scope, scanInfo.getScanResult().libDeps);
|
|
256
|
-
const expected = renderScopeAgentBlock(scope,
|
|
259
|
+
const expected = renderScopeAgentBlock(scope, scanRecipes2(sources));
|
|
257
260
|
const existing = await exec.exists("AGENTS.md") ? await exec.readFile("AGENTS.md") : null;
|
|
258
261
|
const actual = existing ? extractAgentBlock(existing) : null;
|
|
259
262
|
if (actual === expected.trim())
|
|
@@ -266,12 +269,12 @@ class WorkspaceRunner extends runner("workspace") {
|
|
|
266
269
|
return;
|
|
267
270
|
const uiDir = path.join(cwdPath, "ui");
|
|
268
271
|
const sources = [
|
|
269
|
-
...await
|
|
270
|
-
...await
|
|
272
|
+
...await collectRecipeSources2(uiDir, "ui/Recipe"),
|
|
273
|
+
...await collectRecipeSources2(uiDir, "ui/recipe", "recipe")
|
|
271
274
|
];
|
|
272
275
|
if (sources.length === 0)
|
|
273
276
|
return;
|
|
274
|
-
const offenders =
|
|
277
|
+
const offenders = scanRecipes2(sources).filter((recipe) => !Object.values(recipe.variants).some((values) => values.length >= 2 || values.length === 1 && values[0] === "true"));
|
|
275
278
|
if (offenders.length === 0)
|
|
276
279
|
return;
|
|
277
280
|
throw new Error(`[recipeGate] variant-less recipe(s): ${offenders.map((recipe) => recipe.name).join(", ")}
|
|
@@ -282,15 +285,18 @@ class WorkspaceRunner extends runner("workspace") {
|
|
|
282
285
|
if (!cwdPath)
|
|
283
286
|
return;
|
|
284
287
|
const stylesCssPath = path.join(cwdPath, "page", "styles.css");
|
|
285
|
-
|
|
286
|
-
|
|
288
|
+
if (!await Bun.file(stylesCssPath).exists())
|
|
289
|
+
return;
|
|
290
|
+
const violations = {
|
|
291
|
+
theme: new ThemeValidator().validate(await Bun.file(stylesCssPath).text())
|
|
292
|
+
};
|
|
287
293
|
const blocking = countBlocking(violations);
|
|
288
294
|
if (blocking === 0)
|
|
289
295
|
return;
|
|
290
296
|
throw new Error(`[themeValidator] ${blocking} blocking contrast violation(s):
|
|
291
297
|
${formatStyleContract(violations)}
|
|
292
298
|
|
|
293
|
-
` + "
|
|
299
|
+
` + "Raise the foreground/background contrast of these theme token values to the WCAG threshold.");
|
|
294
300
|
}
|
|
295
301
|
async writeTopLevelEnv(workspace, devProjectId) {
|
|
296
302
|
await workspace.writeFile(".env", `AKAN_WORKSPACE_ID=${devProjectId}
|
|
@@ -314,6 +320,8 @@ AKAN_PUBLIC_LOG_LEVEL=debug
|
|
|
314
320
|
}
|
|
315
321
|
|
|
316
322
|
// pkgs/@akanjs/cli/workspace/workspace.script.ts
|
|
323
|
+
import path2 from "path";
|
|
324
|
+
import { Logger } from "akanjs/common";
|
|
317
325
|
class WorkspaceScript extends script("workspace", [
|
|
318
326
|
WorkspaceRunner,
|
|
319
327
|
ApplicationScript,
|
|
@@ -372,30 +380,33 @@ class WorkspaceScript extends script("workspace", [
|
|
|
372
380
|
async generateAgentRules(workspace, { overwrite = false, cursorRules = true } = {}) {
|
|
373
381
|
const spinner = workspace.spinning("Generating agent rules...");
|
|
374
382
|
const files = await this.workspaceRunner.generateAgentRules(workspace, { overwrite, cursorRules });
|
|
383
|
+
if (files.some((file) => file.filePath.endsWith("AGENTS.md")))
|
|
384
|
+
await this.agentScript.agent(workspace, "install", "agents-md", { force: overwrite });
|
|
375
385
|
spinner.succeed(`Agent rules ready (${files.length} file${files.length === 1 ? "" : "s"})`);
|
|
376
386
|
}
|
|
377
|
-
async lint(exec, workspace, { fix = true } = {}) {
|
|
387
|
+
async lint(exec, workspace, { fix = true, maxDiagnostics } = {}) {
|
|
378
388
|
if (exec instanceof AppExecutor)
|
|
379
389
|
await this.applicationScript.sync(exec);
|
|
380
390
|
else if (exec instanceof LibExecutor)
|
|
381
391
|
await this.libraryScript.syncLibrary(exec);
|
|
382
392
|
const spinner = workspace.spinning(`Linting${fix ? " with fix" : ""}...`);
|
|
383
393
|
try {
|
|
384
|
-
await this.workspaceRunner.lint(exec, workspace, { fix });
|
|
394
|
+
await this.workspaceRunner.lint(exec, workspace, { fix, maxDiagnostics });
|
|
385
395
|
spinner.succeed("Lint completed with no errors");
|
|
386
396
|
} catch (error) {
|
|
387
397
|
spinner.fail("Lint failed with errors");
|
|
388
398
|
throw error;
|
|
389
399
|
}
|
|
390
400
|
}
|
|
391
|
-
async lintAll(workspace, { fix = true } = {}) {
|
|
401
|
+
async lintAll(workspace, { fix = true, maxDiagnostics } = {}) {
|
|
392
402
|
const [appNames, libNames, pkgNames] = await workspace.getExecs();
|
|
403
|
+
const options = { fix, maxDiagnostics };
|
|
393
404
|
await Promise.all(appNames.map((appName) => this.applicationScript.sync(AppExecutor.from(workspace, appName))));
|
|
394
405
|
await Promise.all(libNames.map((libName) => this.libraryScript.syncLibrary(LibExecutor.from(workspace, libName))));
|
|
395
406
|
await Promise.all([
|
|
396
|
-
...appNames.map((appName) => this.workspaceRunner.lint(AppExecutor.from(workspace, appName), workspace,
|
|
397
|
-
...libNames.map((libName) => this.workspaceRunner.lint(LibExecutor.from(workspace, libName), workspace,
|
|
398
|
-
...pkgNames.filter((pkgName) => pkgName !== "contract").map((pkgName) => this.workspaceRunner.lint(PkgExecutor.from(workspace, pkgName), workspace,
|
|
407
|
+
...appNames.map((appName) => this.workspaceRunner.lint(AppExecutor.from(workspace, appName), workspace, options)),
|
|
408
|
+
...libNames.map((libName) => this.workspaceRunner.lint(LibExecutor.from(workspace, libName), workspace, options)),
|
|
409
|
+
...pkgNames.filter((pkgName) => pkgName !== "contract").map((pkgName) => this.workspaceRunner.lint(PkgExecutor.from(workspace, pkgName), workspace, options))
|
|
399
410
|
]);
|
|
400
411
|
}
|
|
401
412
|
async syncAll(workspace) {
|
|
@@ -477,11 +488,17 @@ class WorkspaceCommand extends command("workspace", [WorkspaceScript], ({ public
|
|
|
477
488
|
}).option("overwrite", Boolean, { desc: "Overwrite existing agent rule files", default: false }).option("cursorRules", Boolean, { desc: "Generate .cursor/rules/akan.mdc", default: true }).with(Workspace).exec(async function(overwrite, cursorRules, workspace) {
|
|
478
489
|
await this.workspaceScript.generateAgentRules(workspace, { overwrite, cursorRules });
|
|
479
490
|
}),
|
|
480
|
-
lint: target({ desc: "Lint and fix code in a specific app/lib/pkg" }).with(Exec).option("fix", Boolean, { default: true }).
|
|
481
|
-
|
|
491
|
+
lint: target({ desc: "Lint and fix code in a specific app/lib/pkg" }).with(Exec).option("fix", Boolean, { default: true }).option("maxDiagnostics", Number, {
|
|
492
|
+
desc: "How many diagnostics Biome prints before truncating (0 for no limit)",
|
|
493
|
+
default: defaultMaxDiagnostics
|
|
494
|
+
}).with(Workspace).exec(async function(exec, fix, maxDiagnostics, workspace) {
|
|
495
|
+
await this.workspaceScript.lint(exec, workspace, { fix, maxDiagnostics });
|
|
482
496
|
}),
|
|
483
|
-
lintAll: target({ desc: "Lint and fix code in all apps and libraries" }).option("fix", Boolean, { default: true }).
|
|
484
|
-
|
|
497
|
+
lintAll: target({ desc: "Lint and fix code in all apps and libraries" }).option("fix", Boolean, { default: true }).option("maxDiagnostics", Number, {
|
|
498
|
+
desc: "How many diagnostics Biome prints before truncating (0 for no limit)",
|
|
499
|
+
default: defaultMaxDiagnostics
|
|
500
|
+
}).with(Workspace).exec(async function(fix, maxDiagnostics, workspace) {
|
|
501
|
+
await this.workspaceScript.lintAll(workspace, { fix, maxDiagnostics });
|
|
485
502
|
}),
|
|
486
503
|
syncAll: target({ desc: "Sync dependencies and configuration for all apps and libraries" }).with(Workspace).exec(async function(workspace) {
|
|
487
504
|
await this.workspaceScript.syncAll(workspace);
|
package/capacitorApp-p0z5yab2.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import {
|
|
3
|
-
ANDROID_MIN_SDK_VERSION,
|
|
4
|
-
CapacitorApp,
|
|
5
|
-
PLACEHOLDER_APP_IDS,
|
|
6
|
-
SWIFTUICORE_MIN_IOS_MAJOR,
|
|
7
|
-
assertJsonSerializable,
|
|
8
|
-
buildIosNativeRunCommand,
|
|
9
|
-
classifyIosRunFailure,
|
|
10
|
-
clearRootCapacitorConfigs,
|
|
11
|
-
formatAndroidReleaseSigningError,
|
|
12
|
-
formatIosRunFailureMessage,
|
|
13
|
-
getAdbDeviceStateIssues,
|
|
14
|
-
getAndroidLocalServerHost,
|
|
15
|
-
getMissingAndroidReleaseSigningKeys,
|
|
16
|
-
isPlaceholderAppId,
|
|
17
|
-
materializeCapacitorConfig,
|
|
18
|
-
parseDevicectlDevices,
|
|
19
|
-
parseIosRuntimeMajor,
|
|
20
|
-
parseSimctlDevices,
|
|
21
|
-
raiseGradleMinSdkVersion,
|
|
22
|
-
rootCapacitorConfigFilenames,
|
|
23
|
-
rootCapacitorConfigPaths,
|
|
24
|
-
sanitizeIosNativeRunEnv,
|
|
25
|
-
selectLocalDevHost,
|
|
26
|
-
sortIosRunTargets,
|
|
27
|
-
writeRootCapacitorConfig
|
|
28
|
-
} from "./index-xhgtkekh.js";
|
|
29
|
-
import"./index-76rn3g2c.js";
|
|
30
|
-
import"./index-vg0sj9nc.js";
|
|
31
|
-
import"./index-mxvakhsm.js";
|
|
32
|
-
import"./index-67546d0j.js";
|
|
33
|
-
import"./index-r24hmh0q.js";
|
|
34
|
-
export {
|
|
35
|
-
writeRootCapacitorConfig,
|
|
36
|
-
sortIosRunTargets,
|
|
37
|
-
selectLocalDevHost,
|
|
38
|
-
sanitizeIosNativeRunEnv,
|
|
39
|
-
rootCapacitorConfigPaths,
|
|
40
|
-
rootCapacitorConfigFilenames,
|
|
41
|
-
raiseGradleMinSdkVersion,
|
|
42
|
-
parseSimctlDevices,
|
|
43
|
-
parseIosRuntimeMajor,
|
|
44
|
-
parseDevicectlDevices,
|
|
45
|
-
materializeCapacitorConfig,
|
|
46
|
-
isPlaceholderAppId,
|
|
47
|
-
getMissingAndroidReleaseSigningKeys,
|
|
48
|
-
getAndroidLocalServerHost,
|
|
49
|
-
getAdbDeviceStateIssues,
|
|
50
|
-
formatIosRunFailureMessage,
|
|
51
|
-
formatAndroidReleaseSigningError,
|
|
52
|
-
clearRootCapacitorConfigs,
|
|
53
|
-
classifyIosRunFailure,
|
|
54
|
-
buildIosNativeRunCommand,
|
|
55
|
-
assertJsonSerializable,
|
|
56
|
-
SWIFTUICORE_MIN_IOS_MAJOR,
|
|
57
|
-
PLACEHOLDER_APP_IDS,
|
|
58
|
-
CapacitorApp,
|
|
59
|
-
ANDROID_MIN_SDK_VERSION
|
|
60
|
-
};
|
package/index-mxvakhsm.js
DELETED
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
// pkgs/@akanjs/devkit/spinner.ts
|
|
3
|
-
import ora from "ora";
|
|
4
|
-
|
|
5
|
-
class Spinner {
|
|
6
|
-
static padding = 12;
|
|
7
|
-
static oraOptions = { discardStdin: false };
|
|
8
|
-
static canAnimate(stream = process.stderr) {
|
|
9
|
-
return !stream.isTTY || stream.columns > 0;
|
|
10
|
-
}
|
|
11
|
-
spinner;
|
|
12
|
-
stopWatch = null;
|
|
13
|
-
startAt = new Date;
|
|
14
|
-
prefix;
|
|
15
|
-
message;
|
|
16
|
-
enableSpin;
|
|
17
|
-
constructor(message, { prefix = "", indent = 0, enableSpin = true } = {}) {
|
|
18
|
-
Spinner.padding = Math.max(Spinner.padding, prefix.length);
|
|
19
|
-
this.prefix = prefix;
|
|
20
|
-
this.message = message;
|
|
21
|
-
this.spinner = ora({ ...Spinner.oraOptions, text: message });
|
|
22
|
-
this.spinner.prefixText = prefix.padStart(Spinner.padding, " ");
|
|
23
|
-
this.spinner.indent = indent;
|
|
24
|
-
this.enableSpin = enableSpin && Spinner.canAnimate();
|
|
25
|
-
}
|
|
26
|
-
start() {
|
|
27
|
-
this.startAt = new Date;
|
|
28
|
-
if (this.enableSpin) {
|
|
29
|
-
this.spinner.start();
|
|
30
|
-
this.stopWatch = setInterval(() => {
|
|
31
|
-
this.spinner.prefixText = this.prefix.padStart(Spinner.padding, " ");
|
|
32
|
-
this.spinner.text = `${this.message} (${this.#getElapsedTimeStr({ floor: true })})`;
|
|
33
|
-
}, 1000);
|
|
34
|
-
} else
|
|
35
|
-
this.spinner.info();
|
|
36
|
-
return this;
|
|
37
|
-
}
|
|
38
|
-
succeed(message) {
|
|
39
|
-
this.spinner.succeed(`${message} (${this.#getElapsedTimeStr()})`);
|
|
40
|
-
this.#reset();
|
|
41
|
-
}
|
|
42
|
-
fail(message) {
|
|
43
|
-
this.spinner.fail(`${message} (${this.#getElapsedTimeStr()})`);
|
|
44
|
-
this.#reset();
|
|
45
|
-
}
|
|
46
|
-
isSpinning() {
|
|
47
|
-
return this.spinner.isSpinning;
|
|
48
|
-
}
|
|
49
|
-
#reset() {
|
|
50
|
-
if (this.stopWatch)
|
|
51
|
-
clearInterval(this.stopWatch);
|
|
52
|
-
this.stopWatch = null;
|
|
53
|
-
}
|
|
54
|
-
#getElapsedTimeStr({ floor = false } = {}) {
|
|
55
|
-
const ms = Date.now() - this.startAt.getTime();
|
|
56
|
-
if (ms < 1000)
|
|
57
|
-
return `${ms}ms`;
|
|
58
|
-
const s = Math.floor(ms / 1000);
|
|
59
|
-
if (s < 60)
|
|
60
|
-
return `${floor ? Math.floor(ms / 1000) : Math.floor(ms / 100) / 10}s`;
|
|
61
|
-
const m = Math.floor(s / 60);
|
|
62
|
-
return `${m}m ${s % 60}s`;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export { Spinner };
|
package/index-r24hmh0q.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Akan page routing conventions
|
|
3
|
-
globs: apps/**/page/**/*.{ts,tsx,js,jsx}
|
|
4
|
-
alwaysApply: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Akan Page Routing
|
|
8
|
-
|
|
9
|
-
- `apps/<app>/page` may contain route modules only. Do not add helper logic or component-only files there.
|
|
10
|
-
- Route source files under `page/` must use `.tsx`. Do not add `logic.ts`, `.js`, or `.jsx` files under `page/`.
|
|
11
|
-
- Route pages use `_index.tsx`; layouts use `_layout.tsx`.
|
|
12
|
-
- Reserved `_*.tsx` route filenames are limited to `_index.tsx` and `_layout.tsx`; do not add files like `_Component.tsx` or `_helper.tsx`.
|
|
13
|
-
- Page filenames must not start with an uppercase letter. Move helper components like `Component.tsx` to app `ui`, `common`, or `lib` instead.
|
|
14
|
-
- Dynamic segments use `[id]`; route groups use directories like `(user)`, `(public)`, `(tab)`, or `(detail)`.
|
|
15
|
-
- Page modules should usually export `default`, `pageConfig`, `head`, `generateHead`, or `Loading`.
|
|
16
|
-
- Prefer `export default function Page` or `export default async function Page` for page components.
|
|
17
|
-
- Before changing route behavior, check nearby routes for the expected pattern.
|
|
18
|
-
|
|
19
|
-
## Page Body Shape
|
|
20
|
-
|
|
21
|
-
```tsx
|
|
22
|
-
interface PageProps {
|
|
23
|
-
params: { taskId: string };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export default async function Page({ params }: PageProps) {
|
|
27
|
-
const { l } = usePage();
|
|
28
|
-
getSelf({ unauthorize: "/signin" });
|
|
29
|
-
const { taskId } = params;
|
|
30
|
-
const [{ task }] = await Promise.all([fetch.viewTask(taskId)]);
|
|
31
|
-
return <Task.View.General task={task} />;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export const pageConfig = { transition: "stack" } satisfies PageConfig;
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
- There is no `loader=` / `render=` page prop. Pages are `export default async function Page`.
|
|
38
|
-
- Declare `interface PageProps { params: {...}; searchParams?: {...} }` immediately above the default export.
|
|
39
|
-
- Body order: `usePage()`, auth, destructure params, fetch, return.
|
|
40
|
-
- Run independent fetches through `Promise.all`, even when there is only one.
|
|
41
|
-
- Gate auth at `_layout.tsx`; repeating `getSelf({ unauthorize: "/signin" })` in the page is fine and common.
|
|
42
|
-
- Keep `async` even when nothing is awaited — it marks a real server page.
|
|
43
|
-
- No `useState`, no `useEffect`, and no comments in page files.
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: sync-enforced Akan app/lib layout and generated index conventions
|
|
3
|
-
globs: apps/**/*,libs/**/*
|
|
4
|
-
alwaysApply: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Akan Sync Conventions
|
|
8
|
-
|
|
9
|
-
- `apps/<appName>` root may only contain these files: `AGENTS.md`, `CLAUDE.md`, `akan.app.json`, `akan.config.ts`, `capacitor.config.ts`, `client.ts`, `main.ts`, `package.json`, `server.ts`, `tsconfig.json`.
|
|
10
|
-
- `apps/<appName>` root may only contain these folders: `.akan`, `android`, `common`, `env`, `ios`, `lib`, `mobile`, `page`, `plugin`, `private`, `public`, `script`, `secrets`, `srvkit`, `ui`, `webkit`.
|
|
11
|
-
- `akan sync` maintains a scoped agent guide per app/lib (`apps/<app>/AGENTS.md` / `libs/<lib>/AGENTS.md`); the `akan:agent` block in it is generated, content outside the markers is hand-editable, and `akan lint` fails when the block is stale.
|
|
12
|
-
- Do not add `apps/*/base`; place shared app utilities under `apps/*/common`.
|
|
13
|
-
- `apps/*/lib` and `libs/*/lib` root files are limited to generated/support files: `cnst.ts`, `db.ts`, `dict.ts`, `option.ts`, `sig.ts`, `srv.ts`, `st.ts`, `useClient.ts`, `useServer.ts`.
|
|
14
|
-
- Domain module folders are `lib/<model>` for database modules, `lib/_<service>` for service modules, and `lib/__scalar/<scalar>` for scalar modules.
|
|
15
|
-
- Database module UI files are limited to `<Model>.Template.tsx`, `<Model>.Unit.tsx`, `<Model>.Util.tsx`, `<Model>.View.tsx`, and `<Model>.Zone.tsx`.
|
|
16
|
-
- Service module UI files are limited to `<Service>.Util.tsx` and `<Service>.Zone.tsx`.
|
|
17
|
-
- Scalar module UI files are limited to `<Scalar>.Template.tsx` and `<Scalar>.Unit.tsx`.
|
|
18
|
-
- Module `*.test.ts`, `*.test.tsx`, `*.spec.ts`, and `*.spec.tsx` files are allowed.
|
|
19
|
-
- `ui/index.ts`, `webkit/index.ts`, `srvkit/index.ts`, `common/index.ts`, and module `lib/**/index.ts` files are generated by `akan sync`; do not hand-edit or track them.
|
|
20
|
-
- Generated facet indexes export only 1-depth files/folders with `export * from "./name";`.
|
|
21
|
-
|
|
22
|
-
## Layer Placement
|
|
23
|
-
|
|
24
|
-
| Folder | Admission test | Naming |
|
|
25
|
-
|---|---|---|
|
|
26
|
-
| `common/` | pure, isomorphic, zero-dependency; may import only sibling `common/*` and `akanjs/base`. Cannot import `Err`, so keep throwing code out of it. | camelCase file, filename equals the single export |
|
|
27
|
-
| `webkit/` | touches `window` / `navigator` / Capacitor, or is a React hook | `use<Thing>.tsx` — `.tsx` even with no JSX |
|
|
28
|
-
| `srvkit/` | touches `node:*`, `Bun`, `process.env`, a secret, or a server SDK | camelCase file, PascalCase class |
|
|
29
|
-
| `ui/` | renders JSX and is not bound to one model | PascalCase component, camelCase sidecar (`swipeCard.util.ts`) |
|
|
30
|
-
|
|
31
|
-
- Hooks return a named object of async closures, never a tuple.
|
|
32
|
-
- Only layer-root `index.ts` barrels are generated. A `ui/<Folder>/index.tsx` that builds a namespace is hand-written source; the distinguishing test is that a generated barrel contains nothing but `export * from "./X";` lines.
|
|
33
|
-
- `ui/<Folder>/index_.tsx` (trailing underscore) is the `"use client"` + `lazy()` boundary, with a server-safe `index.tsx` beside it. Collapsing the pair into one file breaks RSC.
|
|
34
|
-
- Never add a sibling helper file inside `lib/<model>/`; helpers belong in one of the folders above.
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Application test commands after source changes
|
|
3
|
-
alwaysApply: true
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Application Test Commands
|
|
7
|
-
|
|
8
|
-
- After changing application source code, test the app with `bun run akan start <appName>`.
|
|
9
|
-
- Test production build generation with `bun run akan build <appName>`.
|
|
10
|
-
- To test a built artifact locally, run it from the generated app directory with the required Akan runtime environment variables.
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
cd dist/apps/<appName> && USE_AKANJS_PKGS=true AKAN_PUBLIC_REPO_NAME=akansoft AKAN_PUBLIC_SERVE_DOMAIN="akanjs.com" AKAN_PUBLIC_APP_NAME=seon AKAN_PUBLIC_ENV=local AKAN_PUBLIC_OPERATION_MODE=local SERVER_MODE=federation AKAN_PUBLIC_BASE_PATHS=operator,office,homepage bun main.js
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
- Adjust `<appName>`, `AKAN_PUBLIC_APP_NAME`, and `AKAN_PUBLIC_BASE_PATHS` to match the app being tested.
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Keep edits scoped and avoid unrelated churn
|
|
3
|
-
alwaysApply: true
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Change Scope
|
|
7
|
-
|
|
8
|
-
- Keep edits scoped to the requested task and the directly related files.
|
|
9
|
-
- Do not reformat unrelated files or rewrite nearby code just for style.
|
|
10
|
-
- Do not revert or overwrite unrelated user changes in a dirty working tree.
|
|
11
|
-
- Prefer established nearby patterns over introducing a new abstraction.
|
|
12
|
-
- Add new abstractions only when they remove real duplication or match an existing project pattern.
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Client/server boundary conventions for Akan apps
|
|
3
|
-
globs: apps/**/*.{ts,tsx},libs/**/*.{ts,tsx},pkgs/akanjs/**/*.{ts,tsx}
|
|
4
|
-
alwaysApply: false
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Client Server Boundaries
|
|
8
|
-
|
|
9
|
-
- Use `"use client";` at the top of client component files.
|
|
10
|
-
- Be careful when importing client-only code from page or layout modules.
|
|
11
|
-
- Keep page props serializable unless the existing route pattern clearly allows otherwise.
|
|
12
|
-
- Let server page/layout files own route-level concerns: `usePage`, headers, static layout, and `akanjs/ui` `Tab` composition.
|
|
13
|
-
- Keep interactive loading, submit/import actions, local form inputs, and `router.push` inside client `Util`, `Template`, or `Zone` components.
|
|
14
|
-
- Prefer server-rendered `Tab` shells for static mode selection; put one client component inside each `Tab.Panel` instead of managing the selected mode with extra `useState`.
|
|
15
|
-
- In domain UI the boundary is mechanical, not a judgment call: `Template`, `Zone`, and `Util` are always client components with `"use client"` on line 1; `Unit` and `View` are always server components and never carry the directive. `usePage()` is still legal in server files.
|
|
16
|
-
- Preserve established domain file roles such as `.document.ts`, `.service.ts`, `.store.ts`, `.constant.ts`, and `.client.ts`.
|
|
17
|
-
- When unsure, inspect nearby files in the same app or package before introducing a new boundary pattern.
|
|
18
|
-
- The boundary is only half the rule: how *little* ends up on the client is the other half. See `ssr-first.mdc`.
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Do not narrate code; document only what the code cannot say
|
|
3
|
-
alwaysApply: true
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Comments
|
|
7
|
-
|
|
8
|
-
Do not narrate code. Do document the thing the code cannot say. Both halves are the rule.
|
|
9
|
-
|
|
10
|
-
- Never add a comment that restates the identifier, the signature, or the control flow.
|
|
11
|
-
- Prefer clear names and structure so ordinary logic needs no explanation.
|
|
12
|
-
- Do not add JSDoc, section banners, or "why/how" comments for ordinary logic.
|
|
13
|
-
- Comment density tracks the layer, not the author: pages carry none, product `lib/` and `ui/` code stays under 1 %, and `srvkit/` adapters and `guards.ts` carry as much as the external constraints require.
|
|
14
|
-
- A comment is warranted for: a vendor spec or protocol quirk; an infrastructure constraint; a third-party library gotcha; security reasoning; why a rule that looks arbitrary is correct; a math derivation; a domain field's business meaning; a state transition above a document chain method; why an obvious alternative was rejected.
|
|
15
|
-
- In-code markers:
|
|
16
|
-
1. `TODO` — unfinished work that must be tracked in-code
|
|
17
|
-
2. `FIXME` — known broken or incorrect behavior that must be fixed
|
|
18
|
-
3. `XXX` — dangerous / surprising hazard that a reader must not miss
|
|
19
|
-
4. `//!` — disabled or must-fix code
|
|
20
|
-
5. `//?` — an explanatory aside
|
|
21
|
-
6. `//*` — a design note
|
|
22
|
-
7. Deletion caution — warn why removing a line or block would break something non-obvious
|
|
23
|
-
- Keep allowed comments one short line when possible.
|
|
24
|
-
- Every suppression carries a reason: `// biome-ignore lint/<rule>: <why>`. Never a bare disable block.
|
|
25
|
-
- Match nearby file style: if the surrounding code has few comments, keep it that way.
|