@akanjs/cli 2.4.2-rc.3 → 3.0.0-alpha.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 (84) hide show
  1. package/.build-stamp +1 -1
  2. package/{abstractCompactor-ghh1q9an.js → abstractCompactor-e5yq60qz.js} +4 -4
  3. package/{agent.command-de4r6vk8.js → agent.command-yv00p0s0.js} +8 -7
  4. package/{application.command-nfsfm96y.js → application.command-0qsczf4k.js} +6 -6
  5. package/{applicationBuildRunner-554a2vnk.js → applicationBuildRunner-ct2pxyvw.js} +3 -2
  6. package/{applicationReleasePackager-pjbxc793.js → applicationReleasePackager-gg8ccbeh.js} +3 -3
  7. package/buildBatch.proc.js +8 -7
  8. package/{capacitorApp-yg9b4ajz.js → capacitorApp-4r9sm3qg.js} +3 -3
  9. package/{cloud.command-1qf95x67.js → cloud.command-dxfv18sa.js} +10 -10
  10. package/{context.command-hhjyjtp7.js → context.command-8d9e3k6b.js} +16 -15
  11. package/{guideline.command-vj956kfr.js → guideline.command-3jbkxzh6.js} +10 -10
  12. package/guidelines/componentRule/componentRule.instruction.md +2 -2
  13. package/guidelines/cssRule/cssRule.generate.json +1 -1
  14. package/guidelines/cssRule/cssRule.instruction.md +57 -34
  15. package/guidelines/framework/framework.instruction.md +1 -1
  16. package/guidelines/recipeRule/recipeRule.generate.json +31 -0
  17. package/guidelines/recipeRule/recipeRule.instruction.md +72 -0
  18. package/guidelines/ssrRule/ssrRule.generate.json +31 -0
  19. package/guidelines/ssrRule/ssrRule.instruction.md +108 -0
  20. package/incrementalBuilder.proc.js +6 -6
  21. package/{index-nsj2ftxj.js → index-0cj2zxbm.js} +3 -3
  22. package/{index-y1e79mz3.js → index-1pvex4az.js} +13 -13
  23. package/{index-h971erkm.js → index-2q1f5j9k.js} +3 -3
  24. package/{index-s9s0n5fz.js → index-7c6k4yvg.js} +2 -2
  25. package/{index-d0h48d2f.js → index-8hsbnyes.js} +1 -1
  26. package/{index-v9jqrdd1.js → index-a00jg8x8.js} +100 -2
  27. package/{index-dgeaqwmw.js → index-bbkek1bp.js} +1 -1
  28. package/{index-acwxfncv.js → index-bekddz9q.js} +4 -4
  29. package/{index-fbv96xaw.js → index-e16gnn26.js} +39 -16
  30. package/{index-z5v766nx.js → index-ec09pws3.js} +6 -6
  31. package/{index-zn9rh7sh.js → index-ej426mcr.js} +73 -24
  32. package/{index-xwfg9bam.js → index-hgna5rjy.js} +120 -4
  33. package/{index-z36qzgzp.js → index-k95xkh4p.js} +3 -4
  34. package/{index-7ppn9v4n.js → index-mr5s7mqd.js} +3 -3
  35. package/{index-6pz1j0zj.js → index-mxvakhsm.js} +6 -2
  36. package/{index-h6eav7zx.js → index-nm6wghb6.js} +6 -6
  37. package/{index-7k9sj7j5.js → index-pyt2b4nw.js} +212 -0
  38. package/{index-pfnh87f9.js → index-rzwcpcc3.js} +1 -1
  39. package/{index-zfp1gz9f.js → index-t3723f99.js} +1 -1
  40. package/{index-xftstr5s.js → index-tdbas9r0.js} +1 -1
  41. package/index-xjd3rqzj.js +129 -0
  42. package/index-xys926f2.js +136 -0
  43. package/{index-04as43rp.js → index-yzmhasdb.js} +16 -15
  44. package/{index-h5cvg9z9.js → index-zasydjxd.js} +4 -4
  45. package/index.js +19 -19
  46. package/{library.command-68ah07a3.js → library.command-ebdj1vnm.js} +4 -4
  47. package/{localRegistry.command-84dz000g.js → localRegistry.command-gb178ne8.js} +9 -9
  48. package/{module.command-t68xhamx.js → module.command-9c1bnsx4.js} +8 -8
  49. package/{package.command-00ncttab.js → package.command-t93p4jkj.js} +4 -4
  50. package/package.json +2 -3
  51. package/{page.command-1096s18n.js → page.command-k3k0meh2.js} +4 -4
  52. package/{primitive.command-02eqpx6t.js → primitive.command-de6nktdt.js} +9 -9
  53. package/{quality.command-r9cageqb.js → quality.command-z5kth2wa.js} +451 -48
  54. package/recipeScanner-tghkzrrt.js +12 -0
  55. package/{repair.command-7dynpnf1.js → repair.command-ehf2g112.js} +7 -6
  56. package/{scalar.command-3kxy3fkh.js → scalar.command-7a2jtv33.js} +7 -7
  57. package/templates/app/page/_index.tsx +55 -52
  58. package/templates/app/page/styles.css.template +12 -71
  59. package/templates/appSample/lib/task/Task.Template.tsx +2 -2
  60. package/templates/appSample/lib/task/Task.Unit.tsx +11 -11
  61. package/templates/appSample/lib/task/Task.Util.tsx +27 -28
  62. package/templates/appSample/lib/task/Task.View.tsx +22 -19
  63. package/templates/appSample/lib/task/Task.Zone.tsx +3 -3
  64. package/templates/appSample/page/task/[taskId]/_index.tsx +3 -3
  65. package/templates/appSample/page/task/[taskId]/edit.tsx +5 -5
  66. package/templates/appSample/page/task/_index.tsx +4 -4
  67. package/templates/appSample/page/task/_layout.tsx +1 -1
  68. package/templates/appSample/page/task/new.tsx +5 -5
  69. package/templates/appSample/ui/GlobalLoading.tsx +4 -4
  70. package/templates/appSample/ui/QuantityControl.tsx +5 -4
  71. package/templates/crudPages/[__model__Id]/page.tsx +1 -1
  72. package/templates/crudPages/page.tsx +1 -1
  73. package/templates/crudSinglePage/page.tsx +1 -1
  74. package/templates/module/__Model__.Template.tsx +2 -1
  75. package/templates/module/__Model__.Unit.tsx +2 -1
  76. package/templates/module/__Model__.Util.tsx +2 -1
  77. package/templates/module/__Model__.View.tsx +4 -3
  78. package/templates/module/__Model__.Zone.tsx +2 -1
  79. package/templates/workspaceRoot/.cursor/rules/client-server-boundaries.mdc.template +1 -0
  80. package/templates/workspaceRoot/.cursor/rules/ssr-first.mdc.template +59 -0
  81. package/templates/workspaceRoot/AGENTS.md.template +139 -20
  82. package/templates/workspaceRoot/biome.json.template +1 -1
  83. package/{workflow.command-yy0d9gk3.js → workflow.command-e0tt0vk2.js} +15 -14
  84. package/{workspace.command-stv9g4a0.js → workspace.command-fpda0evj.js} +87 -27
@@ -1,26 +1,37 @@
1
1
  // @bun
2
2
  import {
3
3
  AkanContextAnalyzer
4
- } from "./index-v9jqrdd1.js";
4
+ } from "./index-a00jg8x8.js";
5
5
  import {
6
6
  Prompter
7
- } from "./index-xftstr5s.js";
7
+ } from "./index-tdbas9r0.js";
8
8
  import {
9
9
  runner,
10
10
  script
11
- } from "./index-d0h48d2f.js";
11
+ } from "./index-8hsbnyes.js";
12
+ import {
13
+ AGENT_BLOCK_END,
14
+ AGENT_BLOCK_START,
15
+ AppExecutor,
16
+ LibExecutor,
17
+ renderRecipeEntries,
18
+ upsertAgentBlock
19
+ } from "./index-hgna5rjy.js";
20
+ import {
21
+ collectRecipeSources,
22
+ scanRecipes
23
+ } from "./index-xys926f2.js";
12
24
 
13
25
  // pkgs/@akanjs/cli/agent/agent.script.ts
14
- import { Logger } from "akanjs/common";
26
+ import { Logger as Logger2 } from "akanjs/common";
15
27
 
16
28
  // pkgs/@akanjs/cli/agent/agent.runner.ts
29
+ import { Logger } from "akanjs/common";
17
30
  var targetPaths = {
18
31
  cursor: ".cursor/rules/akan.mdc",
19
32
  "agents-md": "AGENTS.md",
20
33
  claude: "CLAUDE.md"
21
34
  };
22
- var AGENT_BLOCK_START = "<!-- akan:agent:start -->";
23
- var AGENT_BLOCK_END = "<!-- akan:agent:end -->";
24
35
  var SAMPLE_ARTIFACTS = [
25
36
  { probe: "lib/task/task.constant.ts", target: "lib/task", label: "sample database module" },
26
37
  { probe: "lib/_noti/noti.service.ts", target: "lib/_noti", label: "sample service module" },
@@ -60,12 +71,44 @@ ${items.join(`
60
71
 
61
72
  Keep a sample only while you are still learning its pattern; delete it once your own modules cover the same ground.
62
73
 
74
+ `;
75
+ };
76
+ var renderRecipeIndex = async (workspace) => {
77
+ const sources = await collectRecipeSources(`${workspace.workspaceRoot}/pkgs/akanjs/ui`, "akanjs/ui", "recipe");
78
+ const recipes = scanRecipes(sources);
79
+ const scopeIndexPointer = `App and lib recipes are **not** listed here. Each app/lib carries its own generated index \u2014
80
+ \`apps/<app>/AGENTS.md\` / \`libs/<lib>/AGENTS.md\` (\`## Recipes In Scope\`) \u2014 regenerated by \`akan sync\` and
81
+ verified by \`akan lint\`. When working inside an app or lib, consult that file before consuming or authoring a look.`;
82
+ if (recipes.length === 0)
83
+ return `## Recipes
84
+
85
+ ${scopeIndexPointer}
86
+
87
+ `;
88
+ return `## Recipes
89
+
90
+ Framework UI recipes (Tailwind-variant look factories), importable from every app and lib. Consume by exact name \u2014
91
+ \`import { <name> } from "akanjs/ui"\`, then \`<name>(variants?, className?)\`. The second arg merges internally and
92
+ takes **an array too**, so never wrap it in \`cn()\`: \`<name>({}, ["h-full", isWide && "w-full", className])\`.
93
+ Do not guess recipe names, import paths, or variant values; the list below carries
94
+ the full contract (\`*\` marks the default, \`key?\` is a boolean flag), so there is no need to open the recipe file to
95
+ consume one. tsc still reports variant mistakes. **Before inlining a repeated surface (card, box,
96
+ tile, \u2026): reuse a recipe, or add one as \`apps/<app>/ui/Recipe/<name>.ts\` (one recipe per file, re-exported from
97
+ that folder's \`index.ts\`) \u2014 never re-implement the same look inline in several places, and never author a
98
+ near-duplicate.** Full authoring/consumption policy: the \`recipeRule\` guideline.
99
+
100
+ ${renderRecipeEntries(recipes)}
101
+
102
+ ${scopeIndexPointer}
103
+
63
104
  `;
64
105
  };
65
106
  var renderManagedBlock = async (workspace) => {
66
107
  const context = await AkanContextAnalyzer.analyze(workspace);
67
108
  const frameworkGuide = await Prompter.getInstruction("framework");
68
- const sampleCleanup = await renderSampleCleanup(workspace, context.apps.map((app) => app.name));
109
+ const appNames = context.apps.map((app) => app.name);
110
+ const sampleCleanup = await renderSampleCleanup(workspace, appNames);
111
+ const recipeIndex = await renderRecipeIndex(workspace);
69
112
  return `## Workspace
70
113
 
71
114
  - Repo: ${context.repoName}
@@ -86,7 +129,7 @@ ${sampleCleanup}## Akan Module Abstracts
86
129
  Do not hand-edit generated Akan files such as ${context.generatedFiles.map((file) => `\`${file}\``).join(", ")}.
87
130
  If generated output is stale or broken, update the owning source file and run \`akan repair generated\` or \`akan sync <app-or-lib>\`.
88
131
 
89
- ## MCP Workflow Policy
132
+ ${recipeIndex}## MCP Workflow Policy
90
133
 
91
134
  - Prefer Akan MCP workflows before direct source edits.
92
135
  - Direct source edits are denied when an allowlisted Akan workflow or repair tool can perform the change.
@@ -107,24 +150,10 @@ ${context.validationCommands.map((command) => `- \`${command}\``).join(`
107
150
 
108
151
  ${frameworkGuide.trim()}`;
109
152
  };
110
- var upsertManagedBlock = (existing, block) => {
111
- const managed = `${AGENT_BLOCK_START}
112
- ${block}
113
- ${AGENT_BLOCK_END}`;
114
- const startIndex = existing.indexOf(AGENT_BLOCK_START);
115
- const endIndex = existing.indexOf(AGENT_BLOCK_END);
116
- if (startIndex >= 0 && endIndex > startIndex) {
117
- return `${existing.slice(0, startIndex)}${managed}${existing.slice(endIndex + AGENT_BLOCK_END.length)}`;
118
- }
119
- return `${existing.replace(/\s*$/, "")}
120
-
121
- ${managed}
122
- `;
123
- };
124
153
  var renderAgentsMd = async (workspace, existing) => {
125
154
  const block = await renderManagedBlock(workspace);
126
155
  if (existing?.trim())
127
- return upsertManagedBlock(existing, block);
156
+ return upsertAgentBlock(existing, block);
128
157
  const context = await AkanContextAnalyzer.analyze(workspace);
129
158
  return `# ${context.repoName} Agent Guide
130
159
 
@@ -176,6 +205,26 @@ class AgentRunner extends runner("agent") {
176
205
  await workspace.writeFile(filePath, content, { overwrite: true });
177
206
  written.push(filePath);
178
207
  }
208
+ if (targets.includes("agents-md"))
209
+ written.push(...await this.#installScopeIndexes(workspace));
210
+ return written;
211
+ }
212
+ async#installScopeIndexes(workspace) {
213
+ const [appNames, libNames] = await workspace.getExecs();
214
+ const written = [];
215
+ const syncScope = async (exec) => {
216
+ try {
217
+ await exec.syncAgentsIndex();
218
+ written.push(`${exec.type}s/${exec.name}/AGENTS.md`);
219
+ } catch (error) {
220
+ const message = error instanceof Error ? error.message : String(error);
221
+ Logger.rawLog(`Skipped ${exec.type}s/${exec.name}/AGENTS.md (${message})`, undefined, "warn");
222
+ }
223
+ };
224
+ for (const name of libNames)
225
+ await syncScope(LibExecutor.from(workspace, name));
226
+ for (const name of appNames)
227
+ await syncScope(AppExecutor.from(workspace, name));
179
228
  return written;
180
229
  }
181
230
  }
@@ -194,7 +243,7 @@ class AgentScript extends script("agent", [AgentRunner]) {
194
243
  if (action !== "install")
195
244
  throw new Error(`Unknown agent action: ${action}. Use "install".`);
196
245
  const written = await this.agentRunner.install(workspace, resolveTargets(target), { force });
197
- Logger.rawLog(`Agent rules written:
246
+ Logger2.rawLog(`Agent rules written:
198
247
  ${written.map((file) => `- ${file}`).join(`
199
248
  `)}`);
200
249
  }
@@ -1,10 +1,10 @@
1
1
  // @bun
2
+ import {
3
+ Spinner
4
+ } from "./index-mxvakhsm.js";
2
5
  import {
3
6
  FileSys
4
7
  } from "./index-67546d0j.js";
5
- import {
6
- Spinner
7
- } from "./index-6pz1j0zj.js";
8
8
  import {
9
9
  __require
10
10
  } from "./index-r24hmh0q.js";
@@ -39,6 +39,109 @@ import {
39
39
  var {$ } = globalThis.Bun;
40
40
  import chalk2 from "chalk";
41
41
 
42
+ // pkgs/@akanjs/devkit/agentsIndex.ts
43
+ var recipeScannerLoad = null;
44
+ var loadRecipeScanner = () => recipeScannerLoad ??= import("./recipeScanner-tghkzrrt.js");
45
+ var AGENT_BLOCK_START = "<!-- akan:agent:start -->";
46
+ var AGENT_BLOCK_END = "<!-- akan:agent:end -->";
47
+ var upsertAgentBlock = (existing, block) => {
48
+ const managed = `${AGENT_BLOCK_START}
49
+ ${block}
50
+ ${AGENT_BLOCK_END}`;
51
+ const startIndex = existing.indexOf(AGENT_BLOCK_START);
52
+ const endIndex = existing.indexOf(AGENT_BLOCK_END);
53
+ if (startIndex >= 0 && endIndex > startIndex) {
54
+ return `${existing.slice(0, startIndex)}${managed}${existing.slice(endIndex + AGENT_BLOCK_END.length)}`;
55
+ }
56
+ return `${existing.replace(/\s*$/, "")}
57
+
58
+ ${managed}
59
+ `;
60
+ };
61
+ var extractAgentBlock = (content) => {
62
+ const startIndex = content.indexOf(AGENT_BLOCK_START);
63
+ const endIndex = content.indexOf(AGENT_BLOCK_END);
64
+ if (startIndex < 0 || endIndex <= startIndex)
65
+ return null;
66
+ return content.slice(startIndex + AGENT_BLOCK_START.length, endIndex).trim();
67
+ };
68
+ var signatureOf = (recipe) => {
69
+ const entries = Object.entries(recipe.variants);
70
+ if (entries.length === 0)
71
+ return "";
72
+ const parts = entries.map(([key, values]) => {
73
+ if (values.length === 1 && values[0] === "true")
74
+ return `${key}?`;
75
+ const def = recipe.defaultVariants?.[key];
76
+ return `${key}: ${values.map((value) => value === def ? `${value}*` : value).join("|")}`;
77
+ });
78
+ return `(${parts.join(" \xB7 ")})`;
79
+ };
80
+ var renderRecipeEntries = (recipes) => {
81
+ const groups = new Map;
82
+ for (const recipe of recipes)
83
+ groups.set(recipe.importFrom, [...groups.get(recipe.importFrom) ?? [], recipe]);
84
+ return [...groups.entries()].map(([importFrom, list]) => {
85
+ const items = list.sort((a, b) => a.name.localeCompare(b.name)).map((recipe) => `- \`${recipe.name}\`${signatureOf(recipe)}${recipe.doc ? ` \u2014 ${recipe.doc}` : ""}`).join(`
86
+ `);
87
+ return `Import from \`${importFrom}\`:
88
+ ${items}`;
89
+ }).join(`
90
+
91
+ `);
92
+ };
93
+ var collectScopeRecipeSources = async (workspaceRoot, scope, libDeps) => {
94
+ const { collectRecipeSources } = await loadRecipeScanner();
95
+ const sources = [
96
+ ...await collectRecipeSources(`${workspaceRoot}/${scope.type}s/${scope.name}/ui`, `@${scope.type}s/${scope.name}/ui`)
97
+ ];
98
+ for (const lib of [...new Set(libDeps)].sort()) {
99
+ if (scope.type === "lib" && lib === scope.name)
100
+ continue;
101
+ sources.push(...await collectRecipeSources(`${workspaceRoot}/libs/${lib}/ui`, `@libs/${lib}/ui`));
102
+ }
103
+ return sources;
104
+ };
105
+ var scanScopeRecipes = async (workspaceRoot, scope, libDeps) => {
106
+ const { scanRecipes } = await loadRecipeScanner();
107
+ return scanRecipes(await collectScopeRecipeSources(workspaceRoot, scope, libDeps));
108
+ };
109
+ var renderScopeAgentBlock = (scope, recipes) => {
110
+ const scopePath = `${scope.type}s/${scope.name}`;
111
+ const intro = `## Recipes In Scope
112
+
113
+ UI recipes importable from \`${scopePath}\` code, **in addition to** the framework recipes indexed in the root
114
+ \`AGENTS.md\` \`## Recipes\`. Same contract: import by exact name, then \`<name>(variants?, className?)\` \u2014 the second
115
+ arg merges internally and takes an array too, so never wrap it in \`cn()\`. \`*\` marks the default, \`key?\` is a
116
+ boolean flag. Do not guess recipe names or import paths; this index is regenerated by \`akan sync ${scope.name}\`
117
+ and verified by \`akan lint ${scope.name}\`.`;
118
+ if (recipes.length === 0) {
119
+ return `${intro}
120
+
121
+ No scope recipes yet. Before inlining a repeated surface (card, box, tile, \u2026), reuse a framework recipe from the
122
+ root \`AGENTS.md\` or author one as \`${scopePath}/ui/Recipe/<name>.ts\` (one recipe per file, re-exported from that
123
+ folder's \`index.ts\`) \u2014 see the \`recipeRule\` guideline.`;
124
+ }
125
+ return `${intro}
126
+
127
+ ${renderRecipeEntries(recipes)}`;
128
+ };
129
+ var renderScopeAgentsMd = (scope, block) => `# ${scope.name} \u2014 Agent Guide
130
+
131
+ Scoped guide for coding agents working in \`${scope.type}s/${scope.name}\`. Workspace-wide conventions live in the
132
+ root \`AGENTS.md\`; this file carries what is importable from this ${scope.type === "app" ? "app" : "library"}. The
133
+ section between the \`akan:agent\` markers is regenerated by \`akan sync ${scope.name}\`; edit anything outside the
134
+ markers freely.
135
+
136
+ ${AGENT_BLOCK_START}
137
+ ${block}
138
+ ${AGENT_BLOCK_END}
139
+ `;
140
+ var renderScopeClaudeMd = (scope) => `# ${scope.name} \u2014 Claude Code Guide
141
+
142
+ @AGENTS.md
143
+ `;
144
+
42
145
  // pkgs/@akanjs/devkit/akanConfig/akanConfig.ts
43
146
  import fs from "fs";
44
147
  import path from "path";
@@ -824,6 +927,8 @@ var databaseFileTypes = [
824
927
  "zone"
825
928
  ];
826
929
  var appRootAllowedFiles = new Set([
930
+ "AGENTS.md",
931
+ "CLAUDE.md",
827
932
  "akan.app.json",
828
933
  "akan.config.ts",
829
934
  "capacitor.config.ts",
@@ -2252,10 +2357,21 @@ class SysExecutor extends Executor {
2252
2357
  await this.#updateDependencies(scanInfo);
2253
2358
  await Promise.all(libInfos.flatMap((libInfo) => libInfo.exec.#getScanTemplateTasks(libInfo)));
2254
2359
  }
2360
+ await this.syncAgentsIndex(scanInfo);
2255
2361
  }
2256
2362
  this.#scanInfo = scanInfo;
2257
2363
  return scanInfo;
2258
2364
  }
2365
+ async syncAgentsIndex(scanInfo) {
2366
+ const info = scanInfo ?? await this.scan({ write: false });
2367
+ const scope = { type: this.type, name: this.name };
2368
+ const recipes = await scanScopeRecipes(this.workspace.workspaceRoot, scope, info.getScanResult().libDeps);
2369
+ const block = renderScopeAgentBlock(scope, recipes);
2370
+ const existing = await this.exists("AGENTS.md") ? await this.readFile("AGENTS.md") : null;
2371
+ await this.writeFile("AGENTS.md", existing?.trim() ? upsertAgentBlock(existing, block) : renderScopeAgentsMd(scope, block));
2372
+ if (!await this.exists("CLAUDE.md"))
2373
+ await this.writeFile("CLAUDE.md", renderScopeClaudeMd(scope));
2374
+ }
2259
2375
  async#updateDependencies(scanInfo) {
2260
2376
  const rootPackageJson = await this.workspace.getPackageJson();
2261
2377
  const libPackageJson = await this.getPackageJson();
@@ -2887,4 +3003,4 @@ class ModuleExecutor extends Executor {
2887
3003
  }
2888
3004
  }
2889
3005
 
2890
- export { getDirname, CommandExecutionError, Executor, WorkspaceExecutor, AppExecutor, LibExecutor, PkgExecutor, ModuleExecutor };
3006
+ export { AGENT_BLOCK_START, AGENT_BLOCK_END, upsertAgentBlock, extractAgentBlock, renderRecipeEntries, collectScopeRecipeSources, renderScopeAgentBlock, getDirname, CommandExecutionError, Executor, WorkspaceExecutor, SysExecutor, AppExecutor, LibExecutor, PkgExecutor, ModuleExecutor };
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-d0h48d2f.js";
5
+ } from "./index-8hsbnyes.js";
6
6
  import {
7
7
  PkgExecutor
8
- } from "./index-xwfg9bam.js";
8
+ } from "./index-hgna5rjy.js";
9
9
  import {
10
10
  TypeScriptDependencyScanner
11
11
  } from "./index-46tjzh6s.js";
@@ -153,14 +153,13 @@ class PackageRunner extends runner("package") {
153
153
  const scanner = await TypeScriptDependencyScanner.from(pkg);
154
154
  const { npmDeps, npmDevDeps, missingDeps } = await scanner.getPackageBuildDependencies(pkg.name);
155
155
  const packageRuntimeDependencies = {
156
- "@akanjs/devkit": ["daisyui", "tailwind-scrollbar"]
156
+ "@akanjs/devkit": ["tailwind-scrollbar"]
157
157
  };
158
158
  const packageRuntimeDevDependencies = { akanjs: ["@biomejs/biome", "@types/bun"] };
159
159
  if (pkg.name === "@akanjs/cli") {
160
160
  const devkitPackageJson = await pkg.workspace.readJson("pkgs/@akanjs/devkit/package.json");
161
161
  packageRuntimeDependencies[pkg.name] = [
162
162
  ...Object.keys(devkitPackageJson.dependencies ?? {}),
163
- "daisyui",
164
163
  "tailwind-scrollbar"
165
164
  ].filter((dep) => dep !== "akanjs" && dep !== "@akanjs/devkit");
166
165
  }
@@ -1,17 +1,17 @@
1
1
  // @bun
2
2
  import {
3
3
  AkanContextAnalyzer
4
- } from "./index-v9jqrdd1.js";
4
+ } from "./index-a00jg8x8.js";
5
5
  import {
6
6
  createRepairReport,
7
7
  generatedFilePathsForTarget,
8
8
  renderRepairReport,
9
9
  writeGeneratedSyncState,
10
10
  writeWorkflowRunArtifact
11
- } from "./index-pfnh87f9.js";
11
+ } from "./index-rzwcpcc3.js";
12
12
  import {
13
13
  runner
14
- } from "./index-d0h48d2f.js";
14
+ } from "./index-8hsbnyes.js";
15
15
 
16
16
  // pkgs/@akanjs/cli/repair/repair.runner.ts
17
17
  var commandForShell = (command) => command.startsWith("akan ") ? `bun run ${command}` : command;
@@ -4,6 +4,10 @@ import ora from "ora";
4
4
 
5
5
  class Spinner {
6
6
  static padding = 12;
7
+ static oraOptions = { discardStdin: false };
8
+ static canAnimate(stream = process.stderr) {
9
+ return !stream.isTTY || stream.columns > 0;
10
+ }
7
11
  spinner;
8
12
  stopWatch = null;
9
13
  startAt = new Date;
@@ -14,10 +18,10 @@ class Spinner {
14
18
  Spinner.padding = Math.max(Spinner.padding, prefix.length);
15
19
  this.prefix = prefix;
16
20
  this.message = message;
17
- this.spinner = ora(message);
21
+ this.spinner = ora({ ...Spinner.oraOptions, text: message });
18
22
  this.spinner.prefixText = prefix.padStart(Spinner.padding, " ");
19
23
  this.spinner.indent = indent;
20
- this.enableSpin = enableSpin;
24
+ this.enableSpin = enableSpin && Spinner.canAnimate();
21
25
  }
22
26
  start() {
23
27
  this.startAt = new Date;
@@ -1,24 +1,24 @@
1
1
  // @bun
2
2
  import {
3
3
  CloudRunner
4
- } from "./index-h5cvg9z9.js";
4
+ } from "./index-zasydjxd.js";
5
5
  import {
6
6
  PackageScript
7
- } from "./index-z36qzgzp.js";
7
+ } from "./index-k95xkh4p.js";
8
8
  import {
9
9
  AiSession,
10
10
  CloudApi,
11
11
  GlobalConfig
12
- } from "./index-nsj2ftxj.js";
12
+ } from "./index-0cj2zxbm.js";
13
13
  import {
14
14
  ApplicationScript
15
- } from "./index-fbv96xaw.js";
15
+ } from "./index-e16gnn26.js";
16
16
  import {
17
17
  script
18
- } from "./index-d0h48d2f.js";
18
+ } from "./index-8hsbnyes.js";
19
19
  import {
20
20
  PkgExecutor
21
- } from "./index-xwfg9bam.js";
21
+ } from "./index-hgna5rjy.js";
22
22
 
23
23
  // pkgs/@akanjs/cli/cloud/cloud.script.ts
24
24
  import { Logger } from "akanjs/common";
@@ -2217,4 +2217,216 @@ ${preparedCssText}`).toString(36);
2217
2217
  return [basePath, { cssUrl, cssRelPath }];
2218
2218
  }
2219
2219
  }
2220
+ // pkgs/@akanjs/devkit/frontendBuild/styleGuard.ts
2221
+ var PREFIX = "(?:bg|text|border(?:-[tblrxy])?(?:-[se])?|ring(?:-offset)?|fill|stroke|shadow|from|to|via|divide|outline|decoration|placeholder|caret|accent)";
2222
+ var PALETTE = "(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)";
2223
+ var LEAD = "(^|[\\s\"'`{(\\[:!])";
2224
+ var TAIL = "(?=[\\s\"'`})\\]:/!,]|$)";
2225
+ var RAW_PALETTE_RE = new RegExp(`${LEAD}((?:${PREFIX})-)${PALETTE}-\\d{2,3}${TAIL}`, "g");
2226
+ var ARBITRARY_COLOR_RE = /\[(#[0-9a-fA-F]{3,8}|(?:rgb|rgba|hsl|hsla|oklch|oklab|lab|lch|hwb|color)\([^\]]*\))\]/g;
2227
+ var INTERPOLATED_ARBITRARY_RE = new RegExp(`${LEAD}[a-z][a-z0-9-]*-\\[[^\\]\`]*\\$\\{`, "g");
2228
+ var STYLE_OBJECT_RE = /style=\{\{([\s\S]*?)\}\}/g;
2229
+ var STYLE_TAG_RE = /<style[^>]*>([\s\S]*?)<\/style>/g;
2230
+ var INLINE_COLOR_LITERAL_RE = /#[0-9a-fA-F]{3,8}\b|(?:rgb|rgba|hsl|hsla|oklch|oklab|lab|lch|hwb)\(/g;
2231
+ var DAISYUI_LEGACY_RE = new RegExp(`${LEAD}(?:` + "btn-(?:primary|secondary|accent|neutral|info|success|warning|error|ghost|link|outline|square|circle|wide|block|xs|sm|md|lg)|" + "badge-(?:primary|secondary|accent|neutral|info|success|warning|error|ghost|outline)|" + "alert-(?:info|success|warning|error)|" + "input-(?:bordered|primary|secondary|accent|ghost|error)|" + "select-(?:bordered|primary|ghost)|textarea-(?:bordered|primary|ghost)|" + "checkbox-(?:primary|secondary|accent)|toggle-(?:primary|secondary|accent)|" + "loading-(?:spinner|dots|ring|ball|bars|infinity)|" + "card-(?:body|title|actions)|modal-(?:box|action|backdrop)|" + "collapse-(?:title|content|arrow|plus)|dropdown-(?:content|end|start|hover)|" + "stat-(?:title|value|desc)|tabs-(?:boxed|lifted|bordered)|tab-active|" + "menu-(?:title|dropdown)|steps-(?:horizontal|vertical)|join-item|" + "mockup-(?:code|phone|browser|window)|drawer-(?:side|content|toggle)" + `)${TAIL}`, "g");
2232
+ var ALL_RULES = [
2233
+ "raw-palette",
2234
+ "arbitrary-color",
2235
+ "inline-color",
2236
+ "daisyui-legacy",
2237
+ "interpolated-arbitrary"
2238
+ ];
2239
+
2240
+ class StyleGuard {
2241
+ run(files) {
2242
+ const out = [];
2243
+ for (const file of files) {
2244
+ const directives = this.#parseDirectives(file.content);
2245
+ const scan = this.#stripComments(file.content);
2246
+ const local = [];
2247
+ this.#scanClassLiterals(file, scan, local);
2248
+ this.#scanInlineColors(file, scan, local);
2249
+ for (const v of local)
2250
+ if (!this.#isSuppressed(v, directives))
2251
+ out.push(v);
2252
+ }
2253
+ return out;
2254
+ }
2255
+ #stripComments(src) {
2256
+ const out = src.split("");
2257
+ const blank = (i2) => {
2258
+ if (src[i2] !== `
2259
+ `)
2260
+ out[i2] = " ";
2261
+ };
2262
+ let state = "code";
2263
+ let i = 0;
2264
+ while (i < src.length) {
2265
+ const c = src[i];
2266
+ const d = src[i + 1];
2267
+ if (state === "code") {
2268
+ if (c === "/" && d === "/") {
2269
+ blank(i);
2270
+ blank(i + 1);
2271
+ state = "line";
2272
+ i += 2;
2273
+ } else if (c === "/" && d === "*") {
2274
+ blank(i);
2275
+ blank(i + 1);
2276
+ state = "block";
2277
+ i += 2;
2278
+ } else {
2279
+ if (c === "'")
2280
+ state = "squote";
2281
+ else if (c === '"')
2282
+ state = "dquote";
2283
+ else if (c === "`")
2284
+ state = "template";
2285
+ i++;
2286
+ }
2287
+ } else if (state === "line") {
2288
+ if (c === `
2289
+ `)
2290
+ state = "code";
2291
+ else
2292
+ blank(i);
2293
+ i++;
2294
+ } else if (state === "block") {
2295
+ if (c === "*" && d === "/") {
2296
+ blank(i);
2297
+ blank(i + 1);
2298
+ state = "code";
2299
+ i += 2;
2300
+ } else {
2301
+ blank(i);
2302
+ i++;
2303
+ }
2304
+ } else {
2305
+ const close = state === "squote" ? "'" : state === "dquote" ? '"' : "`";
2306
+ if (c === "\\")
2307
+ i += 2;
2308
+ else {
2309
+ if (c === close)
2310
+ state = "code";
2311
+ i++;
2312
+ }
2313
+ }
2314
+ }
2315
+ return out.join("");
2316
+ }
2317
+ #parseDirectives(content) {
2318
+ const directives = { file: null, nextLine: new Map };
2319
+ const lines = content.split(`
2320
+ `);
2321
+ for (let i = 0;i < lines.length; i++) {
2322
+ const line = lines[i];
2323
+ const nextLineMatch = line.match(/styleguard-disable-next-line\b(.*)$/);
2324
+ if (nextLineMatch) {
2325
+ directives.nextLine.set(i + 2, this.#extractRules(nextLineMatch[1]));
2326
+ continue;
2327
+ }
2328
+ const fileMatch = line.match(/styleguard-disable\b(.*)$/);
2329
+ if (fileMatch)
2330
+ directives.file = this.#mergeFileScope(directives.file, this.#extractRules(fileMatch[1]));
2331
+ }
2332
+ return directives;
2333
+ }
2334
+ #extractRules(tail) {
2335
+ const found = ALL_RULES.filter((rule) => tail.includes(rule));
2336
+ return found.length === 0 ? "all" : new Set(found);
2337
+ }
2338
+ #mergeFileScope(prev, next) {
2339
+ if (prev === "all" || next === "all")
2340
+ return "all";
2341
+ return new Set([...prev ?? [], ...next]);
2342
+ }
2343
+ #isSuppressed(v, directives) {
2344
+ if (directives.file === "all" || directives.file?.has(v.rule))
2345
+ return true;
2346
+ const nextLine = directives.nextLine.get(v.line);
2347
+ return nextLine === "all" || (nextLine?.has(v.rule) ?? false);
2348
+ }
2349
+ #scanClassLiterals(file, scan, out) {
2350
+ for (const m of scan.matchAll(RAW_PALETTE_RE)) {
2351
+ out.push(this.#violation(file, m.index ?? 0, {
2352
+ rule: "raw-palette",
2353
+ severity: "error",
2354
+ suggestion: "\uC2DC\uB9E8\uD2F1 \uD1A0\uD070\uC73C\uB85C \uAD50\uCCB4\uD558\uC138\uC694 \u2014 \uC608: text-gray-500\u2192text-muted-foreground, bg-red-500\u2192bg-destructive, bg-blue-500\u2192bg-info. \uBE0C\uB79C\uB4DC \uC0C9\uC740 page/styles.css \uD1A0\uD070\uC5D0\uC11C \uC870\uC815\uD569\uB2C8\uB2E4."
2355
+ }));
2356
+ }
2357
+ for (const m of scan.matchAll(ARBITRARY_COLOR_RE)) {
2358
+ out.push(this.#violation(file, m.index ?? 0, {
2359
+ rule: "arbitrary-color",
2360
+ severity: "error",
2361
+ suggestion: "\uC784\uC758 \uC0C9 \uB9AC\uD130\uB7F4 \uB300\uC2E0 \uD1A0\uD070\uC744 \uC4F0\uC138\uC694 \u2014 bg-[#3b82f6]\u2192bg-info, text-[rgb(...)]\u2192\uC2DC\uB9E8\uD2F1 \uD1A0\uD070. \uAF2D \uD544\uC694\uD558\uBA74 \uC2A4\uCF54\uD504 \uD1A0\uD070(.campaign-x { --primary: \u2026 })\uC744 \uC815\uC758\uD558\uC138\uC694."
2362
+ }));
2363
+ }
2364
+ for (const m of scan.matchAll(DAISYUI_LEGACY_RE)) {
2365
+ out.push(this.#violation(file, m.index ?? 0, {
2366
+ rule: "daisyui-legacy",
2367
+ severity: "error",
2368
+ suggestion: "daisyUI \uD074\uB798\uC2A4\uB294 \uC81C\uAC70\uB410\uC2B5\uB2C8\uB2E4. akanjs/ui \uD504\uB9AC\uBBF8\uD2F0\uBE0C(Button/Badge \uB4F1)\uB098 buttonRecipe()/badgeRecipe() + \uC2DC\uB9E8\uD2F1 \uD1A0\uD070\uC73C\uB85C \uAD50\uCCB4\uD558\uC138\uC694."
2369
+ }));
2370
+ }
2371
+ for (const m of scan.matchAll(INTERPOLATED_ARBITRARY_RE)) {
2372
+ out.push(this.#violation(file, m.index ?? 0, {
2373
+ rule: "interpolated-arbitrary",
2374
+ severity: "error",
2375
+ suggestion: "\uB7F0\uD0C0\uC784 \uAC12\uC73C\uB85C \uC784\uC758\uAC12 \uD074\uB798\uC2A4\uB97C \uC870\uB9BD\uD558\uBA74 CSS \uAC00 \uC0DD\uC131\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4(\uC2A4\uCE90\uB108\uB294 \uC18C\uC2A4 \uD14D\uC2A4\uD2B8\uB97C \uC77D\uC2B5\uB2C8\uB2E4). \uD06C\uAE30/\uC704\uCE58\uB294 style prop \uC73C\uB85C \uB118\uAE30\uC138\uC694 \u2014 style={{ minHeight }}. \uAC12\uC774 enum \uC774\uBA74 \uB9AC\uD130\uB7F4 \uD074\uB798\uC2A4 \uB9F5\uC73C\uB85C \uB450\uC138\uC694."
2376
+ }));
2377
+ }
2378
+ }
2379
+ #scanInlineColors(file, scan, out) {
2380
+ const push = (index) => out.push(this.#violation(file, index, {
2381
+ rule: "inline-color",
2382
+ severity: "error",
2383
+ suggestion: "\uC778\uB77C\uC778 \uC0C9 \uB9AC\uD130\uB7F4 \uB300\uC2E0 CSS \uBCC0\uC218/\uD1A0\uD070\uC744 \uCC38\uC870\uD558\uC138\uC694 \u2014 style={{ color: 'var(--primary)' }} \uB610\uB294 \uC2DC\uB9E8\uD2F1 \uD074\uB798\uC2A4(text-primary). \uD558\uB4DC\uCF54\uB529 hex/rgb \uB294 \uD14C\uB9C8 \uC804\uD658\uC744 \uAE68\uB728\uB9BD\uB2C8\uB2E4."
2384
+ }));
2385
+ for (const region of [STYLE_OBJECT_RE, STYLE_TAG_RE]) {
2386
+ for (const m of scan.matchAll(region)) {
2387
+ const inner = m[1] ?? "";
2388
+ const innerStart = (m.index ?? 0) + m[0].indexOf(inner);
2389
+ for (const lit of inner.matchAll(INLINE_COLOR_LITERAL_RE)) {
2390
+ push(innerStart + (lit.index ?? 0));
2391
+ }
2392
+ }
2393
+ }
2394
+ }
2395
+ #violation(file, index, base) {
2396
+ const before = file.content.slice(0, index);
2397
+ const line = before.length === 0 ? 1 : before.split(`
2398
+ `).length;
2399
+ const lineStart = before.lastIndexOf(`
2400
+ `) + 1;
2401
+ const lineEnd = file.content.indexOf(`
2402
+ `, index);
2403
+ const snippet = file.content.slice(lineStart, lineEnd === -1 ? undefined : lineEnd).trim();
2404
+ return { ...base, path: file.path, line, snippet };
2405
+ }
2406
+ static countNamedComponentClasses(css) {
2407
+ const names = new Set;
2408
+ const layerRe = /@layer\s+components\s*\{/g;
2409
+ for (const layer of css.matchAll(layerRe)) {
2410
+ const bodyStart = (layer.index ?? 0) + layer[0].length;
2411
+ const body = StyleGuard.#extractBalanced(css, bodyStart);
2412
+ for (const sel of body.matchAll(/(^|[\s}])\.(-?[a-zA-Z_][\w-]*)/g))
2413
+ names.add(sel[2]);
2414
+ }
2415
+ return { count: names.size, names: [...names].sort() };
2416
+ }
2417
+ static #extractBalanced(css, start) {
2418
+ let depth = 1;
2419
+ for (let i = start;i < css.length; i++) {
2420
+ const ch = css[i];
2421
+ if (ch === "{")
2422
+ depth++;
2423
+ else if (ch === "}") {
2424
+ depth--;
2425
+ if (depth === 0)
2426
+ return css.slice(start, i);
2427
+ }
2428
+ }
2429
+ return css.slice(start);
2430
+ }
2431
+ }
2220
2432
  export { AllRoutesBuilder, CsrArtifactBuilder, CssCompiler, FontOptimizer, PagesBundleBuilder, precompressArtifacts, SsrBaseArtifactBuilder };
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  AppExecutor,
4
4
  LibExecutor
5
- } from "./index-xwfg9bam.js";
5
+ } from "./index-hgna5rjy.js";
6
6
 
7
7
  // pkgs/@akanjs/devkit/workflow/utils.ts
8
8
  var jsonText = (value, { trailingNewline = true } = {}) => `${JSON.stringify(value, null, 2)}${trailingNewline ? `
@@ -5,7 +5,7 @@ import {
5
5
  } from "./index-76rn3g2c.js";
6
6
  import {
7
7
  CommandExecutionError
8
- } from "./index-xwfg9bam.js";
8
+ } from "./index-hgna5rjy.js";
9
9
 
10
10
  // pkgs/@akanjs/devkit/capacitorApp.ts
11
11
  import { cp, mkdir, readFile, rm, writeFile } from "fs/promises";
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  import {
3
3
  getDirname
4
- } from "./index-xwfg9bam.js";
4
+ } from "./index-hgna5rjy.js";
5
5
 
6
6
  // pkgs/@akanjs/devkit/prompter.ts
7
7
  import fsPromise from "fs/promises";