@akanjs/cli 3.0.0-alpha.8 → 3.0.0-alpha.80

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 (152) 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-pwc6d6yk.js} +3 -5
  5. package/{agent.command-pggr92jj.js → agent.command-180hh0ye.js} +11 -12
  6. package/{application.command-692yap1d.js → application.command-gmcgen9y.js} +59 -35
  7. package/{applicationBuildRunner-ha3y8ew8.js → applicationBuildRunner-tavpx3fv.js} +22 -20
  8. package/{applicationReleasePackager-gg8ccbeh.js → applicationReleasePackager-ktjt0erc.js} +8 -9
  9. package/buildBatch.proc.js +12 -13
  10. package/capacitorApp-kwa67kzs.js +12 -0
  11. package/{cloud.command-wqfsyzv2.js → cloud.command-gpq7qxrc.js} +15 -17
  12. package/commandManifest.json +1 -1
  13. package/{context.command-9bxtdn0w.js → context.command-dk2m2sjx.js} +19 -22
  14. package/dependencyScanner-c64m6fxp.js +8 -0
  15. package/fleet.command-3bkyyd3a.js +836 -0
  16. package/getDirname-dr3jz1xg.js +7 -0
  17. package/{guideline.command-nfqahxex.js → guideline.command-w6ddv13r.js} +16 -17
  18. package/guidelines/agentRule/agentRule.generate.json +31 -0
  19. package/guidelines/agentRule/agentRule.instruction.md +525 -0
  20. package/guidelines/conventions/conventions.generate.json +25 -0
  21. package/guidelines/conventions/conventions.instruction.md +847 -0
  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 +25 -0
  26. package/guidelines/mcpRule/mcpRule.instruction.md +217 -0
  27. package/guidelines/queryRule/queryRule.generate.json +31 -0
  28. package/guidelines/queryRule/queryRule.instruction.md +143 -0
  29. package/guidelines/runtimeRule/runtimeRule.generate.json +25 -0
  30. package/guidelines/runtimeRule/runtimeRule.instruction.md +176 -0
  31. package/guidelines/ssrRule/ssrRule.instruction.md +49 -5
  32. package/guidelines/transportRule/transportRule.generate.json +31 -0
  33. package/guidelines/transportRule/transportRule.instruction.md +60 -0
  34. package/guidelines/workspaceOnboarding/workspaceOnboarding.generate.json +24 -0
  35. package/guidelines/workspaceOnboarding/workspaceOnboarding.instruction.md +263 -0
  36. package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +33 -0
  37. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +402 -0
  38. package/incrementalBuilder.proc.js +21 -22
  39. package/{index-4hek879p.js → index-1kzsn94d.js} +1 -1
  40. package/{index-p3f4q532.js → index-3c9n3nt8.js} +31 -30
  41. package/index-3d9y066c.js +76 -0
  42. package/{index-76rn3g2c.js → index-47pj3aee.js} +4 -4
  43. package/{index-gex7c8kd.js → index-5n0hf8r9.js} +65 -38
  44. package/{index-mssqn2sq.js → index-5y7qba1c.js} +79 -33
  45. package/index-6wwzs1bc.js +7 -0
  46. package/{index-wnp7hwq7.js → index-92zztqy1.js} +7 -7
  47. package/{index-fgc8r6dj.js → index-a5vmm6x4.js} +3 -1
  48. package/{index-azv0xjb5.js → index-a8h184wr.js} +15 -11
  49. package/{index-67546d0j.js → index-ayy5ecax.js} +1 -1
  50. package/{index-xhgtkekh.js → index-b2nt0w0k.js} +27 -27
  51. package/{index-xys926f2.js → index-by5gpp8x.js} +4 -4
  52. package/{index-bz2sfzzt.js → index-cd5x18qh.js} +32 -32
  53. package/{index-bjpxzr6s.js → index-ctphds8v.js} +1 -1
  54. package/{index-w6wbb612.js → index-dq6wq1tv.js} +94 -61
  55. package/{index-js368gk9.js → index-ee8z8adx.js} +13 -13
  56. package/{index-5dw57f0d.js → index-f7wewj2v.js} +155 -76
  57. package/{index-6rhabeev.js → index-ft1sfjz0.js} +36 -25
  58. package/{index-7myvn0f0.js → index-h7yw2z9n.js} +7 -7
  59. package/{index-5pmx7bkg.js → index-j9vnq8tr.js} +18 -18
  60. package/{index-vg0sj9nc.js → index-k1n0h7dk.js} +840 -201
  61. package/{index-vtj3zps1.js → index-k86zc21w.js} +57 -57
  62. package/{index-46tjzh6s.js → index-mfm35dhh.js} +29 -29
  63. package/{index-xjd3rqzj.js → index-n68jx79w.js} +6 -15
  64. package/{index-ztpw544k.js → index-qcracvc9.js} +8 -8
  65. package/{index-2c3e2xh8.js → index-saheq2bs.js} +4 -4
  66. package/{index-gmy45vz2.js → index-v0s24t8j.js} +14 -14
  67. package/{index-0cj2zxbm.js → index-wet2ytnr.js} +12 -11
  68. package/{index-j9cxndc0.js → index-x23688ar.js} +12 -7
  69. package/index-xnhf8tr9.js +109 -0
  70. package/{index-a1e0j63x.js → index-xxe90kqy.js} +58 -25
  71. package/{index-qb61h0k7.js → index-z3c9mmw4.js} +1098 -1360
  72. package/index.js +22 -24
  73. package/{library.command-md9715jz.js → library.command-wpedct6c.js} +11 -9
  74. package/{localRegistry.command-exkbamyj.js → localRegistry.command-pjdxa01g.js} +20 -22
  75. package/{module.command-w5aaddxk.js → module.command-8n4kct3e.js} +13 -15
  76. package/{package.command-yfkrcy0z.js → package.command-fcbd0b1d.js} +8 -9
  77. package/package.json +5 -7
  78. package/{page.command-echbavp4.js → page.command-x4379grq.js} +7 -8
  79. package/{primitive.command-9fbhspw2.js → primitive.command-8etmnqhq.js} +13 -15
  80. package/{quality.command-3pnt9yep.js → quality.command-hfx7z8yr.js} +226 -104
  81. package/recipeScanner-fpagtgc1.js +11 -0
  82. package/{repair.command-carj4vax.js → repair.command-j0fs5qkz.js} +12 -13
  83. package/{routeSourceValidator-e4jmbfcx.js → routeSourceValidator-ze6x894c.js} +0 -2
  84. package/{scalar.command-51ryzypc.js → scalar.command-2emk89eh.js} +11 -13
  85. package/templates/app/env/env.client.debug.ts.template +1 -5
  86. package/templates/app/env/env.client.develop.ts.template +1 -5
  87. package/templates/app/env/env.client.local.ts.template +1 -5
  88. package/templates/app/env/env.client.main.ts.template +1 -5
  89. package/templates/app/env/env.client.testing.ts.template +1 -5
  90. package/templates/app/env/env.client.type.ts +2 -6
  91. package/templates/app/env/env.server.debug.ts.template +1 -5
  92. package/templates/app/env/env.server.develop.ts.template +1 -5
  93. package/templates/app/env/env.server.local.ts.template +1 -5
  94. package/templates/app/env/env.server.main.ts.template +1 -5
  95. package/templates/app/main.ts +3 -1
  96. package/templates/appSample/lib/task/task.signal.ts +11 -6
  97. package/templates/appSample/srvkit/AuthGuard.ts +9 -5
  98. package/templates/appSample/srvkit/SessionInternalArg.ts +4 -3
  99. package/templates/crudPages/[__model__Id]/edit/page.tsx +6 -6
  100. package/templates/crudPages/[__model__Id]/page.tsx +10 -13
  101. package/templates/crudPages/new/page.tsx +6 -6
  102. package/templates/crudPages/page.tsx +9 -9
  103. package/templates/crudSinglePage/page.tsx +11 -7
  104. package/templates/env/_env.server.type.ts +7 -5
  105. package/templates/lib/db.ts +1 -1
  106. package/templates/lib/dict.ts +1 -1
  107. package/templates/lib/sig.ts +1 -1
  108. package/templates/lib/srv.ts +6 -2
  109. package/templates/module/__Model__.Util.tsx +1 -1
  110. package/templates/module/__Model__.Zone.tsx +3 -5
  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/AGENTS.md.template +4 -972
  116. package/templates/workspaceRoot/CLAUDE.md.template +19 -0
  117. package/templates/workspaceRoot/biome.json.template +4 -244
  118. package/templates/workspaceRoot/docs/AI-DEVELOPMENT.md.template +10 -14
  119. package/templates/workspaceRoot/docs/GENERATED.md.template +12 -10
  120. package/templates/workspaceRoot/package.json.template +2 -4
  121. package/typeChecker-3xgrzc2v.js +7 -0
  122. package/typecheck.proc.js +4 -5
  123. package/{workflow.command-91wmvm8k.js → workflow.command-cvpmzwjg.js} +21 -23
  124. package/{workspace.command-wa10mfd9.js → workspace.command-mbb5s3wx.js} +108 -91
  125. package/capacitorApp-p0z5yab2.js +0 -60
  126. package/dependencyScanner-f6grrep3.js +0 -9
  127. package/index-mxvakhsm.js +0 -66
  128. package/index-r24hmh0q.js +0 -4
  129. package/recipeScanner-tghkzrrt.js +0 -12
  130. package/templates/workspaceRoot/.cursor/rules/akan-page-routing.mdc.template +0 -43
  131. package/templates/workspaceRoot/.cursor/rules/akan-sync-conventions.mdc.template +0 -34
  132. package/templates/workspaceRoot/.cursor/rules/application-test-commands.mdc.template +0 -16
  133. package/templates/workspaceRoot/.cursor/rules/change-scope.mdc.template +0 -12
  134. package/templates/workspaceRoot/.cursor/rules/client-server-boundaries.mdc.template +0 -18
  135. package/templates/workspaceRoot/.cursor/rules/coding-comments.mdc.template +0 -25
  136. package/templates/workspaceRoot/.cursor/rules/coding-style.mdc.template +0 -44
  137. package/templates/workspaceRoot/.cursor/rules/domain-module-conventions.mdc.template +0 -17
  138. package/templates/workspaceRoot/.cursor/rules/format-lint.mdc.template +0 -12
  139. package/templates/workspaceRoot/.cursor/rules/lint-enforced-rules.mdc.template +0 -19
  140. package/templates/workspaceRoot/.cursor/rules/module-file-playbook.mdc.template +0 -62
  141. package/templates/workspaceRoot/.cursor/rules/naming-conventions.mdc.template +0 -15
  142. package/templates/workspaceRoot/.cursor/rules/react-component-style.mdc.template +0 -21
  143. package/templates/workspaceRoot/.cursor/rules/repo-overview.mdc.template +0 -17
  144. package/templates/workspaceRoot/.cursor/rules/scalar-modeling.mdc.template +0 -99
  145. package/templates/workspaceRoot/.cursor/rules/secrets-and-env.mdc.template +0 -13
  146. package/templates/workspaceRoot/.cursor/rules/service-signal-conventions.mdc.template +0 -83
  147. package/templates/workspaceRoot/.cursor/rules/srvkit-adapters-and-guards.mdc.template +0 -50
  148. package/templates/workspaceRoot/.cursor/rules/ssr-first.mdc.template +0 -59
  149. package/templates/workspaceRoot/.cursor/rules/typescript-imports.mdc.template +0 -16
  150. package/typeChecker-kravn7ns.js +0 -8
  151. /package/{index-0wae5ebk.js → index-meh558jy.js} +0 -0
  152. /package/{index-ss469dec.js → index-nz8prx9g.js} +0 -0
@@ -1,20 +1,20 @@
1
1
  // @bun
2
- import {
3
- AbstractDoc
4
- } from "./index-0wae5ebk.js";
5
2
  import {
6
3
  Workspace,
7
- command,
8
4
  runner,
9
- script
10
- } from "./index-6rhabeev.js";
5
+ script,
6
+ command
7
+ } from "./index-ft1sfjz0.js";
8
+ import {
9
+ rootAllowedFiles,
10
+ rootAllowedDirs,
11
+ isAllowedLibFacetRootFile
12
+ } from "./index-k1n0h7dk.js";
13
+ import"./index-ayy5ecax.js";
14
+ import"./index-6wwzs1bc.js";
11
15
  import {
12
- appRootAllowedFiles,
13
- libFacetRootAllowedFiles
14
- } from "./index-vg0sj9nc.js";
15
- import"./index-mxvakhsm.js";
16
- import"./index-67546d0j.js";
17
- import"./index-r24hmh0q.js";
16
+ AbstractDoc
17
+ } from "./index-meh558jy.js";
18
18
 
19
19
  // pkgs/@akanjs/devkit/qualityScanner.ts
20
20
  import { createHash } from "crypto";
@@ -22,10 +22,79 @@ import { readdir, readFile, stat } from "fs/promises";
22
22
  import path from "path";
23
23
  import { RESERVED_ROUTE_CONFIG_EXPORTS } from "akanjs/common";
24
24
  import ignore from "ignore";
25
- import ts2 from "typescript";
25
+ import ts3 from "typescript";
26
26
 
27
- // pkgs/@akanjs/devkit/ssrScanner.ts
27
+ // pkgs/@akanjs/devkit/formSetterScanner.ts
28
28
  import ts from "typescript";
29
+
30
+ class FormSetterScanner {
31
+ static #fieldSetter = /^set[A-Za-z0-9_$]*On[A-Za-z0-9_$]*$/;
32
+ scan(sourceFiles) {
33
+ return sourceFiles.filter((sourceFile) => sourceFile.file.endsWith(".tsx")).flatMap((f) => this.#scanFile(f));
34
+ }
35
+ #scanFile({ file, sourceFile }) {
36
+ const wrapped = [];
37
+ const visit = (node) => {
38
+ if (ts.isJsxAttribute(node)) {
39
+ const setter = FormSetterScanner.#wrappedSetterOf(node);
40
+ if (setter)
41
+ wrapped.push({ setter, line: FormSetterScanner.#lineOf(sourceFile, node) });
42
+ }
43
+ ts.forEachChild(node, visit);
44
+ };
45
+ visit(sourceFile);
46
+ if (!wrapped.length)
47
+ return [];
48
+ const setters = [...new Set(wrapped.map((entry) => entry.setter))].sort();
49
+ return [
50
+ {
51
+ rule: "akan.agent.unpublished-form-setter",
52
+ scope: "agent",
53
+ severity: "warning",
54
+ message: setters.length === 1 ? `${setters[0]} is reached through a wrapper, so that field publishes no agent tool and carries no data-akan-action.` : `${setters.length} field setters are reached through a wrapper, so those fields publish no agent tool and carry no data-akan-action: ${setters.join(", ")}.`,
55
+ file,
56
+ line: wrapped[0]?.line,
57
+ locations: wrapped.map(({ line }) => ({ file, line }))
58
+ }
59
+ ];
60
+ }
61
+ static #wrappedSetterOf(attribute) {
62
+ if (!ts.isIdentifier(attribute.name) || !/^on[A-Z]/.test(attribute.name.text))
63
+ return null;
64
+ const initializer = attribute.initializer;
65
+ if (!initializer || !ts.isJsxExpression(initializer) || !initializer.expression)
66
+ return null;
67
+ const handler = initializer.expression;
68
+ if (!ts.isArrowFunction(handler) && !ts.isFunctionExpression(handler))
69
+ return null;
70
+ if (!handler.parameters.length)
71
+ return null;
72
+ return FormSetterScanner.#setterCallIn(handler.body);
73
+ }
74
+ static #setterCallIn(node) {
75
+ let found = null;
76
+ const visit = (current) => {
77
+ if (found)
78
+ return;
79
+ if (ts.isCallExpression(current) && ts.isPropertyAccessExpression(current.expression)) {
80
+ const { expression, name } = current.expression;
81
+ if (ts.isPropertyAccessExpression(expression) && ts.isIdentifier(expression.expression) && expression.expression.text === "st" && expression.name.text === "do" && FormSetterScanner.#fieldSetter.test(name.text)) {
82
+ found = name.text;
83
+ return;
84
+ }
85
+ }
86
+ ts.forEachChild(current, visit);
87
+ };
88
+ visit(node);
89
+ return found;
90
+ }
91
+ static #lineOf(sourceFile, node) {
92
+ return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;
93
+ }
94
+ }
95
+
96
+ // pkgs/@akanjs/devkit/ssrScanner.ts
97
+ import ts2 from "typescript";
29
98
  var STATIC_COMPONENT_MIN_MASS = 4;
30
99
  var MIXED_COMPONENT_MIN_MASS = 10;
31
100
  var MIXED_COMPONENT_MAX_TOUCHES = 2;
@@ -143,31 +212,31 @@ class SsrScanner {
143
212
  });
144
213
  }
145
214
  }
146
- ts.forEachChild(node, visit);
215
+ ts2.forEachChild(node, visit);
147
216
  };
148
- ts.forEachChild(sourceFile.sourceFile, visit);
217
+ ts2.forEachChild(sourceFile.sourceFile, visit);
149
218
  return warnings;
150
219
  }
151
220
  #isMountEffect(sourceFile, node) {
152
- if (!ts.isCallExpression(node))
221
+ if (!ts2.isCallExpression(node))
153
222
  return false;
154
223
  const callee = node.expression.getText(sourceFile);
155
224
  if (callee !== "useEffect" && callee !== "useLayoutEffect")
156
225
  return false;
157
226
  const deps = node.arguments[1];
158
- return !!deps && ts.isArrayLiteralExpression(deps) && deps.elements.length === 0;
227
+ return !!deps && ts2.isArrayLiteralExpression(deps) && deps.elements.length === 0;
159
228
  }
160
229
  #getLoadCalls(sourceFile, node) {
161
230
  const calls = [];
162
231
  const visit = (child) => {
163
- if (ts.isCallExpression(child)) {
232
+ if (ts2.isCallExpression(child)) {
164
233
  const callee = child.expression.getText(sourceFile);
165
234
  if (/^fetch\.[a-z]/.test(callee) || /^st\.do\.(init|get|view|load|list|count|insight)[A-Z]/.test(callee))
166
235
  calls.push({ callee, node: child });
167
236
  }
168
- ts.forEachChild(child, visit);
237
+ ts2.forEachChild(child, visit);
169
238
  };
170
- ts.forEachChild(node, visit);
239
+ ts2.forEachChild(node, visit);
171
240
  return calls;
172
241
  }
173
242
  #getTemplateStateWarnings(sourceFile) {
@@ -175,7 +244,7 @@ class SsrScanner {
175
244
  return [];
176
245
  const warnings = [];
177
246
  const visit = (node) => {
178
- if (ts.isCallExpression(node) && node.expression.getText(sourceFile.sourceFile) === "useState") {
247
+ if (ts2.isCallExpression(node) && node.expression.getText(sourceFile.sourceFile) === "useState") {
179
248
  warnings.push({
180
249
  rule: "akan.ssr.template-client-state",
181
250
  scope: "ssr",
@@ -185,9 +254,9 @@ class SsrScanner {
185
254
  message: "Template holds form state in useState. Templates are store-driven and carry no local state."
186
255
  });
187
256
  }
188
- ts.forEachChild(node, visit);
257
+ ts2.forEachChild(node, visit);
189
258
  };
190
- ts.forEachChild(sourceFile.sourceFile, visit);
259
+ ts2.forEachChild(sourceFile.sourceFile, visit);
191
260
  return warnings;
192
261
  }
193
262
  #measureBalance(sourceFiles) {
@@ -228,14 +297,14 @@ class SsrScanner {
228
297
  return components;
229
298
  }
230
299
  #getComponentNodes(statement) {
231
- if (ts.isFunctionDeclaration(statement) && statement.body)
300
+ if (ts2.isFunctionDeclaration(statement) && statement.body)
232
301
  return [{ name: statement.name?.text ?? "default", node: statement.body }];
233
- if (!ts.isVariableStatement(statement))
302
+ if (!ts2.isVariableStatement(statement))
234
303
  return [];
235
304
  return statement.declarationList.declarations.flatMap((declaration) => {
236
- if (!ts.isIdentifier(declaration.name) || !declaration.initializer)
305
+ if (!ts2.isIdentifier(declaration.name) || !declaration.initializer)
237
306
  return [];
238
- if (!ts.isArrowFunction(declaration.initializer) && !ts.isFunctionExpression(declaration.initializer))
307
+ if (!ts2.isArrowFunction(declaration.initializer) && !ts2.isFunctionExpression(declaration.initializer))
239
308
  return [];
240
309
  return [{ name: declaration.name.text, node: declaration.initializer }];
241
310
  });
@@ -243,7 +312,7 @@ class SsrScanner {
243
312
  #getTouches(sourceFile, node) {
244
313
  const touches = [];
245
314
  const visit = (child) => {
246
- if (ts.isCallExpression(child)) {
315
+ if (ts2.isCallExpression(child)) {
247
316
  const callee = child.expression.getText(sourceFile);
248
317
  const bareName = callee.split(".").pop() ?? callee;
249
318
  if (callee === "createContext" || callee === "lazy")
@@ -251,60 +320,60 @@ class SsrScanner {
251
320
  else if (/^use[A-Z]/.test(bareName) && !SsrScanner.#serverSafeCalls.has(bareName))
252
321
  touches.push(bareName);
253
322
  }
254
- if (ts.isJsxAttribute(child) && /^on[A-Z]/.test(child.name.getText(sourceFile)))
323
+ if (ts2.isJsxAttribute(child) && /^on[A-Z]/.test(child.name.getText(sourceFile)))
255
324
  touches.push(child.name.getText(sourceFile));
256
- if (ts.isPropertyAccessExpression(child)) {
325
+ if (ts2.isPropertyAccessExpression(child)) {
257
326
  const root = getAccessRoot(child);
258
327
  if (root === "st")
259
328
  touches.push("st");
260
329
  else if (SsrScanner.#clientGlobals.has(root))
261
330
  touches.push(root);
262
331
  }
263
- ts.forEachChild(child, visit);
332
+ ts2.forEachChild(child, visit);
264
333
  };
265
- ts.forEachChild(node, visit);
334
+ ts2.forEachChild(node, visit);
266
335
  return touches;
267
336
  }
268
337
  #getTagNames(sourceFile, node) {
269
338
  const tags = new Set;
270
339
  const visit = (child) => {
271
- if (ts.isJsxOpeningElement(child) || ts.isJsxSelfClosingElement(child))
340
+ if (ts2.isJsxOpeningElement(child) || ts2.isJsxSelfClosingElement(child))
272
341
  tags.add(child.tagName.getText(sourceFile).split(".")[0]);
273
- ts.forEachChild(child, visit);
342
+ ts2.forEachChild(child, visit);
274
343
  };
275
- ts.forEachChild(node, visit);
344
+ ts2.forEachChild(node, visit);
276
345
  return tags;
277
346
  }
278
347
  #getMass(node) {
279
348
  let mass = 0;
280
349
  const visit = (child) => {
281
- if (ts.isJsxOpeningElement(child) || ts.isJsxSelfClosingElement(child))
350
+ if (ts2.isJsxOpeningElement(child) || ts2.isJsxSelfClosingElement(child))
282
351
  mass += 1;
283
- ts.forEachChild(child, visit);
352
+ ts2.forEachChild(child, visit);
284
353
  };
285
- ts.forEachChild(node, visit);
354
+ ts2.forEachChild(node, visit);
286
355
  return mass;
287
356
  }
288
357
  #hasUseClient(sourceFile) {
289
358
  const first = sourceFile.statements[0];
290
- if (!first || !ts.isExpressionStatement(first) || !ts.isStringLiteral(first.expression))
359
+ if (!first || !ts2.isExpressionStatement(first) || !ts2.isStringLiteral(first.expression))
291
360
  return false;
292
361
  return first.expression.text === "use client";
293
362
  }
294
363
  #hasVendorImport(sourceFile) {
295
- return sourceFile.statements.some((statement) => ts.isImportDeclaration(statement) && isVendorSpecifier(getSpecifier(statement)));
364
+ return sourceFile.statements.some((statement) => ts2.isImportDeclaration(statement) && isVendorSpecifier(getSpecifier(statement)));
296
365
  }
297
366
  #getVendorNames(sourceFile) {
298
367
  const names = new Set;
299
368
  for (const statement of sourceFile.statements) {
300
- if (!ts.isImportDeclaration(statement) || !isVendorSpecifier(getSpecifier(statement)))
369
+ if (!ts2.isImportDeclaration(statement) || !isVendorSpecifier(getSpecifier(statement)))
301
370
  continue;
302
371
  const clause = statement.importClause;
303
372
  if (clause?.name)
304
373
  names.add(clause.name.text);
305
- if (clause?.namedBindings && ts.isNamespaceImport(clause.namedBindings))
374
+ if (clause?.namedBindings && ts2.isNamespaceImport(clause.namedBindings))
306
375
  names.add(clause.namedBindings.name.text);
307
- if (clause?.namedBindings && ts.isNamedImports(clause.namedBindings))
376
+ if (clause?.namedBindings && ts2.isNamedImports(clause.namedBindings))
308
377
  for (const element of clause.namedBindings.elements)
309
378
  names.add(element.name.text);
310
379
  }
@@ -312,10 +381,10 @@ class SsrScanner {
312
381
  }
313
382
  #importsClientRuntime(sourceFile) {
314
383
  for (const statement of sourceFile.statements) {
315
- if (!ts.isImportDeclaration(statement))
384
+ if (!ts2.isImportDeclaration(statement))
316
385
  continue;
317
386
  const bindings = statement.importClause?.namedBindings;
318
- if (!bindings || !ts.isNamedImports(bindings))
387
+ if (!bindings || !ts2.isNamedImports(bindings))
319
388
  continue;
320
389
  if (bindings.elements.some((element) => SsrScanner.#clientRuntimeImports.has(element.name.text)))
321
390
  return true;
@@ -366,7 +435,7 @@ function getShare(serverMass, clientMass) {
366
435
  return total === 0 ? 1 : serverMass / total;
367
436
  }
368
437
  function getSpecifier(statement) {
369
- return ts.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : "";
438
+ return ts2.isStringLiteral(statement.moduleSpecifier) ? statement.moduleSpecifier.text : "";
370
439
  }
371
440
  function isVendorSpecifier(specifier) {
372
441
  if (specifier === "" || specifier.startsWith(".") || specifier.startsWith("/"))
@@ -379,9 +448,9 @@ function isVendorSpecifier(specifier) {
379
448
  }
380
449
  function getAccessRoot(node) {
381
450
  let current = node;
382
- while (ts.isPropertyAccessExpression(current))
451
+ while (ts2.isPropertyAccessExpression(current))
383
452
  current = current.expression;
384
- return ts.isIdentifier(current) ? current.text : "";
453
+ return ts2.isIdentifier(current) ? current.text : "";
385
454
  }
386
455
 
387
456
  // pkgs/@akanjs/devkit/qualityScanner.ts
@@ -405,7 +474,8 @@ var SUGGESTED_RULES = [
405
474
  "Keep apps/*/lib and libs/*/lib root files limited to generated support facets such as cnst.ts, db.ts, dict.ts, sig.ts, srv.ts, st.ts, useClient.ts, and useServer.ts.",
406
475
  "Use domain module folders consistently: lib/<model> for database modules, lib/_<service> for service modules, and lib/__scalar/<scalar> for scalar modules.",
407
476
  "Keep module UI filenames predictable: database modules use <Model>.Template/Unit/Util/View/Zone.tsx, service modules use <Service>.Util/Zone.tsx, and scalar modules use <Scalar>.Template/Unit.tsx.",
408
- "Move shared app utilities to apps/*/common instead of creating apps/*/base.",
477
+ "Hand a form control its store setter by reference so the field publishes an agent tool; put normalization in the control's transform prop and a multi-write in a _postSet<Field> hook on the store.",
478
+ "Move shared app and lib utilities to common/ instead of creating apps/*/base or libs/*/base.",
409
479
  "Avoid large mixed-purpose class files; class export files should import helpers from neighboring utility files instead of declaring them inline."
410
480
  ];
411
481
  var CONVENTION_SUFFIXES = [
@@ -423,15 +493,20 @@ var RULE_FIXES = {
423
493
  "akan.file.max-lines": "Break the file into smaller focused modules; keep one primary responsibility per file.",
424
494
  "akan.file.abstract-max-lines": "Run `akan compact <app-or-lib>` to rewrite the abstract with the AI editor, keeping only the invariants and workflows the source files cannot show.",
425
495
  "akan.file.placeholder-export": "Remove the placeholder export; generated indexes should only re-export real modules.",
496
+ "akan.file.bang-comment-in-client": "Rewrite the marker as `// FIXME:` or `// TODO:`. Keep the bang form for server, srvkit, and CLI files.",
426
497
  "akan.file.dictionary-stale-text": "Replace the scaffold text with real localized copy for this dictionary entry.",
427
498
  "akan.file.global-declaration": "Move the global declaration into an approved low-level integration file (e.g. webkit) and keep it isolated.",
428
499
  "akan.file.window-augmentation": "Move the Window augmentation into an approved browser integration file and keep it isolated.",
429
500
  "akan.file.prototype-mutation": "Avoid prototype mutation, or isolate it in an approved low-level integration file.",
430
501
  "akan.file.class-export-global-declaration": "Move the helper to a sibling file and import it into the class module.",
502
+ "akan.agent.unpublished-form-setter": "Pass the setter by reference where the wrapper only forwards (onChange={st.do.setTitleOnTask}); move normalization into the control's own transform prop; move a multi-write into a _postSet<Field> hook on the store, keeping the generated setter on the control.",
431
503
  "akan.file.component-internal-declaration": "Move the type or helper to a type/util file in ui/, webkit/, or common/ by purpose. If it is the component's props, declare it as `interface <Component>Props`.",
432
504
  "akan.file.component-export": "Move the value or type to a util/constant/type file in ui/, webkit/, or common/ and import it. Adding `export` is not a valid fix \u2014 only PascalCase components and their `<Component>Props` interface belong here.",
433
505
  "akan.layout.app-root-file": "Move the file into a conventional app folder (common, env, lib, page, private, public, script, srvkit, ui, or webkit).",
434
- "akan.layout.lib-root-file": "Move the file into a domain module folder under lib/; keep lib root limited to generated support facets.",
506
+ "akan.layout.app-root-folder": "Move the folder's contents into a conventional app folder (common, env, lib, page, private, public, script, srvkit, ui, or webkit) and delete it.",
507
+ "akan.layout.lib-root-file": "Move the file into a conventional lib folder (common, env, lib, page, private, public, srvkit, ui, or webkit).",
508
+ "akan.layout.lib-root-folder": "Move the folder's contents into a conventional lib folder (common, env, lib, page, private, public, srvkit, ui, or webkit) and delete it.",
509
+ "akan.layout.lib-facet-file": "Move the file into a domain module folder under lib/; keep the lib facet root limited to generated support facets.",
435
510
  "akan.layout.module-ui-file": "Rename the file to an allowed module UI name, or move it to ui/ if it is not a module component.",
436
511
  "akan.ssr.unnecessary-use-client": 'Delete the "use client" directive so the file renders on the server. If it exists only to wrap one client child, drop the wrapper and use the child directly.',
437
512
  "akan.ssr.client-static-component": "Move the component to a server file \u2014 a <Model>.Unit.tsx / <Model>.View.tsx for a module, or a ui/ file with no directive \u2014 and reference it from the client file.",
@@ -459,6 +534,7 @@ class AkanQualityScanner {
459
534
  ...sourceFiles.flatMap((sourceFile) => this.#scanConventionQuality(sourceFile)),
460
535
  ...sourceFiles.flatMap((sourceFile) => this.#scanLayoutQuality(sourceFile)),
461
536
  ...abstractFiles.flatMap((abstractFile) => this.#scanAbstractQuality(abstractFile)),
537
+ ...new FormSetterScanner().scan(sourceFiles),
462
538
  ...ssr.warnings
463
539
  ];
464
540
  return {
@@ -511,7 +587,7 @@ class AkanQualityScanner {
511
587
  file,
512
588
  absolutePath,
513
589
  content,
514
- sourceFile: ts2.createSourceFile(file, content, ts2.ScriptTarget.Latest, true, getScriptKind(file))
590
+ sourceFile: ts3.createSourceFile(file, content, ts3.ScriptTarget.Latest, true, getScriptKind(file))
515
591
  };
516
592
  }
517
593
  async#readTextFile(workspaceRoot, file) {
@@ -569,6 +645,7 @@ class AkanQualityScanner {
569
645
  message: `File has ${lineCount} lines. Keep single files under ${MAX_FILE_LINES} lines.`
570
646
  });
571
647
  }
648
+ warnings.push(...getBangCommentWarnings(sourceFile));
572
649
  warnings.push(...getPlaceholderExportWarnings(sourceFile));
573
650
  warnings.push(...getDictionaryTextWarnings(sourceFile));
574
651
  warnings.push(...getGlobalMutationWarnings(sourceFile));
@@ -670,25 +747,30 @@ class AkanQualityScanner {
670
747
  ];
671
748
  }
672
749
  #scanLayoutQuality(sourceFile) {
673
- const segments = sourceFile.file.split("/");
674
750
  const warnings = [];
675
- if (segments[0] === "apps" && segments.length === 3 && !appRootAllowedFiles.has(segments[2])) {
676
- warnings.push({
677
- rule: "akan.layout.app-root-file",
678
- scope: "layout",
679
- severity: "warning",
680
- file: sourceFile.file,
681
- message: `Unexpected app root file "${segments[2]}". Keep application code in conventional app folders.`
682
- });
751
+ const rootEntry = getSysRootEntry(sourceFile.file);
752
+ if (rootEntry) {
753
+ const { type, name, isDir } = rootEntry;
754
+ const allowed = isDir ? rootAllowedDirs[type].has(name) : rootAllowedFiles[type].has(name);
755
+ const kind = isDir ? "folder" : "file";
756
+ if (!allowed) {
757
+ warnings.push({
758
+ rule: `akan.layout.${type}-root-${kind}`,
759
+ scope: "layout",
760
+ severity: "warning",
761
+ file: sourceFile.file,
762
+ message: `Unexpected ${type} root ${kind} "${name}". Keep ${type} code in conventional ${type} folders.`
763
+ });
764
+ }
683
765
  }
684
- const libRootFile = getLibRootFile(sourceFile.file);
685
- if (libRootFile && !libFacetRootAllowedFiles.has(libRootFile)) {
766
+ const libFacetFile = getLibFacetRootFile(sourceFile.file);
767
+ if (libFacetFile && !isAllowedLibFacetRootFile(libFacetFile)) {
686
768
  warnings.push({
687
- rule: "akan.layout.lib-root-file",
769
+ rule: "akan.layout.lib-facet-file",
688
770
  scope: "layout",
689
771
  severity: "warning",
690
772
  file: sourceFile.file,
691
- message: `Unexpected lib root file "${libRootFile}". Keep direct lib root files limited to generated support facets.`
773
+ message: `Unexpected lib facet root file "${libFacetFile}". Keep direct lib/ root files limited to generated support facets.`
692
774
  });
693
775
  }
694
776
  const moduleUiWarning = getModuleUiWarning(sourceFile.file);
@@ -758,7 +840,7 @@ function getExportedFunctionLikes(sourceFile) {
758
840
  const declarations = [];
759
841
  const nameExempt = isPageRouteFile(sourceFile.file) || isUiComponentFile(sourceFile.file);
760
842
  for (const statement of sourceFile.sourceFile.statements) {
761
- if (ts2.isFunctionDeclaration(statement) && statement.name && isExported(statement)) {
843
+ if (ts3.isFunctionDeclaration(statement) && statement.name && isExported(statement)) {
762
844
  declarations.push({
763
845
  name: statement.name.text,
764
846
  kind: "function",
@@ -768,7 +850,7 @@ function getExportedFunctionLikes(sourceFile) {
768
850
  duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile.file, false)
769
851
  });
770
852
  }
771
- if (ts2.isClassDeclaration(statement) && statement.name && isExported(statement)) {
853
+ if (ts3.isClassDeclaration(statement) && statement.name && isExported(statement)) {
772
854
  declarations.push({
773
855
  name: statement.name.text,
774
856
  kind: "class",
@@ -778,9 +860,9 @@ function getExportedFunctionLikes(sourceFile) {
778
860
  duplicateNameExempt: nameExempt || isConventionDuplicateNameExempt(sourceFile.file, isEnumClassStatement(sourceFile.sourceFile, statement))
779
861
  });
780
862
  }
781
- if (ts2.isVariableStatement(statement) && isExported(statement)) {
863
+ if (ts3.isVariableStatement(statement) && isExported(statement)) {
782
864
  for (const declaration of statement.declarationList.declarations) {
783
- if (!ts2.isIdentifier(declaration.name) || !isFunctionLikeInitializer(declaration.initializer))
865
+ if (!ts3.isIdentifier(declaration.name) || !isFunctionLikeInitializer(declaration.initializer))
784
866
  continue;
785
867
  declarations.push({
786
868
  name: declaration.name.text,
@@ -819,14 +901,14 @@ function isInLibModule(file) {
819
901
  return (segments[0] === "apps" || segments[0] === "libs") && segments.includes("lib");
820
902
  }
821
903
  function isEnumClassStatement(sourceFile, statement) {
822
- if (!ts2.isClassDeclaration(statement))
904
+ if (!ts3.isClassDeclaration(statement))
823
905
  return false;
824
- const heritageClause = statement.heritageClauses?.find((clause) => clause.token === ts2.SyntaxKind.ExtendsKeyword);
906
+ const heritageClause = statement.heritageClauses?.find((clause) => clause.token === ts3.SyntaxKind.ExtendsKeyword);
825
907
  const expression = heritageClause?.types[0]?.expression;
826
908
  return !!expression && expression.getText(sourceFile).startsWith("enumOf(");
827
909
  }
828
910
  function getExportedClassNames(sourceFile) {
829
- return sourceFile.statements.filter((statement) => ts2.isClassDeclaration(statement) && !!statement.name).filter((statement) => isExported(statement)).map((statement) => statement.name.text);
911
+ return sourceFile.statements.filter((statement) => ts3.isClassDeclaration(statement)).filter((statement) => isExported(statement)).map((statement) => statement.name?.text).filter((name) => !!name);
830
912
  }
831
913
  function isComponentDeclarationFile(file) {
832
914
  if (!file.endsWith(".tsx"))
@@ -842,7 +924,7 @@ function isComponentDeclarationFile(file) {
842
924
  function getComponentFileDeclarations(sourceFile) {
843
925
  const reExportedNames = new Set;
844
926
  for (const statement of sourceFile.statements) {
845
- if (ts2.isExportDeclaration(statement) && statement.exportClause && ts2.isNamedExports(statement.exportClause)) {
927
+ if (ts3.isExportDeclaration(statement) && statement.exportClause && ts3.isNamedExports(statement.exportClause)) {
846
928
  for (const element of statement.exportClause.elements)
847
929
  reExportedNames.add((element.propertyName ?? element.name).text);
848
930
  }
@@ -852,19 +934,19 @@ function getComponentFileDeclarations(sourceFile) {
852
934
  const isDefaultExport = isDefaultExportStatement(statement);
853
935
  const inlineExported = isExported(statement);
854
936
  const add = (name, kind, line) => declarations.push({ name, kind, line, exported: inlineExported || reExportedNames.has(name), isDefaultExport });
855
- if (ts2.isInterfaceDeclaration(statement))
937
+ if (ts3.isInterfaceDeclaration(statement))
856
938
  add(statement.name.text, "interface", getLine(sourceFile, statement));
857
- else if (ts2.isTypeAliasDeclaration(statement))
939
+ else if (ts3.isTypeAliasDeclaration(statement))
858
940
  add(statement.name.text, "type", getLine(sourceFile, statement));
859
- else if (ts2.isEnumDeclaration(statement))
941
+ else if (ts3.isEnumDeclaration(statement))
860
942
  add(statement.name.text, "enum", getLine(sourceFile, statement));
861
- else if (ts2.isFunctionDeclaration(statement) && statement.name)
943
+ else if (ts3.isFunctionDeclaration(statement) && statement.name)
862
944
  add(statement.name.text, "function", getLine(sourceFile, statement));
863
- else if (ts2.isClassDeclaration(statement) && statement.name)
945
+ else if (ts3.isClassDeclaration(statement) && statement.name)
864
946
  add(statement.name.text, "class", getLine(sourceFile, statement));
865
- else if (ts2.isVariableStatement(statement)) {
947
+ else if (ts3.isVariableStatement(statement)) {
866
948
  for (const declaration of statement.declarationList.declarations) {
867
- if (!ts2.isIdentifier(declaration.name))
949
+ if (!ts3.isIdentifier(declaration.name))
868
950
  continue;
869
951
  const kind = isFunctionLikeInitializer(declaration.initializer) ? "function" : "variable";
870
952
  add(declaration.name.text, kind, getLine(sourceFile, declaration));
@@ -876,15 +958,15 @@ function getComponentFileDeclarations(sourceFile) {
876
958
  function getCompoundComponentNames(sourceFile) {
877
959
  const names = new Set;
878
960
  for (const statement of sourceFile.statements) {
879
- if (!ts2.isExpressionStatement(statement))
961
+ if (!ts3.isExpressionStatement(statement))
880
962
  continue;
881
963
  const { expression } = statement;
882
- if (!ts2.isBinaryExpression(expression) || expression.operatorToken.kind !== ts2.SyntaxKind.EqualsToken)
964
+ if (!ts3.isBinaryExpression(expression) || expression.operatorToken.kind !== ts3.SyntaxKind.EqualsToken)
883
965
  continue;
884
- if (!ts2.isPropertyAccessExpression(expression.left) || !isPascalCaseName(expression.left.name.text))
966
+ if (!ts3.isPropertyAccessExpression(expression.left) || !isPascalCaseName(expression.left.name.text))
885
967
  continue;
886
968
  names.add(expression.left.name.text);
887
- if (ts2.isIdentifier(expression.right) && isPascalCaseName(expression.right.text))
969
+ if (ts3.isIdentifier(expression.right) && isPascalCaseName(expression.right.text))
888
970
  names.add(expression.right.text);
889
971
  }
890
972
  return names;
@@ -904,9 +986,37 @@ function isPascalCaseName(name) {
904
986
  return /^[A-Z]/.test(name) && !/^[A-Z0-9_]+$/.test(name);
905
987
  }
906
988
  function isDefaultExportStatement(statement) {
907
- if (ts2.isExportAssignment(statement))
989
+ if (ts3.isExportAssignment(statement))
908
990
  return !statement.isExportEquals;
909
- return !!(ts2.getCombinedModifierFlags(statement) & ts2.ModifierFlags.Default);
991
+ if (!ts3.canHaveModifiers(statement))
992
+ return false;
993
+ return !!ts3.getModifiers(statement)?.some((modifier) => modifier.kind === ts3.SyntaxKind.DefaultKeyword);
994
+ }
995
+ function getBangCommentWarnings(sourceFile) {
996
+ if (!isClientReachableFile(sourceFile.file))
997
+ return [];
998
+ return findPatternLines(sourceFile.content, /(?:^|[^\s/][ \t]+)\/[*/]!/).map((line) => ({
999
+ rule: "akan.file.bang-comment-in-client",
1000
+ scope: "file",
1001
+ severity: "warning",
1002
+ file: sourceFile.file,
1003
+ line,
1004
+ message: "A `//!` or `/*!` marker survives minification and ships to the browser."
1005
+ }));
1006
+ }
1007
+ function isClientReachableFile(file) {
1008
+ if (/\.(test|spec)\.tsx?$/.test(file))
1009
+ return false;
1010
+ if (/\.(constant|store)\.ts$/.test(file))
1011
+ return true;
1012
+ if (/\.(Template|Unit|Util|View|Zone)\.tsx$/.test(file))
1013
+ return true;
1014
+ const segments = file.split("/");
1015
+ if (segments.includes("ui") || segments.includes("webkit"))
1016
+ return /\.tsx?$/.test(file);
1017
+ if (segments.includes("common"))
1018
+ return file.endsWith(".ts");
1019
+ return segments.includes("page") && file.endsWith(".tsx");
910
1020
  }
911
1021
  function getPlaceholderExportWarnings(sourceFile) {
912
1022
  if (!sourceFile.file.endsWith("/index.ts") && !sourceFile.file.endsWith("/index.tsx"))
@@ -936,7 +1046,7 @@ function getDictionaryTextWarnings(sourceFile) {
936
1046
  function getGlobalMutationWarnings(sourceFile) {
937
1047
  const warnings = [];
938
1048
  for (const statement of sourceFile.sourceFile.statements) {
939
- if (ts2.isModuleDeclaration(statement) && statement.name.getText(sourceFile.sourceFile) === "global") {
1049
+ if (ts3.isModuleDeclaration(statement) && statement.name.getText(sourceFile.sourceFile) === "global") {
940
1050
  warnings.push({
941
1051
  rule: "akan.file.global-declaration",
942
1052
  scope: "file",
@@ -946,7 +1056,7 @@ function getGlobalMutationWarnings(sourceFile) {
946
1056
  message: "Global declarations require an explicit low-level integration allowlist."
947
1057
  });
948
1058
  }
949
- if (ts2.isInterfaceDeclaration(statement) && statement.name.text === "Window") {
1059
+ if (ts3.isInterfaceDeclaration(statement) && statement.name.text === "Window") {
950
1060
  warnings.push({
951
1061
  rule: "akan.file.window-augmentation",
952
1062
  scope: "file",
@@ -956,7 +1066,7 @@ function getGlobalMutationWarnings(sourceFile) {
956
1066
  message: "Window augmentation should be isolated to approved browser integration files."
957
1067
  });
958
1068
  }
959
- if (ts2.isExpressionStatement(statement) && statement.expression.getText(sourceFile.sourceFile).includes(".prototype.")) {
1069
+ if (ts3.isExpressionStatement(statement) && statement.expression.getText(sourceFile.sourceFile).includes(".prototype.")) {
960
1070
  warnings.push({
961
1071
  rule: "akan.file.prototype-mutation",
962
1072
  scope: "file",
@@ -974,23 +1084,23 @@ function getTopLevelDeclarations(sourceFile) {
974
1084
  }
975
1085
  function getTopLevelDeclaration(sourceFile, statement) {
976
1086
  const line = getLine(sourceFile, statement);
977
- if (ts2.isClassDeclaration(statement) && statement.name) {
1087
+ if (ts3.isClassDeclaration(statement) && statement.name) {
978
1088
  return [{ name: statement.name.text, kind: "class", line, exported: isExported(statement), node: statement }];
979
1089
  }
980
- if (ts2.isFunctionDeclaration(statement) && statement.name) {
1090
+ if (ts3.isFunctionDeclaration(statement) && statement.name) {
981
1091
  return [{ name: statement.name.text, kind: "function", line, exported: isExported(statement), node: statement }];
982
1092
  }
983
- if (ts2.isInterfaceDeclaration(statement)) {
1093
+ if (ts3.isInterfaceDeclaration(statement)) {
984
1094
  return [{ name: statement.name.text, kind: "interface", line, exported: isExported(statement), node: statement }];
985
1095
  }
986
- if (ts2.isTypeAliasDeclaration(statement)) {
1096
+ if (ts3.isTypeAliasDeclaration(statement)) {
987
1097
  return [{ name: statement.name.text, kind: "type", line, exported: isExported(statement), node: statement }];
988
1098
  }
989
- if (ts2.isEnumDeclaration(statement)) {
1099
+ if (ts3.isEnumDeclaration(statement)) {
990
1100
  return [{ name: statement.name.text, kind: "enum", line, exported: isExported(statement), node: statement }];
991
1101
  }
992
- if (ts2.isVariableStatement(statement)) {
993
- return statement.declarationList.declarations.filter((declaration) => ts2.isIdentifier(declaration.name)).map((declaration) => ({
1102
+ if (ts3.isVariableStatement(statement)) {
1103
+ return statement.declarationList.declarations.filter((declaration) => ts3.isIdentifier(declaration.name)).map((declaration) => ({
994
1104
  name: declaration.name.text,
995
1105
  kind: "variable",
996
1106
  line: getLine(sourceFile, declaration),
@@ -998,7 +1108,7 @@ function getTopLevelDeclaration(sourceFile, statement) {
998
1108
  node: statement
999
1109
  }));
1000
1110
  }
1001
- if (ts2.isExportDeclaration(statement)) {
1111
+ if (ts3.isExportDeclaration(statement)) {
1002
1112
  return [{ name: "export declaration", kind: "export", line, exported: true, node: statement }];
1003
1113
  }
1004
1114
  return [];
@@ -1023,9 +1133,9 @@ function isAllowedConstantDeclaration(modelName, declaration) {
1023
1133
  return false;
1024
1134
  if ([`${modelName}Input`, `${modelName}Object`, modelName, `Light${modelName}`, `${modelName}Insight`].includes(declaration.name))
1025
1135
  return true;
1026
- if (!ts2.isClassDeclaration(declaration.node))
1136
+ if (!ts3.isClassDeclaration(declaration.node))
1027
1137
  return false;
1028
- const heritageClause = declaration.node.heritageClauses?.find((clause) => clause.token === ts2.SyntaxKind.ExtendsKeyword);
1138
+ const heritageClause = declaration.node.heritageClauses?.find((clause) => clause.token === ts3.SyntaxKind.ExtendsKeyword);
1029
1139
  const expression = heritageClause?.types[0]?.expression;
1030
1140
  return !!expression && expression.getText().startsWith("enumOf(");
1031
1141
  }
@@ -1042,7 +1152,19 @@ function getConventionDescription(suffix, modelName) {
1042
1152
  return `${modelName}Internal, ${modelName}Slice, or ${modelName}Endpoint`;
1043
1153
  return `${modelName}Store`;
1044
1154
  }
1045
- function getLibRootFile(file) {
1155
+ var sysRootTypes = { apps: "app", libs: "lib" };
1156
+ function getSysRootEntry(file) {
1157
+ const segments = file.split("/");
1158
+ const root = segments[0];
1159
+ const name = segments[2];
1160
+ if (!root || !name || segments.length < 3)
1161
+ return null;
1162
+ const type = sysRootTypes[root];
1163
+ if (!type)
1164
+ return null;
1165
+ return { type, name, isDir: segments.length > 3 };
1166
+ }
1167
+ function getLibFacetRootFile(file) {
1046
1168
  const segments = file.split("/");
1047
1169
  if ((segments[0] === "libs" || segments[0] === "apps") && segments.length === 4 && segments[2] === "lib")
1048
1170
  return segments[3];
@@ -1091,13 +1213,13 @@ function getModuleInfo(file) {
1091
1213
  return { moduleName, fileName, kind: "database" };
1092
1214
  }
1093
1215
  function isExportedConst(declaration) {
1094
- return declaration.exported && ts2.isVariableStatement(declaration.node) && (declaration.node.declarationList.flags & ts2.NodeFlags.Const) !== 0;
1216
+ return declaration.exported && ts3.isVariableStatement(declaration.node) && (declaration.node.declarationList.flags & ts3.NodeFlags.Const) !== 0;
1095
1217
  }
1096
1218
  function isExported(node) {
1097
- return !!ts2.getCombinedModifierFlags(node) && !!(ts2.getCombinedModifierFlags(node) & ts2.ModifierFlags.Export);
1219
+ return !!ts3.getCombinedModifierFlags(node) && !!(ts3.getCombinedModifierFlags(node) & ts3.ModifierFlags.Export);
1098
1220
  }
1099
1221
  function isFunctionLikeInitializer(node) {
1100
- return !!node && (ts2.isArrowFunction(node) || ts2.isFunctionExpression(node));
1222
+ return !!node && (ts3.isArrowFunction(node) || ts3.isFunctionExpression(node));
1101
1223
  }
1102
1224
  function getBodyFingerprint(sourceFile, node) {
1103
1225
  if (!node)
@@ -1119,7 +1241,7 @@ async function isDirectory(absolutePath) {
1119
1241
  }
1120
1242
  }
1121
1243
  function getScriptKind(file) {
1122
- return file.endsWith(".tsx") ? ts2.ScriptKind.TSX : ts2.ScriptKind.TS;
1244
+ return file.endsWith(".tsx") ? ts3.ScriptKind.TSX : ts3.ScriptKind.TS;
1123
1245
  }
1124
1246
  function getLine(sourceFile, node) {
1125
1247
  return sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1;