@akanjs/devkit 3.0.0-beta.2 → 3.0.0-beta.21

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 (289) hide show
  1. package/README.ko.md +2 -2
  2. package/README.md +3 -2
  3. package/abstractDoc.test.ts +6 -15
  4. package/abstractDoc.ts +6 -8
  5. package/agentsIndex.test.ts +4 -7
  6. package/agentsIndex.ts +6 -22
  7. package/akanApp/BackendImportGraph.test.ts +8 -22
  8. package/akanApp/BackendImportGraph.ts +1 -20
  9. package/akanApp/akanApp.host.test.ts +1 -3
  10. package/akanApp/akanApp.host.ts +82 -254
  11. package/akanApp/devHostPolicy.test.ts +10 -34
  12. package/akanApp/devHostPolicy.ts +12 -98
  13. package/akanConfig/akanConfig.test.ts +142 -106
  14. package/akanConfig/akanConfig.ts +147 -191
  15. package/akanConfig/types.ts +4 -3
  16. package/akanContext.ts +110 -160
  17. package/akanMcpContract.ts +28 -73
  18. package/appSelectionMemory.ts +1 -4
  19. package/applicationBuildReporter.ts +37 -5
  20. package/applicationBuildRunner.test.ts +5 -3
  21. package/applicationBuildRunner.ts +54 -61
  22. package/applicationTestPreload.ts +3 -12
  23. package/artifact/implicitRootLayout.test.ts +32 -30
  24. package/artifact/implicitRootLayout.ts +58 -106
  25. package/artifact/routeSeedIndex.test.ts +7 -6
  26. package/artifact/routeSeedIndex.ts +11 -44
  27. package/biome.base.json +32 -1
  28. package/biomeBase.ts +2 -5
  29. package/cloud/cloudApi.test.ts +202 -0
  30. package/cloud/cloudApi.ts +77 -39
  31. package/cloud/configLock.test.ts +64 -0
  32. package/cloud/configLock.ts +96 -0
  33. package/cloud/constants.ts +26 -5
  34. package/cloud/globalConfig.ts +70 -32
  35. package/codeAgent/agent/AkanCodeServices.ts +97 -0
  36. package/codeAgent/agent/AkanContextFiles.ts +94 -0
  37. package/codeAgent/agent/CodeAgent.ts +551 -0
  38. package/codeAgent/agent/CodeAgentAsks.ts +66 -0
  39. package/codeAgent/agent/CodeAgentEventMapper.ts +225 -0
  40. package/codeAgent/agent/CodeAgentGate.ts +93 -0
  41. package/codeAgent/agent/CodeAgentProxy.ts +82 -0
  42. package/codeAgent/agent/CodeAgentRpcHost.ts +103 -0
  43. package/codeAgent/agent/CodeAgentRpcListener.ts +109 -0
  44. package/codeAgent/agent/CodeAgentStreamPrinter.ts +86 -0
  45. package/codeAgent/agent/CodeAgentSuspended.ts +85 -0
  46. package/codeAgent/agent/CodeAgentUi.ts +47 -0
  47. package/codeAgent/agent/CodeMailbox.ts +148 -0
  48. package/codeAgent/agent/CodeSessionFork.ts +56 -0
  49. package/codeAgent/agent/CodeSessionIndex.ts +78 -0
  50. package/codeAgent/agent/SubagentPool.ts +214 -0
  51. package/codeAgent/agent/akanCodeModel.ts +47 -0
  52. package/codeAgent/agent/akanCodePaths.ts +31 -0
  53. package/codeAgent/agent/akanContextFiles.test.ts +114 -0
  54. package/codeAgent/agent/akanSystemPrompt.ts +46 -0
  55. package/codeAgent/agent/codeAgent.test.ts +178 -0
  56. package/codeAgent/agent/codeAgentContract.test.ts +523 -0
  57. package/codeAgent/agent/codeAgentProxy.test.ts +74 -0
  58. package/codeAgent/agent/codeAgentRpcListener.test.ts +113 -0
  59. package/codeAgent/agent/codeAgentSuspended.test.ts +47 -0
  60. package/codeAgent/agent/codeMailbox.test.ts +76 -0
  61. package/codeAgent/agent/codeSessionFork.test.ts +58 -0
  62. package/codeAgent/agent/codeSessionIndex.test.ts +77 -0
  63. package/codeAgent/agent/consoleToStderr.ts +8 -0
  64. package/codeAgent/agent/jsonLines.ts +29 -0
  65. package/codeAgent/agent/stringArg.ts +5 -0
  66. package/codeAgent/feedback/DevLogFeedback.ts +82 -0
  67. package/codeAgent/feedback/PreviewChrome.ts +82 -0
  68. package/codeAgent/feedback/PreviewFeedback.ts +46 -0
  69. package/codeAgent/feedback/PreviewView.ts +95 -0
  70. package/codeAgent/feedback/TurnFeedback.ts +98 -0
  71. package/codeAgent/feedback/VerifyFeedback.ts +40 -0
  72. package/codeAgent/feedback/previewChrome.test.ts +73 -0
  73. package/codeAgent/index.ts +34 -0
  74. package/codeAgent/skills/akan-code/SKILL.md +130 -0
  75. package/codeAgent/skills/akan-debug/SKILL.md +42 -0
  76. package/codeAgent/skills/akan-deps/SKILL.md +50 -0
  77. package/codeAgent/skills/akan-err/SKILL.md +39 -0
  78. package/codeAgent/skills/akan-module/SKILL.md +45 -0
  79. package/codeAgent/skills/akan-scaffold/SKILL.md +76 -0
  80. package/codeAgent/skills/akan-scalar/SKILL.md +52 -0
  81. package/codeAgent/skills/akan-service/SKILL.md +34 -0
  82. package/codeAgent/skills/akan-store/SKILL.md +67 -0
  83. package/codeAgent/skills/akan-ui/SKILL.md +63 -0
  84. package/codeAgent/skills/akan-validate/SKILL.md +44 -0
  85. package/codeAgent/tools/AkanCli.ts +50 -0
  86. package/codeAgent/tools/AkanCodePlugins.ts +136 -0
  87. package/codeAgent/tools/AkanEditScope.ts +48 -0
  88. package/codeAgent/tools/AkanEnvKeys.ts +50 -0
  89. package/codeAgent/tools/AkanToolPack.ts +92 -0
  90. package/codeAgent/tools/AkanVerifier.ts +48 -0
  91. package/codeAgent/tools/AskToolPack.ts +99 -0
  92. package/codeAgent/tools/MailToolPack.ts +76 -0
  93. package/codeAgent/tools/McpClient.ts +187 -0
  94. package/codeAgent/tools/McpOAuth.ts +233 -0
  95. package/codeAgent/tools/McpOAuthLoopback.ts +64 -0
  96. package/codeAgent/tools/McpServerConfig.ts +129 -0
  97. package/codeAgent/tools/McpSignIn.ts +158 -0
  98. package/codeAgent/tools/McpTokenStore.ts +81 -0
  99. package/codeAgent/tools/McpToolPack.ts +199 -0
  100. package/codeAgent/tools/SessionToolPack.ts +91 -0
  101. package/codeAgent/tools/WebToolPack.ts +147 -0
  102. package/codeAgent/tools/akanCodePlugins.test.ts +677 -0
  103. package/codeAgent/tools/askToolPack.test.ts +116 -0
  104. package/codeAgent/tools/mcpOAuth.test.ts +612 -0
  105. package/codeAgent/tools/mcpServerConfig.test.ts +212 -0
  106. package/codegenLock.test.ts +4 -13
  107. package/codegenLock.ts +3 -17
  108. package/commandDecorators/argMeta.ts +1 -5
  109. package/commandDecorators/camelToKebabCase.ts +1 -0
  110. package/commandDecorators/command.ts +46 -102
  111. package/commandDecorators/commandBuilder.ts +30 -61
  112. package/commandDecorators/commandDecorators.test.ts +2 -10
  113. package/commandDecorators/dependencyBuilder.ts +10 -1
  114. package/commandDecorators/helpFormatter.ts +68 -145
  115. package/commandDecorators/index.ts +0 -2
  116. package/commandDecorators/targetMeta.ts +9 -7
  117. package/createTunnel.ts +7 -14
  118. package/dependencyScanner.test.ts +4 -16
  119. package/dependencyScanner.ts +31 -80
  120. package/devkitUtils.test.ts +48 -20
  121. package/executors.linkFallback.test.ts +103 -0
  122. package/executors.test.ts +132 -106
  123. package/executors.ts +195 -496
  124. package/fileEditor.ts +9 -37
  125. package/{getDirname.test.ts → fileSys.test.ts} +5 -3
  126. package/fileSys.ts +6 -8
  127. package/formSetterScanner.ts +3 -16
  128. package/frontendBuild/allRoutesBuilder.ts +7 -21
  129. package/frontendBuild/autoImportSync.test.ts +27 -38
  130. package/frontendBuild/autoImportSync.ts +31 -65
  131. package/frontendBuild/buildRouteClient.test.ts +62 -37
  132. package/frontendBuild/bundleDefine.ts +12 -0
  133. package/frontendBuild/clientBuildTypes.ts +5 -36
  134. package/frontendBuild/clientEntriesBundler.ts +9 -40
  135. package/frontendBuild/clientEntryDiscovery.ts +6 -41
  136. package/frontendBuild/csrArtifactBuilder.ts +6 -25
  137. package/frontendBuild/cssCandidateCache.test.ts +0 -6
  138. package/frontendBuild/cssCandidateCache.ts +6 -41
  139. package/frontendBuild/cssCompiler.ts +29 -78
  140. package/frontendBuild/cssImportResolver.ts +6 -19
  141. package/frontendBuild/devChangePlanner.ts +7 -10
  142. package/frontendBuild/devGeneratedIndexSync.test.ts +12 -27
  143. package/frontendBuild/devGeneratedIndexSync.ts +1 -4
  144. package/frontendBuild/fontOptimizer.test.ts +6 -14
  145. package/frontendBuild/fontOptimizer.ts +15 -72
  146. package/frontendBuild/fontPruner.test.ts +5 -10
  147. package/frontendBuild/fontPruner.ts +5 -20
  148. package/frontendBuild/frontendBuild.test.ts +46 -69
  149. package/frontendBuild/hmrChangeClassifier.ts +2 -2
  150. package/frontendBuild/hmrWatcher.test.ts +8 -32
  151. package/frontendBuild/hmrWatcher.ts +14 -71
  152. package/frontendBuild/pagesBundleBuilder.ts +4 -29
  153. package/frontendBuild/precompressArtifacts.ts +5 -18
  154. package/frontendBuild/routeClientBuilder.ts +23 -46
  155. package/frontendBuild/routesManifestArtifactSerializer.ts +5 -36
  156. package/frontendBuild/sourceMtimeIndex.test.ts +41 -97
  157. package/frontendBuild/sourceMtimeIndex.ts +19 -130
  158. package/frontendBuild/ssrBaseArtifactBuilder.ts +2 -8
  159. package/frontendBuild/styleContract.ts +1 -8
  160. package/frontendBuild/themeValidator.ts +4 -26
  161. package/frontendBuild/watchRootResolver.test.ts +23 -42
  162. package/frontendBuild/watchRootResolver.ts +5 -27
  163. package/getRelatedCnsts.ts +12 -92
  164. package/incrementalBuilder/buildBatch.proc.ts +29 -58
  165. package/incrementalBuilder/buildBatchProtocol.ts +8 -36
  166. package/incrementalBuilder/buildBatchRunner.test.ts +34 -0
  167. package/incrementalBuilder/buildBatchRunner.ts +10 -31
  168. package/incrementalBuilder/builderChannel.test.ts +24 -49
  169. package/incrementalBuilder/builderChannel.ts +6 -37
  170. package/incrementalBuilder/builderRequestRouter.test.ts +0 -8
  171. package/incrementalBuilder/builderRequestRouter.ts +5 -24
  172. package/incrementalBuilder/devWatchBatch.test.ts +21 -24
  173. package/incrementalBuilder/incrementalBuilder.host.test.ts +18 -55
  174. package/incrementalBuilder/incrementalBuilder.host.ts +18 -76
  175. package/incrementalBuilder/incrementalBuilder.proc.test.ts +81 -0
  176. package/incrementalBuilder/incrementalBuilder.proc.ts +49 -161
  177. package/index.ts +5 -19
  178. package/integration/devResourceProbe.ts +50 -56
  179. package/integration/devStability.integration.test.ts +47 -194
  180. package/integration/devStabilityHarness.test.ts +13 -28
  181. package/integration/devStabilityHarness.ts +65 -330
  182. package/integration/ssrMemoryProbe.ts +41 -167
  183. package/libSource.test.ts +4 -15
  184. package/libSource.ts +19 -31
  185. package/lint/__fixtures__/no-document-cookie/bad.tsx +4 -0
  186. package/lint/__fixtures__/no-document-cookie/good.tsx +7 -0
  187. package/lint/__fixtures__/no-web-only-api-outside-webkit/bad.tsx +7 -0
  188. package/lint/__fixtures__/no-web-only-api-outside-webkit/good.tsx +11 -0
  189. package/lint/__fixtures__/no-web-storage/bad.tsx +6 -0
  190. package/lint/__fixtures__/no-web-storage/good.tsx +7 -0
  191. package/lint/gritRules.test.ts +8 -24
  192. package/lint/no-deep-internal-import.grit +2 -2
  193. package/lint/no-document-cookie.grit +29 -0
  194. package/lint/no-redeclare-predefined-endpoint.grit +2 -1
  195. package/lint/no-web-only-api-outside-webkit.grit +44 -0
  196. package/lint/no-web-storage.grit +30 -0
  197. package/linter.test.ts +1 -2
  198. package/linter.ts +26 -116
  199. package/mobile/index.ts +6 -0
  200. package/mobile/mobileTarget.ts +16 -13
  201. package/mobile/nativeApi.test.ts +30 -0
  202. package/mobile/nativeApi.ts +40 -0
  203. package/mobile/nativeApp.test.ts +85 -0
  204. package/mobile/nativeApp.ts +210 -0
  205. package/mobile/nativeConfig.test.ts +199 -0
  206. package/mobile/nativeConfig.ts +184 -0
  207. package/mobile/nativeWebDir.test.ts +80 -0
  208. package/mobile/nativeWebDir.ts +62 -0
  209. package/mobile/placeholderAppId.test.ts +13 -0
  210. package/mobile/placeholderAppId.ts +16 -0
  211. package/mobile/usageDescriptions.test.ts +27 -0
  212. package/mobile/usageDescriptions.ts +24 -0
  213. package/package.json +10 -10
  214. package/packageExports.test.ts +3 -18
  215. package/packageExportsMap.ts +3 -19
  216. package/piDependencyPins.test.ts +46 -0
  217. package/platformTest/BunTestReport.test.ts +60 -0
  218. package/platformTest/BunTestReport.ts +65 -0
  219. package/platformTest/IdleWatchedProcess.test.ts +56 -0
  220. package/platformTest/IdleWatchedProcess.ts +73 -0
  221. package/platformTest/LinuxDockerTarget.ts +105 -0
  222. package/platformTest/PlatformTestRun.test.ts +64 -0
  223. package/platformTest/PlatformTestRun.ts +141 -0
  224. package/platformTest/PlatformTestTarget.ts +142 -0
  225. package/platformTest/TestSnapshot.test.ts +72 -0
  226. package/platformTest/TestSnapshot.ts +103 -0
  227. package/platformTest/WindowsSshTarget.ts +151 -0
  228. package/prompter.ts +3 -13
  229. package/qualityScanner.test.ts +9 -26
  230. package/qualityScanner.ts +200 -286
  231. package/recipeScanner.test.ts +7 -12
  232. package/recipeScanner.ts +9 -38
  233. package/repoIdentity.ts +2 -9
  234. package/routeSourceValidator.test.ts +0 -1
  235. package/routeSourceValidator.ts +7 -42
  236. package/scanInfo.ts +91 -225
  237. package/selectModel.ts +1 -2
  238. package/semver.ts +3 -5
  239. package/slicePlanner.test.ts +6 -24
  240. package/slicePlanner.ts +11 -32
  241. package/spinner.test.ts +3 -8
  242. package/spinner.ts +4 -16
  243. package/sshTunnel.ts +1 -6
  244. package/ssrScanner.test.ts +1 -6
  245. package/ssrScanner.ts +103 -113
  246. package/stripAnsi.ts +3 -0
  247. package/subspace.test.ts +30 -25
  248. package/subspace.ts +81 -115
  249. package/subspaceConfig.ts +11 -9
  250. package/testHelpers.ts +194 -0
  251. package/transforms/asyncDefaultExportDetector.ts +3 -11
  252. package/transforms/barrelAnalyzer.ts +43 -135
  253. package/transforms/barrelImportsPlugin.ts +38 -175
  254. package/transforms/externalizeFrameworkPlugin.test.ts +39 -118
  255. package/transforms/externalizeFrameworkPlugin.ts +13 -87
  256. package/transforms/moduleSyntax.ts +32 -0
  257. package/transforms/rscUseClientTransform.ts +35 -20
  258. package/transforms/transforms.test.ts +153 -44
  259. package/transforms/tsconfigPackageResolver.test.ts +6 -24
  260. package/transforms/useClientBundlePlugin.ts +2 -22
  261. package/typeChecker.ts +7 -63
  262. package/types.ts +1 -0
  263. package/uploadRelease.ts +10 -25
  264. package/workflow/artifacts.ts +18 -0
  265. package/workflow/executor.test.ts +1 -12
  266. package/workflow/executor.ts +101 -110
  267. package/workflow/index.ts +0 -1
  268. package/workflow/moduleIndex.test.ts +4 -15
  269. package/workflow/moduleIndex.ts +9 -49
  270. package/workflow/plan.ts +18 -25
  271. package/workflow/render.ts +80 -96
  272. package/workflow/rolloutGate.test.ts +1 -1
  273. package/workflow/source.ts +52 -69
  274. package/workflow/sourceAst.ts +50 -0
  275. package/workspaceLayout.test.ts +13 -3
  276. package/workspaceLayout.ts +20 -23
  277. package/abstractCompactor.ts +0 -112
  278. package/aiEditor.test.ts +0 -60
  279. package/aiEditor.ts +0 -387
  280. package/applicationReleasePackager.ts +0 -209
  281. package/capacitorApp.test.ts +0 -372
  282. package/capacitorApp.ts +0 -1648
  283. package/commandDecorators/commandMeta.ts +0 -7
  284. package/commandDecorators/types.ts +0 -10
  285. package/getDirname.ts +0 -4
  286. package/guideline.ts +0 -19
  287. package/local/optimize-resource/ipcprobe/child.ts +0 -1
  288. package/local/optimize-resource/ipcprobe/parent.ts +0 -11
  289. package/workflow/primitive.ts +0 -59
@@ -0,0 +1,50 @@
1
+ import ts from "typescript";
2
+
3
+ export const sourceFileFor = (fileName: string, content: string) =>
4
+ ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
5
+
6
+ export const nodeName = (node: ts.PropertyName | ts.BindingName | undefined) => {
7
+ if (!node) return null;
8
+ if (ts.isIdentifier(node) || ts.isStringLiteral(node) || ts.isNumericLiteral(node)) return node.text;
9
+ return null;
10
+ };
11
+
12
+ export const propertyName = (node: ts.ObjectLiteralElementLike) =>
13
+ ts.isPropertyAssignment(node) || ts.isShorthandPropertyAssignment(node) || ts.isMethodDeclaration(node)
14
+ ? nodeName(node.name)
15
+ : null;
16
+
17
+ export const expressionName = (expression: ts.Expression): string | null => {
18
+ if (ts.isIdentifier(expression)) return expression.text;
19
+ if (ts.isPropertyAccessExpression(expression)) return expression.name.text;
20
+ if (ts.isCallExpression(expression)) return expressionName(expression.expression);
21
+ if (ts.isAsExpression(expression)) return expressionName(expression.expression);
22
+ return null;
23
+ };
24
+
25
+ export const callExpressionName = (node: ts.CallExpression) =>
26
+ ts.isPropertyAccessExpression(node.expression) ? node.expression.name.text : expressionName(node.expression);
27
+
28
+ export const firstObjectReturnedByArrow = (node: ts.Node): ts.ObjectLiteralExpression | null => {
29
+ if (!ts.isArrowFunction(node) && !ts.isFunctionExpression(node)) return null;
30
+ if (ts.isObjectLiteralExpression(node.body)) return node.body;
31
+ if (ts.isParenthesizedExpression(node.body) && ts.isObjectLiteralExpression(node.body.expression)) {
32
+ return node.body.expression;
33
+ }
34
+ if (!ts.isBlock(node.body)) return null;
35
+ for (const statement of node.body.statements) {
36
+ if (ts.isReturnStatement(statement) && statement.expression && ts.isObjectLiteralExpression(statement.expression)) {
37
+ return statement.expression;
38
+ }
39
+ }
40
+ return null;
41
+ };
42
+
43
+ const isViaCall = (expression: ts.Expression) =>
44
+ ts.isCallExpression(expression) && expressionName(expression.expression) === "via";
45
+
46
+ export const heritageCall = (node: ts.ClassDeclaration) => {
47
+ const heritage = node.heritageClauses?.flatMap((clause) => [...clause.types]) ?? [];
48
+ const expression = heritage.find((clause) => isViaCall(clause.expression))?.expression;
49
+ return expression && ts.isCallExpression(expression) ? expression : null;
50
+ };
@@ -6,6 +6,7 @@ import {
6
6
  isScannedRootEntry,
7
7
  libRootAllowedDirs,
8
8
  libRootAllowedFiles,
9
+ rootEntryHintOf,
9
10
  } from "./workspaceLayout";
10
11
 
11
12
  describe("app root layout allowlist", () => {
@@ -15,7 +16,7 @@ describe("app root layout allowlist", () => {
15
16
  });
16
17
 
17
18
  test("admits every documented app root folder", () => {
18
- for (const dirname of ["mobile", "plugin", "secrets", "srvkit", "webkit"]) {
19
+ for (const dirname of [".akan", "plugin", "script", "secrets", "srvkit", "webkit"]) {
19
20
  expect(appRootAllowedDirs.has(dirname)).toBe(true);
20
21
  }
21
22
  });
@@ -25,6 +26,15 @@ describe("app root layout allowlist", () => {
25
26
  expect(appRootAllowedDirs.has("base")).toBe(false);
26
27
  });
27
28
 
29
+ test("names what a Capacitor app kept in its root as a leftover, not an unknown entry", () => {
30
+ for (const name of ["android", "ios", "mobile", "capacitor.config.ts", "capacitor.config.json"]) {
31
+ expect(appRootAllowedFiles.has(name) || appRootAllowedDirs.has(name)).toBe(false);
32
+ expect(rootEntryHintOf("app", name)).toContain(".akan/mobile/<target>");
33
+ }
34
+ expect(rootEntryHintOf("app", "base")).toBeNull();
35
+ expect(rootEntryHintOf("lib", "ios")).toBeNull();
36
+ });
37
+
28
38
  test("skips dotfile artifacts the sync glob never sees, but keeps .akan", () => {
29
39
  expect(isScannedRootEntry("app", ".DS_Store")).toBe(false);
30
40
  expect(isScannedRootEntry("app", ".akan")).toBe(true);
@@ -48,10 +58,10 @@ describe("lib root layout allowlist", () => {
48
58
  });
49
59
 
50
60
  test("rejects the app-only run and mobile entries", () => {
51
- for (const filename of ["main.ts", "capacitor.config.ts", "akan.app.json"]) {
61
+ for (const filename of ["main.ts", "akan.app.json"]) {
52
62
  expect(libRootAllowedFiles.has(filename)).toBe(false);
53
63
  }
54
- for (const dirname of [".akan", "android", "ios", "mobile", "script", "secrets"]) {
64
+ for (const dirname of [".akan", "script", "secrets"]) {
55
65
  expect(libRootAllowedDirs.has(dirname)).toBe(false);
56
66
  }
57
67
  });
@@ -1,21 +1,13 @@
1
- /**
2
- * App/lib 루트 레이아웃 허용 목록 — 단일 소스.
3
- *
4
- * 같은 규칙을 scanInfo(`akan sync`, hard error) · akanContext(`akan doctor`, diagnostic) ·
5
- * qualityScanner(`akan quality scan`, warning) 세 곳이 각자 복사해 두면서 실제로 어긋났다
6
- * (스코프 AGENTS.md/CLAUDE.md 는 sync 만 허용, `plugin` 은 문서에만, `secrets` 는 doctor 만 거부).
7
- * 규칙을 추가할 때는 이 파일만 고치고, 루트 AGENTS.md 의 목록도 같이 갱신한다.
8
- */
1
+ // The one source of the app/lib root allowlists (sync, doctor and quality scan read it); mirror a change into the
2
+ // root AGENTS.md list.
9
3
 
10
4
  export type SysType = "app" | "lib";
11
5
 
12
6
  export const appRootAllowedFiles = new Set([
13
- // 스코프 에이전트 가이드 — scan(write) 이 유지하는 색인 + 마커 밖 hand-written 내용 (agentsIndex.ts)
14
7
  "AGENTS.md",
15
8
  "CLAUDE.md",
16
9
  "akan.app.json",
17
10
  "akan.config.ts",
18
- "capacitor.config.ts",
19
11
  "client.ts",
20
12
  "main.ts",
21
13
  "package.json",
@@ -26,12 +18,9 @@ export const appRootAllowedFiles = new Set([
26
18
 
27
19
  export const appRootAllowedDirs = new Set([
28
20
  ".akan",
29
- "android",
30
21
  "common",
31
22
  "env",
32
- "ios",
33
23
  "lib",
34
- "mobile",
35
24
  "page",
36
25
  "plugin",
37
26
  "private",
@@ -43,12 +32,7 @@ export const appRootAllowedDirs = new Set([
43
32
  "webkit",
44
33
  ]);
45
34
 
46
- /**
47
- * 라이브러리 루트는 앱 루트에서 실행/모바일 전용 항목(`main.ts`, `capacitor.config.ts`, `.akan`,
48
- * `android`, `ios`, `mobile`, `script`, `secrets`)을 뺀 집합이다 — 라이브러리는 부팅되지도, 패키징되지도
49
- * 않는다. `index.ts` 는 lib 에만 생성되고, `README.md` / `tsconfig.spec.json` 은 라이브러리가 패키지로
50
- * 배포되기 때문에 남는다. `public` / `private` 은 syncAssets 가 앱으로 심링크하므로 라이브러리도 가진다.
51
- */
35
+ // A library is never booted or packaged as an app, so the run/mobile entries are out; it is published, so README stays.
52
36
  export const libRootAllowedFiles = new Set([
53
37
  "AGENTS.md",
54
38
  "CLAUDE.md",
@@ -98,9 +82,22 @@ const libFacetRootTestPattern = /^[A-Za-z][A-Za-z0-9_-]*\.signal\.(test|spec)\.(
98
82
  export const isAllowedLibFacetRootFile = (filename: string) =>
99
83
  libFacetRootAllowedFiles.has(filename) || libFacetRootTestPattern.test(filename);
100
84
 
101
- /**
102
- * scanSync 는 루트를 `Bun.Glob("*")` 로 읽어 dotfile 을 아예 보지 못한다. 디렉터리를 직접 읽는
103
- * doctor 가 그 차이만큼 `.DS_Store` 같은 툴 산출물을 에러로 올리므로 같은 기준으로 걸러낸다.
104
- */
85
+ //* What a Capacitor app kept in its root. The native runtime generates its projects under `.akan/mobile/<target>`, so
86
+ //* these are named as leftovers instead of as unknown entries.
87
+ const retiredAppRootEntries = new Set([
88
+ "android",
89
+ "ios",
90
+ "mobile",
91
+ "capacitor.config.ts",
92
+ "capacitor.config.js",
93
+ "capacitor.config.json",
94
+ ]);
95
+
96
+ export const rootEntryHintOf = (type: SysType, name: string) =>
97
+ type === "app" && retiredAppRootEntries.has(name)
98
+ ? "a Capacitor-era entry; the native runtime generates its projects under .akan/mobile/<target>, so delete it"
99
+ : null;
100
+
101
+ // scanSync reads roots through `Bun.Glob("*")`, which skips dotfiles, so doctor skips them the same way.
105
102
  export const isScannedRootEntry = (type: SysType, name: string) =>
106
103
  !name.startsWith(".") || rootAllowedDirs[type].has(name);
@@ -1,112 +0,0 @@
1
- import { Logger } from "akanjs/common";
2
- import chalk from "chalk";
3
- import { AbstractDoc, type AbstractKind } from "./abstractDoc";
4
- import { AiSession } from "./aiEditor";
5
- import type { SysExecutor } from "./executors";
6
-
7
- export interface AbstractCompactOptions {
8
- module?: string | null;
9
- minLines?: number;
10
- interactive?: boolean;
11
- }
12
-
13
- export interface AbstractCompactReport {
14
- path: string;
15
- beforeLines: number;
16
- afterLines: number;
17
- status: "compacted" | "unchanged" | "failed";
18
- }
19
-
20
- /** Rewrites bloated `*.abstract.md` files down to the invariants their source files cannot show. */
21
- export class AbstractCompactor {
22
- static readonly #reviewRequest = `Review the compacted file you just wrote against the original.
23
- - Did you drop an invariant, a security reason, or a workflow step that the source files cannot show by themselves? Restore it.
24
- - Did you keep anything that only restates code, scaffold wording, or history? Remove it.
25
- - Is it in the same language as the original, within the line budget, and one short line per bullet?
26
- Respond with exactly one \`\`\`markdown code block holding the corrected file and nothing else. If nothing needs to change, repeat the file unchanged.`;
27
-
28
- #sys: SysExecutor;
29
- #minLines: number;
30
- #interactive: boolean;
31
- constructor(
32
- sys: SysExecutor,
33
- { minLines = AbstractDoc.compactMinLines, interactive = false }: AbstractCompactOptions = {},
34
- ) {
35
- this.#sys = sys;
36
- this.#minLines = minLines;
37
- this.#interactive = interactive;
38
- }
39
- async compactAll({ module }: { module?: string | null } = {}) {
40
- const docs = await AbstractDoc.findAll(this.#sys, { module });
41
- const targets = docs.filter((doc) => doc.lineCount > this.#minLines);
42
- const reports: AbstractCompactReport[] = [];
43
- // One file at a time: each doc gets its own AI session, and parallel runs would interleave the
44
- // streamed response with each other and with the interactive confirm prompt.
45
- for (const doc of targets) reports.push(await this.compact(doc));
46
- return { scanned: docs.length, reports };
47
- }
48
- async compact(doc: AbstractDoc): Promise<AbstractCompactReport> {
49
- const session = new AiSession("compactAbstract", {
50
- workspace: this.#sys.workspace,
51
- cacheKey: `${this.#sys.name}-${doc.moduleName}`,
52
- });
53
- const approve = !this.#interactive;
54
- const compacted = await session.editMarkdown(this.#request(doc), { approve });
55
- const reviewed = await session.editMarkdown(AbstractCompactor.#reviewRequest, { approve });
56
- // The review answers in prose when it finds nothing to fix, so the first compaction is the fallback.
57
- const next = [reviewed, compacted]
58
- .map((candidate) => candidate.trim())
59
- .find((candidate) => doc.canReplaceWith(candidate));
60
- const beforeLines = doc.lineCount;
61
- if (!next) {
62
- Logger.rawLog(chalk.yellow(`${doc.path}: the editor returned no shorter abstract, keeping the current file`));
63
- return { path: doc.path, beforeLines, afterLines: beforeLines, status: "failed" };
64
- }
65
- if (next === doc.content.trim())
66
- return { path: doc.path, beforeLines, afterLines: beforeLines, status: "unchanged" };
67
- const content = `${next}\n`;
68
- await this.#sys.writeFile(doc.path, content);
69
- return { path: doc.path, beforeLines, afterLines: AbstractDoc.lineCountOf(content), status: "compacted" };
70
- }
71
- #targetShape(kind: AbstractKind) {
72
- if (kind === "other")
73
- return " - keep the headings that still carry information and drop the rest; do not impose a new structure";
74
- return [
75
- " - `# <name> Abstract` title line",
76
- " - one declarative sentence naming what this module owns",
77
- " - `## Rules` — two to five bullets, each an invariant the code cannot show by itself",
78
- " - optional `## Workflow` — the lifecycle as an arrow chain (`draft -> signed -> active`) or a few bullets",
79
- ].join("\n");
80
- }
81
- #request(doc: AbstractDoc) {
82
- return `You are compacting an Akan.js abstract file.
83
-
84
- An abstract is the summary a coding agent reads before changing a module. Repeated edits have made this one
85
- bloated, and it has to shrink back to what the source files cannot show by themselves.
86
-
87
- # Target file
88
- ${this.#sys.type}s/${this.#sys.name}/${doc.path} (${doc.kind} module "${doc.moduleName}", ${doc.lineCount} lines)
89
-
90
- # Source files in the same folder
91
- ${doc.siblingFiles.join(", ") || "none"}
92
-
93
- # Current content
94
- \`\`\`markdown
95
- ${doc.content}
96
- \`\`\`
97
-
98
- # Rules for the compacted file
99
- - Write it in the SAME language as the current content. Never translate.
100
- - Keep every invariant, constraint, security reason, and workflow step that the source files cannot show by
101
- themselves. Merge duplicates instead of dropping either one.
102
- - Delete what the code already states: field lists, types, labels, signatures, file lists, and imports.
103
- - Delete scaffold and placeholder wording, changelog or migration history, TODOs, and any instruction about
104
- reading or updating this file.
105
- - Never invent a rule that the current content does not state.
106
- - Keep every bullet to one short line, and stay under ${AbstractDoc.compactMinLines} lines in total.
107
- - Shape:
108
- ${this.#targetShape(doc.kind)}
109
-
110
- Respond with exactly one \`\`\`markdown code block holding the whole new file and nothing else.`;
111
- }
112
- }
package/aiEditor.test.ts DELETED
@@ -1,60 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
- import { parseTypescriptFileBlocks, preserveTypescriptResponseContent } from "./aiEditor";
3
-
4
- describe("parseTypescriptFileBlocks", () => {
5
- test("parses TypeScript file blocks with common fence variants", () => {
6
- const writes = parseTypescriptFileBlocks(`
7
- \`\`\`ts
8
-
9
- // File: lib/car/car.constant.ts
10
-
11
- export const car = "car";
12
- \`\`\`
13
-
14
- \`\`\`tsx
15
- // File: lib/car/Car.Unit.tsx
16
- export const CarUnit = () => null;
17
- \`\`\`
18
- `);
19
-
20
- expect(writes).toEqual([
21
- {
22
- filePath: "lib/car/car.constant.ts",
23
- content: 'export const car = "car";',
24
- },
25
- {
26
- filePath: "lib/car/Car.Unit.tsx",
27
- content: "export const CarUnit = () => null;",
28
- },
29
- ]);
30
- });
31
-
32
- test("keeps previous code response when validation responds with prose only", () => {
33
- const previousContent = `
34
- \`\`\`typescript
35
- // File: lib/car/car.constant.ts
36
- export const car = "car";
37
- \`\`\`
38
- `;
39
- const nextContent = "The generated file meets all specified requirements. No rewrite is necessary.";
40
-
41
- expect(preserveTypescriptResponseContent(previousContent, nextContent)).toBe(previousContent);
42
- });
43
-
44
- test("uses next code response when validation rewrites with parseable files", () => {
45
- const previousContent = `
46
- \`\`\`typescript
47
- // File: lib/car/car.constant.ts
48
- export const car = "car";
49
- \`\`\`
50
- `;
51
- const nextContent = `
52
- \`\`\`typescript
53
- // File: lib/car/car.constant.ts
54
- export const car = "updated";
55
- \`\`\`
56
- `;
57
-
58
- expect(preserveTypescriptResponseContent(previousContent, nextContent)).toBe(nextContent);
59
- });
60
- });