@akanjs/cli 3.0.0-alpha.10 → 3.0.0-alpha.101

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 (135) hide show
  1. package/.build-stamp +1 -1
  2. package/README.ko.md +1 -1
  3. package/README.md +1 -1
  4. package/{abstractCompactor-e5yq60qz.js → abstractCompactor-byytxs22.js} +3 -5
  5. package/{agent.command-f0gqkfgz.js → agent.command-v1a4746v.js} +11 -13
  6. package/{application.command-x903m2qq.js → application.command-fzdcnzhg.js} +65 -38
  7. package/{applicationBuildRunner-ha3y8ew8.js → applicationBuildRunner-s4gsk728.js} +27 -23
  8. package/{applicationReleasePackager-gg8ccbeh.js → applicationReleasePackager-28v9vbzk.js} +8 -9
  9. package/buildBatch.proc.js +12 -14
  10. package/capacitorApp-8d6d4zkm.js +12 -0
  11. package/{cloud.command-zs6kyf83.js → cloud.command-wygy2z05.js} +15 -18
  12. package/commandManifest.json +1 -1
  13. package/{context.command-fmepgjzg.js → context.command-4vdt1aqq.js} +19 -23
  14. package/dependencyScanner-shs82ynp.js +8 -0
  15. package/devTui-qnf1txdz.js +553 -0
  16. package/devTuiView-yzct2cq6.js +9 -0
  17. package/getDirname-dr3jz1xg.js +7 -0
  18. package/{guideline.command-n6sw0a0c.js → guideline.command-p92dq6ts.js} +16 -18
  19. package/guidelines/agentRule/agentRule.generate.json +31 -0
  20. package/guidelines/agentRule/agentRule.instruction.md +533 -0
  21. package/guidelines/conventions/conventions.instruction.md +447 -197
  22. package/guidelines/cssRule/cssRule.instruction.md +7 -0
  23. package/guidelines/framework/framework.generate.json +3 -2
  24. package/guidelines/framework/framework.instruction.md +1 -9
  25. package/guidelines/mcpRule/mcpRule.generate.json +35 -0
  26. package/guidelines/mcpRule/mcpRule.instruction.md +366 -0
  27. package/guidelines/modelStore/modelStore.instruction.md +12 -0
  28. package/guidelines/modelTemplate/modelTemplate.instruction.md +5 -0
  29. package/guidelines/queryRule/queryRule.generate.json +31 -0
  30. package/guidelines/queryRule/queryRule.instruction.md +178 -0
  31. package/guidelines/runtimeRule/runtimeRule.generate.json +25 -0
  32. package/guidelines/runtimeRule/runtimeRule.instruction.md +220 -0
  33. package/guidelines/ssrRule/ssrRule.instruction.md +49 -5
  34. package/guidelines/transportRule/transportRule.generate.json +31 -0
  35. package/guidelines/transportRule/transportRule.instruction.md +60 -0
  36. package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +51 -760
  37. package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +33 -0
  38. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +402 -0
  39. package/incrementalBuilder.proc.js +26 -25
  40. package/{index-jf2ya7r2.js → index-0amdxycf.js} +8 -8
  41. package/{index-779ske1y.js → index-1yxtbmbj.js} +27 -27
  42. package/{index-eyyf2149.js → index-29sxqfaw.js} +36 -37
  43. package/index-3d9y066c.js +76 -0
  44. package/{index-76rn3g2c.js → index-47pj3aee.js} +4 -4
  45. package/index-5svjba73.js +159 -0
  46. package/{index-1577bej2.js → index-6wwzs1bc.js} +2 -2
  47. package/{index-gcv8ncfh.js → index-7d6vny25.js} +16 -12
  48. package/{index-y4vkyhvv.js → index-8p8p0cf8.js} +14 -14
  49. package/{index-wnp7hwq7.js → index-92zztqy1.js} +7 -7
  50. package/{index-fgc8r6dj.js → index-a5vmm6x4.js} +3 -1
  51. package/{index-xys926f2.js → index-by5gpp8x.js} +4 -4
  52. package/{index-0cj2zxbm.js → index-c69j78kk.js} +12 -11
  53. package/{index-rxkpk7n4.js → index-fc1bh0a7.js} +4 -4
  54. package/{index-d43t8af2.js → index-gq44bqjt.js} +58 -25
  55. package/{index-774gcx29.js → index-gtmz74tj.js} +41 -34
  56. package/{index-j37qq1f2.js → index-h7yw2z9n.js} +7 -7
  57. package/{index-bjpxzr6s.js → index-hwkygn9s.js} +51 -3
  58. package/{index-xmmzf150.js → index-hyywke0f.js} +1 -1
  59. package/{index-46tjzh6s.js → index-kcxmv48c.js} +29 -29
  60. package/{index-xjd3rqzj.js → index-n68jx79w.js} +6 -15
  61. package/{index-qb61h0k7.js → index-p5neav9b.js} +1098 -1360
  62. package/{index-67546d0j.js → index-q0y2jq9j.js} +14 -2
  63. package/{index-3vta1tqa.js → index-qkk27bk6.js} +32 -32
  64. package/{index-z8ptfkzv.js → index-qsq3q8fy.js} +975 -242
  65. package/{index-qzdjd4ct.js → index-srdssqj7.js} +18 -18
  66. package/{index-j9cxndc0.js → index-w8kmx1b6.js} +20 -11
  67. package/{index-82jrh4hj.js → index-yks023mb.js} +13 -13
  68. package/{index-5sn5w2mt.js → index-yza7zkpt.js} +94 -61
  69. package/{index-jhpa13zj.js → index-zmjppp25.js} +57 -57
  70. package/{index-kdh76j26.js → index-znynzt5w.js} +100 -32
  71. package/{index-4m0bphac.js → index-zxgr3s8s.js} +31 -30
  72. package/{index-62955kn5.js → index-zz5jyd94.js} +1002 -128
  73. package/index.js +22 -25
  74. package/{library.command-cv9gdbmg.js → library.command-s4fszngs.js} +11 -10
  75. package/{localRegistry.command-d8fg36zc.js → localRegistry.command-gyw4da9z.js} +20 -23
  76. package/{module.command-qyr1s9cn.js → module.command-6n7dwvav.js} +13 -16
  77. package/{package.command-wsjx0k47.js → package.command-gr82ypnr.js} +8 -10
  78. package/package.json +5 -7
  79. package/{page.command-rdzg65rm.js → page.command-7gvgb3jb.js} +7 -9
  80. package/{primitive.command-89g38b53.js → primitive.command-tk5ckw38.js} +13 -16
  81. package/{quality.command-0cs2z92d.js → quality.command-38v81baf.js} +226 -105
  82. package/recipeScanner-fpagtgc1.js +11 -0
  83. package/{repair.command-6fphxfwj.js → repair.command-5xbwvsxp.js} +12 -14
  84. package/{routeSourceValidator-e4jmbfcx.js → routeSourceValidator-ze6x894c.js} +0 -2
  85. package/{scalar.command-xfer69s6.js → scalar.command-0epwcr5k.js} +11 -14
  86. package/subspace.command-e2t36xb2.js +755 -0
  87. package/templates/app/env/env.client.debug.ts.template +1 -5
  88. package/templates/app/env/env.client.develop.ts.template +1 -5
  89. package/templates/app/env/env.client.local.ts.template +1 -5
  90. package/templates/app/env/env.client.main.ts.template +1 -5
  91. package/templates/app/env/env.client.testing.ts.template +1 -5
  92. package/templates/app/env/env.client.type.ts +2 -6
  93. package/templates/app/env/env.server.debug.ts.template +1 -5
  94. package/templates/app/env/env.server.develop.ts.template +1 -5
  95. package/templates/app/env/env.server.local.ts.template +1 -5
  96. package/templates/app/env/env.server.main.ts.template +1 -5
  97. package/templates/app/main.ts +3 -1
  98. package/templates/appSample/lib/task/task.signal.ts +11 -6
  99. package/templates/appSample/srvkit/AuthGuard.ts +9 -5
  100. package/templates/appSample/srvkit/SessionInternalArg.ts +4 -3
  101. package/templates/crudPages/[__model__Id]/edit/page.tsx +5 -5
  102. package/templates/crudPages/[__model__Id]/page.tsx +10 -13
  103. package/templates/crudPages/new/page.tsx +5 -5
  104. package/templates/crudPages/page.tsx +9 -9
  105. package/templates/crudSinglePage/page.tsx +11 -7
  106. package/templates/env/_env.server.type.ts +7 -5
  107. package/templates/lib/db.ts +1 -1
  108. package/templates/lib/dict.ts +1 -1
  109. package/templates/lib/sig.ts +5 -1
  110. package/templates/lib/srv.ts +6 -2
  111. package/templates/module/__model__.dictionary.ts +4 -1
  112. package/templates/module/__model__.signal.ts +2 -3
  113. package/templates/module/__model__.store.ts +1 -2
  114. package/templates/workspaceRoot/.gitignore.template +0 -1
  115. package/templates/workspaceRoot/.husky/pre-commit.template +16 -0
  116. package/templates/workspaceRoot/.vscode/settings.json.template +1 -1
  117. package/templates/workspaceRoot/AGENTS.md.template +4 -0
  118. package/templates/workspaceRoot/CLAUDE.md.template +19 -0
  119. package/templates/workspaceRoot/biome.json.template +2 -1
  120. package/templates/workspaceRoot/docs/AI-DEVELOPMENT.md.template +10 -14
  121. package/templates/workspaceRoot/docs/GENERATED.md.template +12 -10
  122. package/templates/workspaceRoot/package.json.template +2 -4
  123. package/typeChecker-3xgrzc2v.js +7 -0
  124. package/typecheck.proc.js +4 -5
  125. package/{workflow.command-2ygfqt4f.js → workflow.command-kphbr7eh.js} +22 -25
  126. package/{workspace.command-vbgpjkf9.js → workspace.command-j1gatz3d.js} +96 -81
  127. package/capacitorApp-9xswcgx7.js +0 -61
  128. package/dependencyScanner-f6grrep3.js +0 -9
  129. package/getDirname-m9s0cmhq.js +0 -8
  130. package/index-mxvakhsm.js +0 -66
  131. package/index-r24hmh0q.js +0 -4
  132. package/recipeScanner-tghkzrrt.js +0 -12
  133. package/typeChecker-kravn7ns.js +0 -8
  134. /package/{index-0wae5ebk.js → index-meh558jy.js} +0 -0
  135. /package/{index-ss469dec.js → index-nz8prx9g.js} +0 -0
@@ -1,11 +1,11 @@
1
1
  // @bun
2
+ import {
3
+ CommandExecutionError
4
+ } from "./index-qsq3q8fy.js";
2
5
  import {
3
6
  resolveMobilePath,
4
7
  targetHtmlFilename
5
- } from "./index-76rn3g2c.js";
6
- import {
7
- CommandExecutionError
8
- } from "./index-z8ptfkzv.js";
8
+ } from "./index-47pj3aee.js";
9
9
 
10
10
  // pkgs/@akanjs/devkit/capacitorApp.ts
11
11
  import { cp, mkdir, readFile, rm, writeFile } from "fs/promises";
@@ -17,22 +17,22 @@ import { capitalize } from "akanjs/common";
17
17
 
18
18
  // pkgs/@akanjs/devkit/fileEditor.ts
19
19
  class FileEditor {
20
- filePath;
21
- content;
20
+ #filePath;
21
+ #content;
22
22
  constructor(filePath, content) {
23
- this.filePath = filePath;
24
- this.content = content;
23
+ this.#filePath = filePath;
24
+ this.#content = content;
25
25
  }
26
26
  static async create(filePath) {
27
27
  try {
28
28
  const content = await Bun.file(filePath).text();
29
29
  return new FileEditor(filePath, content);
30
- } catch (error) {
30
+ } catch (_error) {
31
31
  throw new Error(`Failed to read file: ${filePath}`);
32
32
  }
33
33
  }
34
34
  find(pattern) {
35
- const lines = this.content.split(`
35
+ const lines = this.#content.split(`
36
36
  `);
37
37
  const regex = typeof pattern === "string" ? new RegExp(pattern) : pattern;
38
38
  for (let i = 0;i < lines.length; i++) {
@@ -45,7 +45,7 @@ class FileEditor {
45
45
  return -1;
46
46
  }
47
47
  findAll(pattern) {
48
- const lines = this.content.split(`
48
+ const lines = this.#content.split(`
49
49
  `);
50
50
  const regex = typeof pattern === "string" ? new RegExp(pattern) : pattern;
51
51
  const matches = [];
@@ -63,10 +63,10 @@ class FileEditor {
63
63
  if (lineIndex === -1) {
64
64
  throw new Error(`Pattern not found: ${pattern}`);
65
65
  }
66
- const lines = this.content.split(`
66
+ const lines = this.#content.split(`
67
67
  `);
68
68
  lines.splice(lineIndex + 1, 0, data);
69
- this.content = lines.join(`
69
+ this.#content = lines.join(`
70
70
  `);
71
71
  return this;
72
72
  }
@@ -75,40 +75,40 @@ class FileEditor {
75
75
  if (lineIndex === -1) {
76
76
  throw new Error(`Pattern not found: ${pattern}`);
77
77
  }
78
- const lines = this.content.split(`
78
+ const lines = this.#content.split(`
79
79
  `);
80
80
  lines.splice(lineIndex, 0, data);
81
- this.content = lines.join(`
81
+ this.#content = lines.join(`
82
82
  `);
83
83
  return this;
84
84
  }
85
85
  replace(pattern, replacement) {
86
86
  const regex = typeof pattern === "string" ? new RegExp(pattern, "g") : pattern;
87
- this.content = this.content.replace(regex, replacement);
87
+ this.#content = this.#content.replace(regex, replacement);
88
88
  return this;
89
89
  }
90
90
  append(data) {
91
- this.content += `
91
+ this.#content += `
92
92
  ${data}`;
93
93
  return this;
94
94
  }
95
95
  prepend(data) {
96
- this.content = `${data}
97
- ${this.content}`;
96
+ this.#content = `${data}
97
+ ${this.#content}`;
98
98
  return this;
99
99
  }
100
100
  async save() {
101
101
  try {
102
- await Bun.write(this.filePath, this.content);
103
- } catch (error) {
104
- throw new Error(`Failed to save file: ${this.filePath}`);
102
+ await Bun.write(this.#filePath, this.#content);
103
+ } catch (_error) {
104
+ throw new Error(`Failed to save file: ${this.#filePath}`);
105
105
  }
106
106
  }
107
107
  getContent() {
108
- return this.content;
108
+ return this.#content;
109
109
  }
110
110
  setContent(content) {
111
- this.content = content;
111
+ this.#content = content;
112
112
  return this;
113
113
  }
114
114
  }
@@ -474,7 +474,7 @@ var PLACEHOLDER_APP_IDS = [
474
474
  "com.example.myapp"
475
475
  ];
476
476
  var placeholderAppIdSegment = /^(example|examples|myorg|myapp|mycompany|myorganization|changeme|todo|sample|test)$/;
477
- var isPlaceholderAppId = (appId) => {
477
+ var isPlaceholderAppId2 = (appId) => {
478
478
  const normalized = appId?.trim().toLowerCase() ?? "";
479
479
  if (!normalized)
480
480
  return true;
@@ -641,7 +641,7 @@ function materializeCapacitorConfig(target, { operation, localServerUrl, localIp
641
641
  return config;
642
642
  }
643
643
 
644
- class CapacitorApp {
644
+ class CapacitorApp2 {
645
645
  app;
646
646
  target;
647
647
  project;
@@ -1513,4 +1513,4 @@ ${filter}$1`);
1513
1513
  }
1514
1514
  }
1515
1515
 
1516
- export { SWIFTUICORE_MIN_IOS_MAJOR, rootCapacitorConfigFilenames, rootCapacitorConfigPaths, clearRootCapacitorConfigs, writeRootCapacitorConfig, selectLocalDevHost, parseIosRuntimeMajor, sortIosRunTargets, parseDevicectlDevices, parseSimctlDevices, buildIosNativeRunCommand, classifyIosRunFailure, formatIosRunFailureMessage, sanitizeIosNativeRunEnv, PLACEHOLDER_APP_IDS, isPlaceholderAppId, getMissingAndroidReleaseSigningKeys, formatAndroidReleaseSigningError, getAdbDeviceStateIssues, getAndroidLocalServerHost, ANDROID_MIN_SDK_VERSION, raiseGradleMinSdkVersion, assertJsonSerializable, materializeCapacitorConfig, CapacitorApp };
1516
+ export { isPlaceholderAppId2, CapacitorApp2 };
@@ -1,28 +1,29 @@
1
1
  // @bun
2
- import {
3
- AkanContextAnalyzer
4
- } from "./index-774gcx29.js";
5
- import {
6
- Prompter
7
- } from "./index-j37qq1f2.js";
8
2
  import {
9
3
  runner,
10
4
  script
11
- } from "./index-kdh76j26.js";
5
+ } from "./index-znynzt5w.js";
12
6
  import {
13
- AGENT_BLOCK_END,
14
7
  AGENT_BLOCK_START,
15
- AppExecutor,
16
- LibExecutor,
8
+ AGENT_BLOCK_END,
9
+ stampBlockVersion,
17
10
  readDevkitVersion,
11
+ upsertAgentBlock,
18
12
  renderRecipeEntries,
19
- stampBlockVersion,
20
- upsertAgentBlock
21
- } from "./index-z8ptfkzv.js";
13
+ CLAUDE_COMMENT_RULE,
14
+ AppExecutor,
15
+ LibExecutor
16
+ } from "./index-qsq3q8fy.js";
22
17
  import {
23
- collectRecipeSources,
24
- scanRecipes
25
- } from "./index-xys926f2.js";
18
+ collectRecipeSources2,
19
+ scanRecipes2
20
+ } from "./index-by5gpp8x.js";
21
+ import {
22
+ AkanContextAnalyzer
23
+ } from "./index-gtmz74tj.js";
24
+ import {
25
+ Prompter
26
+ } from "./index-h7yw2z9n.js";
26
27
 
27
28
  // pkgs/@akanjs/cli/agent/agent.script.ts
28
29
  import { Logger as Logger2 } from "akanjs/common";
@@ -76,8 +77,8 @@ Keep a sample only while you are still learning its pattern; delete it once your
76
77
  `;
77
78
  };
78
79
  var renderRecipeIndex = async (workspace) => {
79
- const sources = await collectRecipeSources(`${workspace.workspaceRoot}/pkgs/akanjs/ui`, "akanjs/ui", "recipe");
80
- const recipes = scanRecipes(sources);
80
+ const sources = await collectRecipeSources2(`${workspace.workspaceRoot}/pkgs/akanjs/ui`, "akanjs/ui", "recipe");
81
+ const recipes = scanRecipes2(sources);
81
82
  const scopeIndexPointer = `App and lib recipes are **not** listed here. Each app/lib carries its own generated index \u2014
82
83
  \`apps/<app>/AGENTS.md\` / \`libs/<lib>/AGENTS.md\` (\`## Recipes In Scope\`) \u2014 regenerated by \`akan sync\` and
83
84
  verified by \`akan lint\`. When working inside an app or lib, consult that file before consuming or authoring a look.`;
@@ -89,15 +90,14 @@ ${scopeIndexPointer}
89
90
  `;
90
91
  return `## Recipes
91
92
 
92
- Framework UI recipes (Tailwind-variant look factories), importable from every app and lib. Consume by exact name \u2014
93
- \`import { <name> } from "akanjs/ui"\`, then \`<name>(variants?, className?)\`. The second arg merges internally and
94
- takes **an array too**, so never wrap it in \`cn()\`: \`<name>({}, ["h-full", isWide && "w-full", className])\`.
95
- Do not guess recipe names, import paths, or variant values; the list below carries
96
- the full contract (\`*\` marks the default, \`key?\` is a boolean flag), so there is no need to open the recipe file to
97
- consume one. tsc still reports variant mistakes. **Before inlining a repeated surface (card, box,
98
- tile, \u2026): reuse a recipe, or add one as \`apps/<app>/ui/Recipe/<name>.ts\` (one recipe per file, re-exported from
99
- that folder's \`index.ts\`) \u2014 never re-implement the same look inline in several places, and never author a
100
- near-duplicate.** Full authoring/consumption policy: the \`recipeRule\` guideline.
93
+ Framework UI recipes (Tailwind-variant look factories), importable from every app and lib: \`import { <name> } from
94
+ "akanjs/ui"\`, then \`<name>(variants?, className?)\`. The second arg merges internally and takes **an array too**, so
95
+ never wrap it in \`cn()\`: \`<name>({}, ["h-full", isWide && "w-full", className])\`. The list below is the full
96
+ contract (\`*\` marks the default, \`key?\` is a boolean flag) \u2014 do not guess a name, path, or variant value, and do
97
+ not open the recipe file to consume one. **Before inlining a repeated surface (card, box, tile, \u2026): reuse a recipe,
98
+ or add one as \`apps/<app>/ui/Recipe/<name>.ts\`, one per file, re-exported from that folder's \`index.ts\` \u2014 never
99
+ re-implement the same look inline in several places, and never author a near-duplicate.** Full policy: the
100
+ \`recipeRule\` guideline.
101
101
 
102
102
  ${renderRecipeEntries(recipes)}
103
103
 
@@ -147,15 +147,12 @@ If generated output is stale or broken, update the owning source file and run \`
147
147
 
148
148
  ${recipeIndex}## MCP Workflow Policy
149
149
 
150
- - Prefer Akan MCP workflows before direct source edits.
151
- - Direct source edits are denied when an allowlisted Akan workflow or repair tool can perform the change.
152
- - Use \`akan mcp --mode plan\` to inspect \`list_workflows\`, \`explain_workflow\`, and \`plan_workflow\`.
153
- - If \`plan_workflow\` returns \`planPath\` or \`next.tool=apply_workflow\`, call \`apply_workflow({ planPath })\` before editing source files directly.
154
- - Use \`akan mcp --mode apply\` only for allowlisted \`apply_workflow\`, \`run_validation\`, and repair tools.
155
- - After \`apply_workflow\`, run \`run_validation\` with \`validationTarget\` when present; otherwise use \`applyReportPath\`.
156
- - If no workflow exists, or apply reports unsupported/no-op/failed diagnostics that require manual action, keep edits scoped to owning source files and never patch generated files directly.
157
- - For compound requests, split the request into workflows and apply each \`planPath\` in order, such as \`create-module\` followed by \`add-field\`.
158
- - **CLI-only fallback (MCP not connected):** \`akan mcp\` starts a stdio MCP server, so the \`list_workflows\`/\`plan_workflow\`/\`apply_workflow\` tools exist only when your agent is wired to it as an MCP client. When they are unavailable, the CLI is a first-class equivalent: \`akan workflow list\` / \`explain <name>\` / \`plan <name> ... --format json --out <planPath>\` / \`apply <planPath> --format json\`, \`akan doctor --strict --format json\` for validation, and \`akan repair generated|imports|module-shape --app <app> --format json\` for repairs. Scaffolding primitives (\`create-module\`/\`create-scalar\`/\`create-service\` take the target app/lib as a POSITIONAL arg; \`add-field\`/\`add-enum-field\` use \`--app\`/\`--module\` flags) call the same code the workflows do.
150
+ - **Prefer an Akan workflow to a direct source edit.** A direct edit is denied when an allowlisted workflow or repair tool can make the change.
151
+ - Inspect with \`akan mcp --mode plan\` (\`list_workflows\`, \`explain_workflow\`, \`plan_workflow\`); apply with \`akan mcp --mode apply\`, which allowlists \`apply_workflow\`, \`run_validation\`, and the repair tools.
152
+ - If \`plan_workflow\` returns \`planPath\` or \`next.tool=apply_workflow\`, call \`apply_workflow({ planPath })\` before editing source. Then run \`run_validation\` with \`validationTarget\` when present, otherwise \`applyReportPath\`.
153
+ - Split a compound request into workflows and apply each \`planPath\` in order, such as \`create-module\` followed by \`add-field\`.
154
+ - When no workflow exists, or apply reports unsupported/no-op/failed diagnostics needing manual action, keep edits scoped to owning source files and never patch generated files directly.
155
+ - **MCP not connected?** The CLI is a first-class equivalent \u2014 \`akan workflow list\` / \`explain\` / \`plan\` / \`apply\`, \`akan doctor\`, \`akan repair\`. See the onboarding guide's CLI-only fallback for the exact flags.
159
156
 
160
157
  ## Validation
161
158
 
@@ -199,6 +196,8 @@ var renderClaudeMd = async (workspace) => {
199
196
  return `# ${context.repoName} \u2014 Claude Code Guide
200
197
 
201
198
  @AGENTS.md
199
+
200
+ ${CLAUDE_COMMENT_RULE}
202
201
  `;
203
202
  };
204
203
  var renderCursorRule = () => `---
@@ -246,7 +245,7 @@ class AgentRunner extends runner("agent") {
246
245
  written.push(`${exec.type}s/${exec.name}/AGENTS.md`);
247
246
  } catch (error) {
248
247
  const message = error instanceof Error ? error.message : String(error);
249
- Logger.rawLog(`Skipped ${exec.type}s/${exec.name}/AGENTS.md (${message})`, undefined, "warn");
248
+ Logger.rawLog(`Skipped ${exec.type}s/${exec.name}/AGENTS.md (${message})`, undefined, "error");
250
249
  }
251
250
  };
252
251
  for (const name of libNames)
@@ -0,0 +1,76 @@
1
+ // @bun
2
+ // pkgs/@akanjs/devkit/libSource.ts
3
+ class LibSource {
4
+ static manifestKey = "akan";
5
+ static unhashedDirs = ["env"];
6
+ #lib;
7
+ constructor(lib) {
8
+ this.#lib = lib;
9
+ }
10
+ get #prefix() {
11
+ return `libs/${this.#lib.name}/`;
12
+ }
13
+ #isHashed(file) {
14
+ const relative = file.slice(this.#prefix.length);
15
+ return !LibSource.unhashedDirs.includes(relative.split("/")[0] ?? "");
16
+ }
17
+ async#hashableContent(file) {
18
+ const content = await this.#lib.workspace.readFile(file);
19
+ if (file !== `${this.#prefix}package.json`)
20
+ return content;
21
+ const manifest = JSON.parse(content);
22
+ delete manifest[LibSource.manifestKey];
23
+ return JSON.stringify(manifest);
24
+ }
25
+ async computeHash() {
26
+ const files = (await this.#lib.workspace.listGitFiles([`libs/${this.#lib.name}`], { untracked: true })).filter((file) => this.#isHashed(file));
27
+ const hasher = new Bun.CryptoHasher("sha256");
28
+ for (const file of files) {
29
+ hasher.update(file);
30
+ hasher.update("\x00");
31
+ hasher.update(await this.#hashableContent(file));
32
+ hasher.update("\x00");
33
+ }
34
+ return hasher.digest("hex").slice(0, 32);
35
+ }
36
+ async read() {
37
+ const manifest = await this.#lib.getPackageJson();
38
+ const akan = manifest[LibSource.manifestKey];
39
+ return akan?.source ?? null;
40
+ }
41
+ async write({ origin, sha }) {
42
+ const [manifest, hash] = await Promise.all([this.#lib.getPackageJson(), this.computeHash()]);
43
+ const akan = manifest[LibSource.manifestKey] ?? {};
44
+ const stamp = { origin, sha, hash, syncedAt: new Date().toISOString() };
45
+ await this.#lib.setPackageJson({ ...manifest, [LibSource.manifestKey]: { ...akan, source: stamp } });
46
+ return stamp;
47
+ }
48
+ async syncStamp({ origin, sha }) {
49
+ const [current, hash] = await Promise.all([this.read(), this.computeHash()]);
50
+ if (current?.origin === origin && current.sha === sha && current.hash === hash)
51
+ return { stamp: current, changed: false };
52
+ return { stamp: await this.write({ origin, sha }), changed: true };
53
+ }
54
+ async status() {
55
+ const [stamp, hash] = await Promise.all([this.read(), this.computeHash()]);
56
+ const drift = !stamp ? "unstamped" : stamp.hash === hash ? "clean" : "drifted";
57
+ return { lib: this.#lib.name, drift, stamp, hash };
58
+ }
59
+ }
60
+ function formatLibStatuses(statuses) {
61
+ const marks = { clean: "clean ", drifted: "DRIFTED ", unstamped: "unstamped" };
62
+ const sections = [
63
+ "Akan Library Source Status",
64
+ "",
65
+ ...statuses.map((status) => {
66
+ const origin = status.stamp ? `${status.stamp.origin}@${status.stamp.sha}` : "no akan.source in package.json";
67
+ return ` ${marks[status.drift]} libs/${status.lib} ${origin}`;
68
+ }),
69
+ "",
70
+ `drifted: ${statuses.filter((status) => status.drift === "drifted").length} / ${statuses.length}`
71
+ ];
72
+ return sections.join(`
73
+ `);
74
+ }
75
+
76
+ export { LibSource, formatLibStatuses };
@@ -37,10 +37,10 @@ var resolveMobileTargets = async (app, selection) => {
37
37
  if (!selection && targets.length === 1)
38
38
  return targets;
39
39
  if (!selection) {
40
- const choices2 = await getMobileTargetChoices(app);
41
- if (choices2.length === 1)
42
- return resolveMobileTargets(app, choices2[0]);
43
- throw new Error(`Multiple mobile targets found for ${app.name}. Pass --target <${choices2.join("|")}|all>.`);
40
+ const choices = await getMobileTargetChoices(app);
41
+ if (choices.length === 1)
42
+ return resolveMobileTargets(app, choices[0]);
43
+ throw new Error(`Multiple mobile targets found for ${app.name}. Pass --target <${choices.join("|")}|all>.`);
44
44
  }
45
45
  if (selection === "all") {
46
46
  if (Object.keys(config.mobile.targets).length > 1)
@@ -0,0 +1,159 @@
1
+ // @bun
2
+ import {
3
+ AppInfo
4
+ } from "./index-qsq3q8fy.js";
5
+
6
+ // pkgs/@akanjs/devkit/slicePlanner.ts
7
+ class SlicePlanner {
8
+ static memberDirs = ["apps", "libs", "pkgs"];
9
+ static toolchainDependencies = [
10
+ "@akanjs/cli",
11
+ "@akanjs/devkit",
12
+ "@biomejs/biome",
13
+ "@types/bun",
14
+ "akanjs",
15
+ "tailwindcss",
16
+ "typescript"
17
+ ];
18
+ static akanPackages = ["akanjs", "@akanjs/devkit", "@akanjs/cli"];
19
+ static async#frameworkPeers(workspace) {
20
+ const peers = new Set;
21
+ let found = false;
22
+ for (const akanPackage of SlicePlanner.akanPackages) {
23
+ for (const prefix of ["node_modules", "pkgs"]) {
24
+ const manifestPath = `${prefix}/${akanPackage}/package.json`;
25
+ if (!await workspace.exists(manifestPath))
26
+ continue;
27
+ const manifest = await workspace.readJson(manifestPath);
28
+ for (const peer of Object.keys(manifest.peerDependencies ?? {}))
29
+ peers.add(peer);
30
+ found = true;
31
+ break;
32
+ }
33
+ }
34
+ return found ? peers : null;
35
+ }
36
+ static typesPackageOf(dependency) {
37
+ return dependency.startsWith("@") ? `@types/${dependency.slice(1).replace("/", "__")}` : `@types/${dependency}`;
38
+ }
39
+ static async pruneDependencies(workspace, rootPackageJson, required) {
40
+ const peers = await SlicePlanner.#frameworkPeers(workspace);
41
+ const { workspaces: _workspaces, ...rest } = rootPackageJson;
42
+ if (!peers)
43
+ return {
44
+ packageJson: rest,
45
+ pruned: [],
46
+ warnings: [`dependencies carried whole \u2014 none of ${SlicePlanner.akanPackages.join(", ")} is installed`]
47
+ };
48
+ const keep = new Set([...SlicePlanner.toolchainDependencies, ...peers, ...required]);
49
+ for (const dependency of [...keep])
50
+ keep.add(SlicePlanner.typesPackageOf(dependency));
51
+ const pick = (entries) => Object.fromEntries(Object.entries(entries ?? {}).filter(([name]) => keep.has(name)));
52
+ const patched = rootPackageJson.patchedDependencies ?? {};
53
+ const packageJson = {
54
+ ...rest,
55
+ dependencies: pick(rootPackageJson.dependencies),
56
+ devDependencies: pick(rootPackageJson.devDependencies),
57
+ ...Object.keys(patched).length ? {
58
+ patchedDependencies: Object.fromEntries(Object.entries(patched).filter(([spec]) => keep.has(spec.slice(0, spec.lastIndexOf("@")))))
59
+ } : {}
60
+ };
61
+ const pruned = Object.keys({ ...rootPackageJson.dependencies, ...rootPackageJson.devDependencies }).filter((name) => !keep.has(name)).sort();
62
+ return { packageJson, pruned, warnings: [] };
63
+ }
64
+ #app;
65
+ constructor(app) {
66
+ this.#app = app;
67
+ }
68
+ async#trackedFiles(paths) {
69
+ return await this.#app.workspace.listGitFiles(paths);
70
+ }
71
+ async#untrackedFiles(paths) {
72
+ const [tracked, all] = await Promise.all([
73
+ this.#app.workspace.listGitFiles(paths),
74
+ this.#app.workspace.listGitFiles(paths, { untracked: true })
75
+ ]);
76
+ const trackedSet = new Set(tracked);
77
+ return all.filter((file) => !trackedSet.has(file));
78
+ }
79
+ #isMemberFile(file) {
80
+ return SlicePlanner.memberDirs.includes(file.split("/")[0] ?? "");
81
+ }
82
+ static #requiredDependencies(appInfo) {
83
+ const scanResults = [
84
+ appInfo.getScanResult(),
85
+ ...[...appInfo.getLibInfos().values()].map((lib) => lib.getScanResult())
86
+ ];
87
+ return new Set([
88
+ ...scanResults.flatMap((scanResult) => [
89
+ ...scanResult.dependencies,
90
+ ...scanResult.devDependencies,
91
+ ...scanResult.pkgDeps
92
+ ])
93
+ ]);
94
+ }
95
+ async#patchWarnings(packageJson) {
96
+ const patchedDependencies = packageJson.patchedDependencies ?? {};
97
+ const missing = (await Promise.all(Object.entries(patchedDependencies).map(async ([spec, patchPath]) => await this.#app.workspace.exists(patchPath) ? null : `${spec} -> ${patchPath}`))).filter((entry) => !!entry);
98
+ return missing.length ? [`patchedDependencies references a missing patch file: ${missing.join(", ")}`] : [];
99
+ }
100
+ async plan() {
101
+ const appInfo = await AppInfo.fromExecutor(this.#app);
102
+ const libs = appInfo.getLibs();
103
+ const slicePaths = [`apps/${this.#app.name}`, ...libs.map((lib) => `libs/${lib}`)];
104
+ const [appFiles, allTracked, untracked, rootPackageJson] = await Promise.all([
105
+ this.#trackedFiles([`apps/${this.#app.name}`]),
106
+ this.#trackedFiles(["."]),
107
+ this.#untrackedFiles(slicePaths),
108
+ this.#app.workspace.getPackageJson()
109
+ ]);
110
+ const libFiles = Object.fromEntries(await Promise.all(libs.map(async (lib) => [lib, await this.#trackedFiles([`libs/${lib}`])])));
111
+ const rootFiles = allTracked.filter((file) => !this.#isMemberFile(file));
112
+ const required = SlicePlanner.#requiredDependencies(appInfo);
113
+ const {
114
+ packageJson,
115
+ pruned,
116
+ warnings: manifestWarnings
117
+ } = await SlicePlanner.pruneDependencies(this.#app.workspace, rootPackageJson, required);
118
+ const warnings = [
119
+ ...untracked.length ? [`${untracked.length} untracked file(s) under the slice paths: ${untracked.join(", ")}`] : [],
120
+ ...rootPackageJson.workspaces ? ["root `workspaces` dropped \u2014 a slice consumes akanjs from the registry"] : [],
121
+ ...manifestWarnings,
122
+ ...await this.#patchWarnings(rootPackageJson)
123
+ ];
124
+ return {
125
+ app: this.#app.name,
126
+ libs,
127
+ appFiles,
128
+ libFiles,
129
+ rootFiles,
130
+ packageJson,
131
+ requiredDependencies: [...required].sort(),
132
+ unusedDependencies: pruned,
133
+ warnings
134
+ };
135
+ }
136
+ }
137
+ var rootEntriesOf = (rootFiles) => [...new Set(rootFiles.map((file) => file.split("/")[0] ?? file))].sort();
138
+ function formatSlicePlan(plan) {
139
+ const libCounts = Object.entries(plan.libFiles).map(([lib, files]) => ` - libs/${lib}: ${files.length} files`);
140
+ const sections = [
141
+ "Akan Slice Plan",
142
+ `app: ${plan.app} (apps/${plan.app}: ${plan.appFiles.length} files)`,
143
+ `libs: ${plan.libs.length ? plan.libs.join(", ") : "(none)"}`,
144
+ ...libCounts,
145
+ `workspace shell: ${plan.rootFiles.length} files across ${rootEntriesOf(plan.rootFiles).join(", ")}`,
146
+ "",
147
+ `Root dependencies this slice does not use (${plan.unusedDependencies.length}) \u2014 pruned:`,
148
+ "",
149
+ ...plan.unusedDependencies.length ? plan.unusedDependencies.map((dep) => ` - ${dep}`) : [" (none)"],
150
+ "",
151
+ `Warnings (${plan.warnings.length}):`,
152
+ "",
153
+ ...plan.warnings.length ? plan.warnings.map((warning) => ` - ${warning}`) : [" (none)"]
154
+ ];
155
+ return sections.join(`
156
+ `);
157
+ }
158
+
159
+ export { SlicePlanner, formatSlicePlan };
@@ -2,6 +2,6 @@
2
2
  // pkgs/@akanjs/devkit/getDirname.ts
3
3
  import path from "path";
4
4
  import { fileURLToPath } from "url";
5
- var getDirname = (url) => path.dirname(fileURLToPath(url));
5
+ var getDirname2 = (url) => path.dirname(fileURLToPath(url));
6
6
 
7
- export { getDirname };
7
+ export { getDirname2 };
@@ -2,16 +2,16 @@
2
2
  import {
3
3
  runner,
4
4
  script
5
- } from "./index-kdh76j26.js";
5
+ } from "./index-znynzt5w.js";
6
6
  import {
7
- PkgExecutor
8
- } from "./index-z8ptfkzv.js";
7
+ FileSys
8
+ } from "./index-q0y2jq9j.js";
9
9
  import {
10
- TypeScriptDependencyScanner
11
- } from "./index-46tjzh6s.js";
10
+ PkgExecutor
11
+ } from "./index-qsq3q8fy.js";
12
12
  import {
13
- FileSys
14
- } from "./index-67546d0j.js";
13
+ TypeScriptDependencyScanner2
14
+ } from "./index-kcxmv48c.js";
15
15
 
16
16
  // pkgs/@akanjs/cli/package/package.runner.ts
17
17
  import path2 from "path";
@@ -140,7 +140,7 @@ class PackageRunner extends runner("package") {
140
140
  await workspace.setPkgTsPaths(pkgName);
141
141
  }
142
142
  async removePackage(pkg) {
143
- await pkg.workspace.exec(`rm -rf pkgs/${pkg.name}`);
143
+ await pkg.workspace.removeDir(`pkgs/${pkg.name}`);
144
144
  await pkg.workspace.unsetPkgTsPaths(pkg.name);
145
145
  }
146
146
  async scanSync(pkg) {
@@ -150,7 +150,7 @@ class PackageRunner extends runner("package") {
150
150
  async buildPackage(pkg) {
151
151
  await $`rm -rf ${pkg.dist.cwdPath}`;
152
152
  await pkg.dist.mkdir(pkg.dist.cwdPath);
153
- const scanner = await TypeScriptDependencyScanner.from(pkg);
153
+ const scanner = await TypeScriptDependencyScanner2.from(pkg);
154
154
  const { npmDeps, npmDevDeps, missingDeps } = await scanner.getPackageBuildDependencies(pkg.name);
155
155
  const packageRuntimeDependencies = {
156
156
  "@akanjs/devkit": ["tailwind-scrollbar"]
@@ -163,13 +163,17 @@ class PackageRunner extends runner("package") {
163
163
  "tailwind-scrollbar"
164
164
  ].filter((dep) => dep !== "akanjs" && dep !== "@akanjs/devkit");
165
165
  }
166
- const bundledRuntimeDeps = new Set(pkg.name === "@akanjs/cli" ? ["@akanjs/devkit"] : []);
166
+ const packageBundledRuntimeDependencies = {
167
+ "@akanjs/cli": ["@akanjs/devkit"],
168
+ akanjs: ["use-agentic"]
169
+ };
170
+ const bundledRuntimeDeps = new Set(packageBundledRuntimeDependencies[pkg.name] ?? []);
167
171
  const forcedRuntimeDeps = packageRuntimeDependencies[pkg.name] ?? [];
168
172
  const forcedRuntimeDevDeps = packageRuntimeDevDependencies[pkg.name] ?? [];
169
173
  const [rootPackageJson, pkgJson] = await Promise.all([pkg.workspace.getPackageJson(), pkg.getPackageJson()]);
170
174
  const optionalPeerDeps = new Set(Object.entries(pkgJson.peerDependenciesMeta ?? {}).filter(([, meta]) => meta.optional).map(([dep]) => dep));
171
175
  const packageRuntimeDeps = [...new Set([...npmDeps, ...forcedRuntimeDeps])].filter((dep) => !optionalPeerDeps.has(dep) && !bundledRuntimeDeps.has(dep));
172
- const packageRuntimeDevDeps = [...new Set([...npmDevDeps, ...forcedRuntimeDevDeps])].filter((dep) => !optionalPeerDeps.has(dep));
176
+ const packageRuntimeDevDeps = [...new Set([...npmDevDeps, ...forcedRuntimeDevDeps])].filter((dep) => !optionalPeerDeps.has(dep) && !bundledRuntimeDeps.has(dep));
173
177
  const rootDeps = { ...rootPackageJson.dependencies, ...rootPackageJson.devDependencies };
174
178
  const missingForcedDeps = forcedRuntimeDeps.filter((dep) => !rootDeps[dep]);
175
179
  const missingForcedDevDeps = forcedRuntimeDevDeps.filter((dep) => !rootDeps[dep]);
@@ -268,7 +272,7 @@ class PackageRunner extends runner("package") {
268
272
  }
269
273
  if (!pkgJson.version)
270
274
  throw new Error(`[package] dist package version is missing for ${pkg.name}`);
271
- if (!pkgJson.publishConfig || pkgJson.publishConfig.access !== "public") {
275
+ if (pkgJson.publishConfig?.access !== "public") {
272
276
  throw new Error(`[package] ${pkg.name} must publish with publishConfig.access=public`);
273
277
  }
274
278
  if (!await Bun.file(`${pkg.dist.cwdPath}/README.md`).exists()) {
@@ -1,22 +1,22 @@
1
1
  // @bun
2
2
  import {
3
- pluralizeName
4
- } from "./index-ss469dec.js";
5
- import {
6
- AiSession
7
- } from "./index-0cj2zxbm.js";
3
+ runner,
4
+ script
5
+ } from "./index-znynzt5w.js";
8
6
  import {
9
- createPassedPrimitiveReport,
10
7
  generatedFilesForSync,
8
+ createPassedPrimitiveReport,
11
9
  scalarChangedFiles
12
- } from "./index-rxkpk7n4.js";
10
+ } from "./index-fc1bh0a7.js";
11
+ import {
12
+ AiSession
13
+ } from "./index-c69j78kk.js";
13
14
  import {
14
15
  Prompter
15
- } from "./index-j37qq1f2.js";
16
+ } from "./index-h7yw2z9n.js";
16
17
  import {
17
- runner,
18
- script
19
- } from "./index-kdh76j26.js";
18
+ pluralizeName
19
+ } from "./index-nz8prx9g.js";
20
20
 
21
21
  // pkgs/@akanjs/cli/scalar/scalar.prompt.ts
22
22
  import { input } from "@inquirer/prompts";
@@ -192,9 +192,9 @@ class ScalarRunner extends runner("scalar") {
192
192
  const { request, validate } = await prompt.requestUpdateDictonaryWithInstruction();
193
193
  await session.writeTypescripts(request, sys, { validate });
194
194
  for (const scalarName of followingScalarNames) {
195
- const prompt2 = new ScalarPrompt(sys, scalarName);
196
- const { request: request2, validate: validate2 } = await prompt2.requestUpdateDictonaryWithFollowing();
197
- await session.writeTypescripts(request2, sys, { validate: validate2 });
195
+ const prompt = new ScalarPrompt(sys, scalarName);
196
+ const { request, validate } = await prompt.requestUpdateDictonaryWithFollowing();
197
+ await session.writeTypescripts(request, sys, { validate });
198
198
  }
199
199
  }
200
200
  }