@akanjs/cli 3.0.0-beta.9 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/.build-stamp +1 -1
  2. package/CodeAgent-2vmp9qe0.js +9 -0
  3. package/CodeAgentRpcHost-p7h6n2hp.js +7 -0
  4. package/CodeAgentRpcListener-7p7z5dd7.js +97 -0
  5. package/CodeTui-5ed6bg2a.js +1457 -0
  6. package/README.ko.md +83 -28
  7. package/README.md +70 -27
  8. package/TunnelShare-cwh9ezsm.js +9 -0
  9. package/{agent.command-0q17pnrs.js → agent.command-gn73rhe7.js} +8 -9
  10. package/akanCode.js +102 -0
  11. package/application.command-e968t0hw.js +246 -0
  12. package/{applicationBuildRunner-kxwbssgn.js → applicationBuildRunner-64taxseg.js} +121 -77
  13. package/buildBatch.proc.js +120 -32
  14. package/cloud.command-0jm301rr.js +95 -0
  15. package/cloud.script-nemnzjpv.js +20 -0
  16. package/code.command-18kcm7hq.js +154 -0
  17. package/commandManifest.json +1 -1
  18. package/consoleToStderr-h5bryj94.js +7 -0
  19. package/context.command-trd9bn18.js +48 -0
  20. package/context.runner-y5hwh673.js +21 -0
  21. package/{dependencyScanner-shs82ynp.js → dependencyScanner-06z2dmrr.js} +2 -2
  22. package/{devTui-m1atgkc9.js → devTui-q7k7bakd.js} +122 -40
  23. package/fileSys-wzzrntkw.js +9 -0
  24. package/guideline.command-bdmdn2de.js +42 -0
  25. package/guidelines/agentRule/agentRule.instruction.md +154 -26
  26. package/guidelines/conventions/conventions.instruction.md +134 -48
  27. package/guidelines/mcpRule/mcpRule.instruction.md +7 -5
  28. package/guidelines/queryRule/queryRule.instruction.md +21 -7
  29. package/guidelines/runtimeRule/runtimeRule.instruction.md +291 -6
  30. package/guidelines/ssrRule/ssrRule.instruction.md +4 -2
  31. package/guidelines/transportRule/transportRule.instruction.md +10 -8
  32. package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +20 -0
  33. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +66 -3
  34. package/incrementalBuilder.proc.js +564 -109
  35. package/index-0wpybxtr.js +2729 -0
  36. package/{index-kcxmv48c.js → index-2ahj896a.js} +45 -79
  37. package/index-2wc41k5w.js +49 -0
  38. package/index-3hx1z96c.js +87 -0
  39. package/{index-2tv3fdx4.js → index-3w94e7n3.js} +1228 -1458
  40. package/{index-hwkygn9s.js → index-48k96p55.js} +325 -36
  41. package/index-4npz05nm.js +187 -0
  42. package/{index-q0y2jq9j.js → index-52w0fvh8.js} +21 -4
  43. package/index-6he6gvfg.js +4300 -0
  44. package/index-7md2g9vw.js +6 -0
  45. package/{index-04bk599g.js → index-93j60em0.js} +10 -17
  46. package/index-94s080qm.js +266 -0
  47. package/index-9dp031by.js +12 -0
  48. package/{index-ktb5njgy.js → index-9z771ptz.js} +49 -99
  49. package/{index-y6n8nmny.js → index-abxpehf8.js} +75 -203
  50. package/{index-3d9y066c.js → index-bjwxs904.js} +9 -8
  51. package/{index-9077wzd2.js → index-by9pxkr0.js} +43 -26
  52. package/index-c6eggbee.js +123 -0
  53. package/index-d2242ksy.js +99 -0
  54. package/index-drehwpdt.js +1119 -0
  55. package/{index-92zztqy1.js → index-dy0jx9ay.js} +2 -17
  56. package/{index-ffvk10zz.js → index-f3c78nd6.js} +107 -241
  57. package/index-gbggbqcp.js +1058 -0
  58. package/{index-by5gpp8x.js → index-hj6w4ka1.js} +2 -1
  59. package/index-hsmtysz4.js +53 -0
  60. package/{index-j9yhg404.js → index-jmrn54tt.js} +4 -7
  61. package/{index-a64esmtb.js → index-kcdj1z5v.js} +523 -1022
  62. package/{index-d43r08tf.js → index-kqabytj7.js} +77 -150
  63. package/{index-vyvre9en.js → index-mbxbhay5.js} +6 -2
  64. package/{index-vxtad5bd.js → index-mgxpx3f2.js} +5 -8
  65. package/index-p6pbz9n5.js +25 -0
  66. package/{index-sj5vxr8f.js → index-p993efkq.js} +981 -897
  67. package/{index-2xp0kfkt.js → index-pmhqttv3.js} +37 -25
  68. package/index-tqm7jjcn.js +700 -0
  69. package/{index-0g7r8xz3.js → index-vpj42xwt.js} +114 -232
  70. package/index-wa5jbxj1.js +760 -0
  71. package/{index-k2j1hc4r.js → index-wprnsjms.js} +12 -12
  72. package/{index-gyd220p2.js → index-y3mphr1m.js} +554 -577
  73. package/index-yg7jhz8x.js +69 -0
  74. package/{index-h7yw2z9n.js → index-zzvvc845.js} +8 -14
  75. package/index.js +23 -22
  76. package/{library.command-qzzbj6d8.js → library.command-9h749a1x.js} +4 -5
  77. package/{localRegistry.command-vyrgg4xw.js → localRegistry.command-2bqqhxyz.js} +23 -43
  78. package/{module.command-rq5hq3ax.js → module.command-nv8nzgft.js} +8 -12
  79. package/{package.command-d9hd6v9n.js → package.command-mq4bggp6.js} +6 -7
  80. package/package.json +15 -7
  81. package/{page.command-126d56te.js → page.command-j639n707.js} +4 -5
  82. package/{primitive.command-taxd1538.js → primitive.command-kz6849th.js} +9 -23
  83. package/prompter-76k56b37.js +8 -0
  84. package/{quality.command-6gsna0a3.js → quality.command-4hyabwkb.js} +205 -377
  85. package/{recipeScanner-fpagtgc1.js → recipeScanner-4b69ybe0.js} +1 -1
  86. package/{repair.command-tq2dgy72.js → repair.command-a9awpbqr.js} +11 -35
  87. package/{routeSourceValidator-apyqw7wk.js → routeSourceValidator-7ycnfz0e.js} +0 -6
  88. package/{scalar.command-3bcmrrkv.js → scalar.command-ma4fpm9m.js} +7 -11
  89. package/skills/akan-code/SKILL.md +130 -0
  90. package/skills/akan-debug/SKILL.md +42 -0
  91. package/skills/akan-deps/SKILL.md +50 -0
  92. package/skills/akan-err/SKILL.md +39 -0
  93. package/skills/akan-module/SKILL.md +45 -0
  94. package/skills/akan-scaffold/SKILL.md +76 -0
  95. package/skills/akan-scalar/SKILL.md +52 -0
  96. package/skills/akan-service/SKILL.md +34 -0
  97. package/skills/akan-store/SKILL.md +67 -0
  98. package/skills/akan-ui/SKILL.md +63 -0
  99. package/skills/akan-validate/SKILL.md +44 -0
  100. package/{subspace.command-eddzqpx3.js → subspace.command-3k2pmrs4.js} +53 -62
  101. package/templates/__scalar/__model__/__model__.abstract.md.template +8 -0
  102. package/templates/app/page/_index.tsx +257 -258
  103. package/templates/app/page/_layout.tsx +5 -1
  104. package/templates/app/page/_overrides.tsx +12 -0
  105. package/templates/app/page/styles.css.template +316 -14
  106. package/templates/app/public/apple-touch-icon.png +0 -0
  107. package/templates/app/public/favicon.ico +0 -0
  108. package/templates/app/public/jelly/cloud.webp +0 -0
  109. package/templates/app/public/jelly/comet.webp +0 -0
  110. package/templates/app/public/jelly/moon.webp +0 -0
  111. package/templates/app/public/jelly/planet.webp +0 -0
  112. package/templates/app/public/jelly/rocket.webp +0 -0
  113. package/templates/app/public/jelly/star.webp +0 -0
  114. package/templates/app/public/jelly/sugar.webp +0 -0
  115. package/templates/app/public/logo.png +0 -0
  116. package/templates/app/ui/Recipe/index.ts +9 -0
  117. package/templates/app/ui/Recipe/jellyButton.ts +63 -0
  118. package/templates/appSample/lib/__scalar/workHistory/workHistory.abstract.ts +8 -39
  119. package/templates/appSample/lib/_noti/noti.abstract.ts +6 -29
  120. package/templates/appSample/lib/task/Task.Unit.tsx +1 -1
  121. package/templates/appSample/lib/task/Task.Util.tsx +10 -13
  122. package/templates/appSample/lib/task/Task.View.tsx +2 -2
  123. package/templates/appSample/lib/task/Task.Zone.tsx +5 -2
  124. package/templates/appSample/lib/task/task.abstract.ts +12 -32
  125. package/templates/appSample/lib/task/task.signal.spec.ts +1 -15
  126. package/templates/appSample/lib/task/task.signal.test.ts +15 -1
  127. package/templates/appSample/lib/task/task.signal.ts +10 -8
  128. package/templates/appSample/page/task/[taskId]/_index.tsx +6 -6
  129. package/templates/appSample/page/task/[taskId]/edit.tsx +5 -4
  130. package/templates/appSample/page/task/_index.tsx +4 -3
  131. package/templates/appSample/page/task/_layout.tsx +1 -1
  132. package/templates/appSample/page/task/new.tsx +5 -4
  133. package/templates/appSample/srvkit/{AuthGuard.ts → guards.ts} +7 -4
  134. package/templates/appSample/srvkit/{SessionInternalArg.ts → internalArgs.ts} +6 -4
  135. package/templates/appSample/ui/GlobalLoading.tsx +2 -1
  136. package/templates/appSample/ui/QuantityControl.tsx +3 -3
  137. package/templates/client.ts +7 -30
  138. package/templates/crudPages/[__model__Id]/edit/page.tsx +2 -1
  139. package/templates/crudPages/[__model__Id]/page.tsx +2 -1
  140. package/templates/crudPages/new/page.tsx +2 -1
  141. package/templates/crudPages/page.tsx +2 -1
  142. package/templates/crudSinglePage/page.tsx +2 -1
  143. package/templates/lib/__lib/lib.dictionary.ts +0 -2
  144. package/templates/lib/__lib/lib.document.ts +0 -2
  145. package/templates/lib/sig.ts +8 -30
  146. package/templates/localDev/docker-compose.yaml.template +3 -14
  147. package/templates/module/__model__.signal.ts +12 -4
  148. package/templates/pkgRoot/tsconfig.json.template +2 -7
  149. package/templates/server.ts +1 -3
  150. package/templates/service/__model__.abstract.md.template +8 -0
  151. package/templates/workspaceRoot/.gitignore.template +0 -1
  152. package/templates/workspaceRoot/AGENTS.md.template +6 -0
  153. package/templates/workspaceRoot/package.json.template +1 -3
  154. package/tunnel.command-xwr46b66.js +129 -0
  155. package/{typeChecker-3xgrzc2v.js → typeChecker-px49mezc.js} +1 -1
  156. package/typecheck.proc.js +1 -1
  157. package/workflow.command-t7wqe4h7.js +79 -0
  158. package/{workspace.command-06wvstgr.js → workspace.command-4derhzrh.js} +79 -109
  159. package/abstractCompactor-gmkc0z8j.js +0 -102
  160. package/application.command-18y0s485.js +0 -204
  161. package/applicationReleasePackager-4yasxwv9.js +0 -244
  162. package/capacitorApp-36rbr858.js +0 -12
  163. package/cloud.command-av97ndh6.js +0 -94
  164. package/cloud.script-cm11xjdz.js +0 -20
  165. package/context.command-5v37ef3n.js +0 -81
  166. package/devTuiView-0hc2emhe.js +0 -9
  167. package/getDirname-dr3jz1xg.js +0 -7
  168. package/guideline.command-4pz9g1rt.js +0 -360
  169. package/guidelines/agentRule/agentRule.generate.json +0 -31
  170. package/guidelines/componentRule/componentRule.generate.json +0 -31
  171. package/guidelines/conventions/conventions.generate.json +0 -25
  172. package/guidelines/cssRule/cssRule.generate.json +0 -31
  173. package/guidelines/docPageRule/docPageRule.generate.json +0 -31
  174. package/guidelines/docPageRule/docPageRule.instruction.md +0 -25
  175. package/guidelines/docSyncRule/docSyncRule.generate.json +0 -31
  176. package/guidelines/docSyncRule/docSyncRule.instruction.md +0 -25
  177. package/guidelines/enumConstant/enumConstant.generate.json +0 -31
  178. package/guidelines/enumConstant/enumConstant.instruction.md +0 -28
  179. package/guidelines/fieldRule/fieldRule.generate.json +0 -31
  180. package/guidelines/framework/framework.generate.json +0 -32
  181. package/guidelines/mcpRule/mcpRule.generate.json +0 -35
  182. package/guidelines/modelConstant/modelConstant.generate.json +0 -32
  183. package/guidelines/modelDictionary/modelDictionary.generate.json +0 -32
  184. package/guidelines/modelDocument/modelDocument.generate.json +0 -31
  185. package/guidelines/modelService/modelService.generate.json +0 -31
  186. package/guidelines/modelSignal/modelSignal.generate.json +0 -31
  187. package/guidelines/modelStore/modelStore.generate.json +0 -31
  188. package/guidelines/modelTemplate/modelTemplate.generate.json +0 -31
  189. package/guidelines/modelUnit/modelUnit.generate.json +0 -31
  190. package/guidelines/modelUtil/modelUtil.generate.json +0 -31
  191. package/guidelines/modelView/modelView.generate.json +0 -31
  192. package/guidelines/modelZone/modelZone.generate.json +0 -31
  193. package/guidelines/moduleCodegen/moduleCodegen.generate.json +0 -31
  194. package/guidelines/moduleCodegen/moduleCodegen.instruction.md +0 -28
  195. package/guidelines/moduleOverview/moduleOverview.generate.json +0 -31
  196. package/guidelines/queryRule/queryRule.generate.json +0 -31
  197. package/guidelines/recipeRule/recipeRule.generate.json +0 -31
  198. package/guidelines/runtimeRule/runtimeRule.generate.json +0 -25
  199. package/guidelines/scalarConstant/scalarConstant.generate.json +0 -32
  200. package/guidelines/scalarDictionary/scalarDictionary.generate.json +0 -32
  201. package/guidelines/scalarModule/scalarModule.generate.json +0 -31
  202. package/guidelines/sharedUiUsage/sharedUiUsage.generate.json +0 -31
  203. package/guidelines/sharedUiUsage/sharedUiUsage.instruction.md +0 -25
  204. package/guidelines/ssrRule/ssrRule.generate.json +0 -31
  205. package/guidelines/transportRule/transportRule.generate.json +0 -31
  206. package/guidelines/utilUiUsage/utilUiUsage.generate.json +0 -31
  207. package/guidelines/utilUiUsage/utilUiUsage.instruction.md +0 -25
  208. package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +0 -24
  209. package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +0 -33
  210. package/index-47pj3aee.js +0 -76
  211. package/index-5ystnsd5.js +0 -841
  212. package/index-6wwzs1bc.js +0 -7
  213. package/index-a17x49vg.js +0 -229
  214. package/index-m0xccmmm.js +0 -228
  215. package/index-meh558jy.js +0 -65
  216. package/index-rtxxan88.js +0 -471
  217. package/index-te54x9zm.js +0 -338
  218. package/index-w8kmx1b6.js +0 -2176
  219. package/index-wt7qrtd4.js +0 -1516
  220. package/templates/__scalar/__model__/__model__.abstract.md +0 -28
  221. package/templates/module/__model__.abstract.md +0 -28
  222. package/templates/service/__model__.abstract.md +0 -28
  223. package/templates/workspaceRoot/patches/react-dom@19.2.7.patch.template +0 -62
  224. package/workflow.command-gtdnzvbz.js +0 -108
@@ -1,11 +1,294 @@
1
1
  // @bun
2
+ // pkgs/@akanjs/devkit/applicationBuildReporter.ts
3
+ import { realpathSync } from "fs";
4
+ import path from "path";
5
+ import { Logger } from "akanjs/common";
6
+
7
+ class ApplicationBuildReporter {
8
+ static create() {
9
+ return {
10
+ phaseDone: (phase) => Logger.rawLog(ApplicationBuildReporter.formatPhaseLine(phase))
11
+ };
12
+ }
13
+ static printSummary(result) {
14
+ Logger.rawLog("");
15
+ Logger.rawLog(`Route artifacts: ${result.artifactDir}`);
16
+ Logger.rawLog(`Server output: ${result.outputDir}`);
17
+ Logger.rawLog(`Done in ${ApplicationBuildReporter.formatDuration(result.durationMs)}`);
18
+ }
19
+ static formatError(error, workspaceRoot = process.cwd()) {
20
+ if (error instanceof AggregateError) {
21
+ const nestedMessages = error.errors.map((nestedError, index) => ApplicationBuildReporter.formatError(nestedError, workspaceRoot).trim() || `Unknown error ${index + 1}`).map((message) => message.replace(/^/gm, " ")).join(`
22
+ `);
23
+ return nestedMessages ? `${error.message}
24
+ ${nestedMessages}` : error.message;
25
+ }
26
+ if (error instanceof Error) {
27
+ const causeMessage = error.cause ? `
28
+ Caused by: ${ApplicationBuildReporter.formatError(error.cause, workspaceRoot)}` : "";
29
+ return `${ApplicationBuildReporter.#withLocation(error.message, error, workspaceRoot)}${causeMessage}`;
30
+ }
31
+ if (typeof error === "object" && error !== null && "message" in error)
32
+ return ApplicationBuildReporter.#withLocation(String(error.message), error, workspaceRoot);
33
+ return String(error);
34
+ }
35
+ static #withLocation(message, error, workspaceRoot) {
36
+ const { position } = error;
37
+ if (!position?.file)
38
+ return message;
39
+ const file = ApplicationBuildReporter.#relativeToWorkspace(position.file, workspaceRoot);
40
+ const location = position.line > 0 ? `${file}:${position.line}:${position.column}` : file;
41
+ return message.includes(location) ? message : message.replace(/^.*/, (headline) => `${headline} (${location})`);
42
+ }
43
+ static #relativeToWorkspace(file, workspaceRoot) {
44
+ if (!path.isAbsolute(file))
45
+ return file;
46
+ for (const root of [workspaceRoot, ApplicationBuildReporter.#realpathOf(workspaceRoot)]) {
47
+ const relative = path.relative(root, file);
48
+ if (!relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))
49
+ return relative.replaceAll(path.sep, "/");
50
+ }
51
+ return file;
52
+ }
53
+ static #realpathOf(dir) {
54
+ try {
55
+ return realpathSync(dir);
56
+ } catch {
57
+ return dir;
58
+ }
59
+ }
60
+ static formatDuration(ms) {
61
+ if (ms < 1000)
62
+ return `${ms}ms`;
63
+ if (ms < 60000)
64
+ return `${Math.round(ms / 100) / 10}s`;
65
+ const seconds = Math.floor(ms / 1000);
66
+ return `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
67
+ }
68
+ static formatPhaseLine(phase) {
69
+ const summary = phase.summary ? `: ${phase.summary}` : "";
70
+ return `\u2713 ${phase.label}${summary} (${ApplicationBuildReporter.formatDuration(phase.durationMs)})`;
71
+ }
72
+ }
73
+
2
74
  // pkgs/@akanjs/devkit/frontendBuild/hmrWatcher.ts
3
75
  import fs from "fs";
4
- import path3 from "path";
76
+ import path5 from "path";
5
77
 
6
78
  // pkgs/@akanjs/devkit/frontendBuild/hmrChangeClassifier.ts
7
- import path from "path";
79
+ import path3 from "path";
80
+
81
+ // pkgs/@akanjs/devkit/akanApp/devHostPolicy.ts
82
+ import path2 from "path";
83
+ var BACKEND_RECOVERY_MAX_ATTEMPTS = 5;
84
+ var HELD_BUILDER_REQUEST_LIMIT = 64;
85
+ var BUILDER_MIN_RSS_RECYCLE_INTERVAL_MS = 30000;
86
+ var BUILDER_TIGHT_RSS_REPORT_LIMIT = 2;
87
+ var BUILDER_RSS_HARD_MULTIPLE = 1.5;
88
+ var DEV_IDLE_SUSPEND_MS = 300000;
89
+ var DEV_IDLE_MIN_UPTIME_MS = 30000;
8
90
  var SOURCE_EXTS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
91
+ var SERVER_SUFFIXES = [".service.ts", ".document.ts"];
92
+ var SHARED_SUFFIXES = [".constant.ts", ".dictionary.ts", ".signal.ts"];
93
+ var RUNTIME_METADATA_BASENAMES = new Set(["dict.ts", "sig.ts", "useClient.ts", "useServer.ts"]);
94
+ var shouldRestartBackendByDevPlan = (message) => {
95
+ if (!message.devPlan)
96
+ return null;
97
+ if (message.devPlan.actions.includes("report-error"))
98
+ return false;
99
+ if (message.devPlan.actions.includes("restart-builder"))
100
+ return false;
101
+ return message.devPlan.actions.includes("restart-backend");
102
+ };
103
+ var shouldRestartBuilderByDevPlan = (message) => message.devPlan?.actions.includes("restart-builder") ?? false;
104
+ var shouldAbandonBackendRecovery = (attempts, maxAttempts = BACKEND_RECOVERY_MAX_ATTEMPTS) => attempts >= maxAttempts;
105
+ var normalizeBackendReportedGeneration = (generation) => generation >= 0 ? generation : undefined;
106
+ var shouldRestartDevHostByDevPlan = (message) => message.devPlan?.actions.includes("restart-dev-host") ?? message.kinds.includes("config");
107
+ var devHostStateByBackendState = {
108
+ starting: "starting",
109
+ ready: "ready",
110
+ "restart-pending": "restarting",
111
+ recovering: "recovering",
112
+ stopping: "stopped",
113
+ stopped: "stopped"
114
+ };
115
+ var devHostStateOf = (state, gaveUp) => state === "stopped" && gaveUp ? "failed" : devHostStateByBackendState[state];
116
+ var RESTART_ROLE_ORDER = ["server", "shared", "barrel", "config"];
117
+ var generationValue = (generation) => generation ?? -1;
118
+ var isLegacyBackendFallbackFile = (file, workspaceRoot) => {
119
+ const abs = path2.resolve(file);
120
+ const ext = path2.extname(abs).toLowerCase();
121
+ if (!SOURCE_EXTS.has(ext))
122
+ return false;
123
+ const rel = path2.relative(path2.resolve(workspaceRoot), abs);
124
+ if (!rel || rel.startsWith("..") || path2.isAbsolute(rel))
125
+ return false;
126
+ const parts = rel.split(path2.sep).filter(Boolean);
127
+ const [scope] = parts;
128
+ if (scope !== "apps" && scope !== "libs" && scope !== "pkgs")
129
+ return false;
130
+ const base = path2.basename(abs);
131
+ return parts.includes("srvkit") || parts.includes("common") || SERVER_SUFFIXES.some((suffix) => base.endsWith(suffix)) || SHARED_SUFFIXES.some((suffix) => base.endsWith(suffix)) || RUNTIME_METADATA_BASENAMES.has(base) || base === "main.ts" || base === "server.ts";
132
+ };
133
+ var shouldMarkBuildPhaseRecovered = (previousByPhase, status) => {
134
+ const previous = previousByPhase.get(status.phase);
135
+ if (!previous || previous.ok || !status.ok)
136
+ return false;
137
+ const generation = generationValue(status.generation);
138
+ if (status.phase === "route" && status.scope !== undefined && previous.scope !== undefined)
139
+ return status.scope === previous.scope && generation >= previous.generation;
140
+ if (generation !== previous.generation)
141
+ return generation > previous.generation;
142
+ return status.phase === "backend";
143
+ };
144
+ var shouldKeepBuildFailure = (previousByPhase, status) => status.ok && previousByPhase.get(status.phase)?.ok === false && !shouldMarkBuildPhaseRecovered(previousByPhase, status);
145
+ var createBackendBuildStatus = ({
146
+ generation,
147
+ ok,
148
+ files = [],
149
+ message
150
+ }) => ({
151
+ generation,
152
+ phase: "backend",
153
+ ok,
154
+ files,
155
+ message
156
+ });
157
+ var backendRestartReasonFromMessage = (message) => {
158
+ const roleSet = new Set;
159
+ for (const role of message.devPlan?.roles ?? []) {
160
+ if (role === "server" || role === "shared" || role === "barrel" || role === "config")
161
+ roleSet.add(role);
162
+ }
163
+ return {
164
+ generation: message.devPlan?.generation ?? message.generation,
165
+ files: [...new Set(message.files)].sort(),
166
+ roles: RESTART_ROLE_ORDER.filter((role) => roleSet.has(role))
167
+ };
168
+ };
169
+ var mergeBackendRestartReasons = (current, next) => ({
170
+ generation: generationValue(next.generation) >= generationValue(current?.generation) ? next.generation : current?.generation,
171
+ files: [...new Set([...current?.files ?? [], ...next.files])].sort(),
172
+ roles: RESTART_ROLE_ORDER.filter((role) => current?.roles.includes(role) || next.roles.includes(role))
173
+ });
174
+ var shouldReplaceLastGoodMessage = (current, next) => !current || generationValue(next.data.generation) >= generationValue(current.data.generation);
175
+ var shouldQueueBuildStatusReplay = (backendReady, pendingReplayCount) => !backendReady || pendingReplayCount > 0;
176
+ var hasBuildFailureForGeneration = (statusByPhase, generation) => {
177
+ if (typeof generation !== "number")
178
+ return false;
179
+ for (const status of statusByPhase.values()) {
180
+ if (!status.ok && status.phase !== "route" && status.generation === generation)
181
+ return true;
182
+ }
183
+ return false;
184
+ };
185
+ var decideBuilderRssRecycle = ({
186
+ rssBytes,
187
+ ceilingBytes,
188
+ buildFailed,
189
+ msSinceLastRecycle,
190
+ minIntervalMs = BUILDER_MIN_RSS_RECYCLE_INTERVAL_MS
191
+ }) => {
192
+ if (!ceilingBytes)
193
+ return "unbounded";
194
+ if (rssBytes < ceilingBytes)
195
+ return "below-ceiling";
196
+ if (buildFailed)
197
+ return "build-failed";
198
+ if (msSinceLastRecycle !== null && msSinceLastRecycle < minIntervalMs)
199
+ return "too-soon";
200
+ return "recycle";
201
+ };
202
+ var decideBuilderRssSettle = ({
203
+ rssBytes,
204
+ ceilingBytes,
205
+ hardMultiple = BUILDER_RSS_HARD_MULTIPLE
206
+ }) => rssBytes >= ceilingBytes * hardMultiple ? "recycle-now" : "wait-and-recheck";
207
+ var decideIdleSuspend = ({
208
+ enabled,
209
+ suspended,
210
+ builderReady,
211
+ backendReady,
212
+ buildFailed,
213
+ restartPending,
214
+ msSinceWake,
215
+ minUptimeMs = DEV_IDLE_MIN_UPTIME_MS
216
+ }) => {
217
+ if (!enabled)
218
+ return "disabled";
219
+ if (suspended)
220
+ return "already-suspended";
221
+ if (!builderReady)
222
+ return "builder-not-ready";
223
+ if (!backendReady)
224
+ return "backend-not-ready";
225
+ if (buildFailed)
226
+ return "build-failed";
227
+ if (restartPending)
228
+ return "restart-pending";
229
+ if (msSinceWake !== null && msSinceWake < minUptimeMs)
230
+ return "too-soon";
231
+ return "suspend";
232
+ };
233
+ var resolveIdleSuspendMs = (raw) => {
234
+ if (raw === undefined || raw === "")
235
+ return DEV_IDLE_SUSPEND_MS;
236
+ const parsed = Number(raw);
237
+ if (!Number.isFinite(parsed) || parsed <= 0)
238
+ return null;
239
+ return Math.round(parsed);
240
+ };
241
+ var hasAnyBuildFailure = (statusByPhase) => [...statusByPhase.values()].some((status) => !status.ok && status.phase !== "route");
242
+ var shouldRefreshConfigOnIdleWake = (batch) => !!batch && batch.kinds.has("config");
243
+ var RETURNING_BUILDER_STATUSES = new Set(["starting", "recycling", "restarting"]);
244
+ var shouldHoldForReturningBuilder = ({
245
+ status,
246
+ heldCount,
247
+ limit = HELD_BUILDER_REQUEST_LIMIT
248
+ }) => RETURNING_BUILDER_STATUSES.has(status) && heldCount < limit;
249
+ var shouldWarnBuilderRssCeilingTight = (reportsSinceRecycle, limit = BUILDER_TIGHT_RSS_REPORT_LIMIT) => reportsSinceRecycle >= limit;
250
+ var isRssCeilingUnreachable = (freshRssBytes, ceilingBytes) => freshRssBytes !== null && ceilingBytes !== null && freshRssBytes >= ceilingBytes;
251
+ var shouldRelayRecycledFrontendState = (current, next) => {
252
+ if (!current || current.type !== next.type)
253
+ return true;
254
+ if (current.type === "pages-updated" && next.type === "pages-updated")
255
+ return current.data.bundlePath !== next.data.bundlePath;
256
+ if (current.type === "css-updated" && next.type === "css-updated")
257
+ return JSON.stringify(current.data.cssAssets) !== JSON.stringify(next.data.cssAssets);
258
+ return true;
259
+ };
260
+ var mergeDevPlans = (current, next) => {
261
+ if (!current)
262
+ return next;
263
+ if (!next)
264
+ return current;
265
+ const reasonByFile = { ...current.reasonByFile };
266
+ for (const [file, reasons] of Object.entries(next.reasonByFile)) {
267
+ reasonByFile[file] = [...new Set([...reasonByFile[file] ?? [], ...reasons])].sort();
268
+ }
269
+ return {
270
+ generation: Math.max(current.generation, next.generation),
271
+ files: [...new Set([...current.files, ...next.files])].sort(),
272
+ generatedFiles: [...new Set([...current.generatedFiles, ...next.generatedFiles])].sort(),
273
+ roles: [...new Set([...current.roles, ...next.roles])].sort(),
274
+ actions: [...new Set([...current.actions, ...next.actions])].sort(),
275
+ reasonByFile
276
+ };
277
+ };
278
+ var mergeInvalidateMessages = (current, next) => {
279
+ const generation = Math.max(generationValue(current.generation), generationValue(next.generation));
280
+ return {
281
+ type: "invalidate",
282
+ kinds: [...new Set([...current.kinds, ...next.kinds])].sort(),
283
+ files: [...new Set([...current.files, ...next.files])].sort(),
284
+ generation: generation >= 0 ? generation : undefined,
285
+ devPlan: mergeDevPlans(current.devPlan, next.devPlan)
286
+ };
287
+ };
288
+ var buildStatusReplaySequence = (pendingReplay, latestByPhase) => [...pendingReplay, ...latestByPhase.values()];
289
+ var filesChangedSince = (before, after) => [...before].filter(([file, stamp]) => after.get(file) !== stamp).map(([file]) => file);
290
+
291
+ // pkgs/@akanjs/devkit/frontendBuild/hmrChangeClassifier.ts
9
292
  var CSS_EXTS = new Set([".css"]);
10
293
  var CONFIG_BASENAMES = new Set(["akan.config.ts", "bunfig.toml", "tsconfig.json", "package.json"]);
11
294
 
@@ -13,10 +296,10 @@ class HmrChangeClassifier {
13
296
  classify(abs) {
14
297
  if (this.#isUninteresting(abs))
15
298
  return "ignore";
16
- const base = path.basename(abs);
299
+ const base = path3.basename(abs);
17
300
  if (CONFIG_BASENAMES.has(base))
18
301
  return "config";
19
- const ext = path.extname(abs).toLowerCase();
302
+ const ext = path3.extname(abs).toLowerCase();
20
303
  if (CSS_EXTS.has(ext))
21
304
  return "css";
22
305
  if (SOURCE_EXTS.has(ext))
@@ -24,16 +307,16 @@ class HmrChangeClassifier {
24
307
  return "ignore";
25
308
  }
26
309
  #isUninteresting(abs) {
27
- const base = path.basename(abs);
310
+ const base = path3.basename(abs);
28
311
  if (!base)
29
312
  return true;
30
313
  if (base.startsWith("."))
31
314
  return true;
32
315
  if (base.endsWith("~") || base.endsWith(".swp") || base.endsWith(".swx") || base.endsWith(".tmp"))
33
316
  return true;
34
- if (abs.includes(`${path.sep}node_modules${path.sep}`))
317
+ if (abs.includes(`${path3.sep}node_modules${path3.sep}`))
35
318
  return true;
36
- if (abs.includes(`${path.sep}.akan${path.sep}`))
319
+ if (abs.includes(`${path3.sep}.akan${path3.sep}`))
37
320
  return true;
38
321
  return false;
39
322
  }
@@ -41,7 +324,7 @@ class HmrChangeClassifier {
41
324
 
42
325
  // pkgs/@akanjs/devkit/frontendBuild/sourceMtimeIndex.ts
43
326
  import { readdir, stat } from "fs/promises";
44
- import path2 from "path";
327
+ import path4 from "path";
45
328
  var UNREADABLE = Number.NaN;
46
329
 
47
330
  class SourceMtimeIndex {
@@ -104,7 +387,7 @@ class SourceMtimeIndex {
104
387
  if (!this.#primed)
105
388
  return;
106
389
  await Promise.all(paths.map(async (file) => {
107
- const abs = path2.resolve(file);
390
+ const abs = path4.resolve(file);
108
391
  const stats = await stat(abs).catch(() => null);
109
392
  if (!stats?.isFile()) {
110
393
  this.#files.delete(abs);
@@ -190,7 +473,7 @@ class SourceMtimeIndex {
190
473
  for (const entry of entries) {
191
474
  if (SourceMtimeIndex.#skipDirent(entry.name))
192
475
  continue;
193
- const abs = path2.join(dir, entry.name);
476
+ const abs = path4.join(dir, entry.name);
194
477
  if (entry.isDirectory()) {
195
478
  descend.push(abs);
196
479
  continue;
@@ -217,7 +500,7 @@ class SourceMtimeIndex {
217
500
  }
218
501
  if (known) {
219
502
  for (const abs of [...this.#files.keys()]) {
220
- if (present.has(abs) || path2.dirname(abs) !== dir)
503
+ if (present.has(abs) || path4.dirname(abs) !== dir)
221
504
  continue;
222
505
  this.#files.delete(abs);
223
506
  changed?.add(abs);
@@ -235,7 +518,7 @@ class SourceMtimeIndex {
235
518
  this.#unsettled.delete(dir);
236
519
  }
237
520
  #forget(dir) {
238
- const prefix = `${dir}${path2.sep}`;
521
+ const prefix = `${dir}${path4.sep}`;
239
522
  this.#dirs.delete(dir);
240
523
  this.#unreadable.delete(dir);
241
524
  this.#unsettled.delete(dir);
@@ -273,8 +556,8 @@ class SourceMtimeIndex {
273
556
  return !name || name.startsWith(".") || name === "node_modules";
274
557
  }
275
558
  static #pruneNestedRoots(roots) {
276
- const resolved = [...new Set(roots.map((root) => path2.resolve(root)))].sort();
277
- return resolved.filter((root) => !resolved.some((other) => other !== root && root.startsWith(`${other}${path2.sep}`)));
559
+ const resolved = [...new Set(roots.map((root) => path4.resolve(root)))].sort();
560
+ return resolved.filter((root) => !resolved.some((other) => other !== root && root.startsWith(`${other}${path4.sep}`)));
278
561
  }
279
562
  }
280
563
 
@@ -292,14 +575,15 @@ class HmrWatcher {
292
575
  #index;
293
576
  #timer = null;
294
577
  #verifyTimer = null;
578
+ #windowStartedAt = null;
295
579
  #stopped = false;
296
580
  #flushing = false;
297
581
  #unreportedChanges = 0;
298
582
  #reportedCompensating = false;
299
583
  #reportedGaps = "";
300
584
  constructor(opts) {
301
- this.#roots = [...new Set(opts.roots.map((r) => path3.resolve(r)))];
302
- this.#debounceMs = opts.debounceMs ?? 80;
585
+ this.#roots = [...new Set(opts.roots.map((r) => path5.resolve(r)))];
586
+ this.#debounceMs = opts.debounceMs ?? HmrWatcher.#envDebounceMs() ?? 30;
303
587
  this.#verifyDelayMs = opts.verifyDelayMs ?? 250;
304
588
  this.#onBatch = opts.onBatch;
305
589
  this.#logger = opts.logger;
@@ -314,7 +598,7 @@ class HmrWatcher {
314
598
  const w = fs.watch(root, { recursive: true, persistent: false }, (_event, filename) => {
315
599
  if (!filename)
316
600
  return;
317
- const abs = path3.resolve(root, filename.toString());
601
+ const abs = path5.resolve(root, filename.toString());
318
602
  this.#queue(abs);
319
603
  });
320
604
  this.#watchers.push(w);
@@ -365,6 +649,7 @@ class HmrWatcher {
365
649
  this.#scheduleFlush();
366
650
  }
367
651
  #scheduleFlush() {
652
+ this.#windowStartedAt ??= Date.now();
368
653
  if (this.#flushing)
369
654
  return;
370
655
  if (this.#timer)
@@ -382,14 +667,19 @@ class HmrWatcher {
382
667
  try {
383
668
  while (!this.#stopped) {
384
669
  await this.#mergeDetectedChanges();
385
- if (this.#pending.size === 0)
670
+ if (this.#pending.size === 0) {
671
+ this.#windowStartedAt = null;
386
672
  break;
673
+ }
387
674
  const files = Array.from(this.#pending.keys());
388
675
  const kinds = new Set(this.#pending.values());
676
+ const flushAt = Date.now();
677
+ const trace = { eventAt: this.#windowStartedAt ?? flushAt, flushAt };
678
+ this.#windowStartedAt = null;
389
679
  this.#pending.clear();
390
680
  this.#hinted.clear();
391
681
  try {
392
- await this.#onBatch({ files, kinds });
682
+ await this.#onBatch({ files, kinds, trace });
393
683
  } catch (e) {
394
684
  this.#logger.error(`[hmr] onBatch error: ${e.message}`);
395
685
  }
@@ -440,6 +730,11 @@ class HmrWatcher {
440
730
  const rest = gaps.length > 3 ? ` and ${gaps.length - 3} more` : "";
441
731
  this.#logger.warn(`[hmr] cannot read ${gaps.length} path(s), so edits underneath them will not rebuild: ${shown}${rest}`);
442
732
  }
733
+ static #envDebounceMs() {
734
+ const raw = process.env.AKAN_DEV_WATCH_DEBOUNCE_MS;
735
+ const ms = raw ? Number(raw) : Number.NaN;
736
+ return Number.isInteger(ms) && ms >= 0 ? ms : null;
737
+ }
443
738
  #scheduleVerify() {
444
739
  if (this.#stopped || this.#verifyDelayMs <= 0)
445
740
  return;
@@ -464,7 +759,7 @@ class HmrWatcher {
464
759
  // pkgs/@akanjs/devkit/frontendBuild/watchRootResolver.ts
465
760
  import fs2 from "fs";
466
761
  import { readFile } from "fs/promises";
467
- import path4 from "path";
762
+ import path6 from "path";
468
763
 
469
764
  class WatchRootResolver {
470
765
  #app;
@@ -473,20 +768,20 @@ class WatchRootResolver {
473
768
  }
474
769
  async resolve() {
475
770
  const tsconfig = await this.#app.getTsConfig();
476
- const appDir = path4.resolve(this.#app.cwdPath);
477
- const appsContainer = path4.dirname(appDir);
478
- const libsContainer = path4.resolve(this.#app.workspace.workspaceRoot, "libs");
479
- const libRoots = await this.#resolveLibRoots(libsContainer);
771
+ const appDir = path6.resolve(this.#app.cwdPath);
772
+ const appsContainer = path6.dirname(appDir);
773
+ const libsContainer = path6.resolve(this.#app.workspace.workspaceRoot, "libs");
774
+ const libRoots = (await this.#resolveLibDeps(libsContainer))?.map((name) => path6.join(libsContainer, name)).filter((dir) => fs2.existsSync(dir));
480
775
  const set = new Set;
481
- set.add(path4.resolve(`${this.#app.cwdPath}/page`));
776
+ set.add(path6.resolve(`${this.#app.cwdPath}/page`));
482
777
  for (const targets of Object.values(tsconfig.compilerOptions.paths ?? {})) {
483
778
  for (const target of targets) {
484
779
  if (!target)
485
780
  continue;
486
- if (path4.isAbsolute(target))
781
+ if (path6.isAbsolute(target))
487
782
  continue;
488
783
  const cleaned = target.replace(/\/?\*+.*$/, "").replace(/\/[^/]+\.[^/]+$/, "");
489
- const resolved = path4.resolve(this.#app.workspace.workspaceRoot, cleaned);
784
+ const resolved = path6.resolve(this.#app.workspace.workspaceRoot, cleaned);
490
785
  if (resolved === libsContainer && libRoots) {
491
786
  for (const root of libRoots)
492
787
  set.add(root);
@@ -499,17 +794,11 @@ class WatchRootResolver {
499
794
  }
500
795
  return [...set];
501
796
  }
502
- async#resolveLibRoots(libsContainer) {
503
- const libDeps = await this.#resolveLibDeps(libsContainer);
504
- if (!libDeps)
505
- return null;
506
- return libDeps.map((name) => path4.join(libsContainer, name)).filter((dir) => fs2.existsSync(dir));
507
- }
508
797
  async#resolveLibDeps(libsContainer) {
509
798
  const scanInfo = this.#app.getScanInfo({ allowEmpty: true });
510
799
  if (scanInfo?.type === "app")
511
800
  return scanInfo.libDeps;
512
- const direct = await WatchRootResolver.#readManifestLibDeps(path4.join(this.#app.cwdPath, "akan.app.json"));
801
+ const direct = await WatchRootResolver.#readManifestLibDeps(path6.join(this.#app.cwdPath, "akan.app.json"));
513
802
  if (!direct)
514
803
  return null;
515
804
  const closure = new Set;
@@ -519,7 +808,7 @@ class WatchRootResolver {
519
808
  if (!name || closure.has(name))
520
809
  continue;
521
810
  closure.add(name);
522
- const nested = await WatchRootResolver.#readManifestLibDeps(path4.join(libsContainer, name, "akan.lib.json"));
811
+ const nested = await WatchRootResolver.#readManifestLibDeps(path6.join(libsContainer, name, "akan.lib.json"));
523
812
  if (!nested)
524
813
  return null;
525
814
  queue.push(...nested);
@@ -538,4 +827,4 @@ class WatchRootResolver {
538
827
  }
539
828
  }
540
829
 
541
- export { HmrWatcher, WatchRootResolver };
830
+ export { ApplicationBuildReporter, BUILDER_MIN_RSS_RECYCLE_INTERVAL_MS, SOURCE_EXTS, shouldRestartBackendByDevPlan, shouldRestartBuilderByDevPlan, shouldAbandonBackendRecovery, normalizeBackendReportedGeneration, shouldRestartDevHostByDevPlan, devHostStateOf, isLegacyBackendFallbackFile, shouldMarkBuildPhaseRecovered, shouldKeepBuildFailure, createBackendBuildStatus, backendRestartReasonFromMessage, mergeBackendRestartReasons, shouldReplaceLastGoodMessage, shouldQueueBuildStatusReplay, hasBuildFailureForGeneration, decideBuilderRssRecycle, decideBuilderRssSettle, decideIdleSuspend, resolveIdleSuspendMs, hasAnyBuildFailure, shouldRefreshConfigOnIdleWake, shouldHoldForReturningBuilder, shouldWarnBuilderRssCeilingTight, isRssCeilingUnreachable, shouldRelayRecycledFrontendState, mergeInvalidateMessages, buildStatusReplaySequence, filesChangedSince, HmrWatcher, WatchRootResolver };