@akanjs/cli 3.0.0-beta.9 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (224) hide show
  1. package/.build-stamp +1 -1
  2. package/CodeAgent-zfab7pkn.js +9 -0
  3. package/CodeAgentRpcHost-p7h6n2hp.js +7 -0
  4. package/CodeAgentRpcListener-7p7z5dd7.js +97 -0
  5. package/CodeTui-0zhnr0pw.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-aja6z9mn.js} +8 -9
  10. package/akanCode.js +102 -0
  11. package/application.command-049ehgx3.js +246 -0
  12. package/{applicationBuildRunner-kxwbssgn.js → applicationBuildRunner-75n5rpwp.js} +121 -77
  13. package/buildBatch.proc.js +120 -32
  14. package/cloud.command-gw4kqxt8.js +95 -0
  15. package/cloud.script-c723cpcb.js +20 -0
  16. package/code.command-x9t6z5nw.js +154 -0
  17. package/commandManifest.json +1 -1
  18. package/consoleToStderr-h5bryj94.js +7 -0
  19. package/context.command-yfbe1rtd.js +48 -0
  20. package/context.runner-erfe68j5.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-kq9gp690.js +42 -0
  25. package/guidelines/agentRule/agentRule.instruction.md +154 -26
  26. package/guidelines/conventions/conventions.instruction.md +138 -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-2tv3fdx4.js → index-150s07n8.js} +1230 -1459
  36. package/{index-vyvre9en.js → index-25fvrxmy.js} +6 -2
  37. package/{index-kcxmv48c.js → index-2ahj896a.js} +45 -79
  38. package/index-2wc41k5w.js +49 -0
  39. package/index-3hx1z96c.js +87 -0
  40. package/{index-q0y2jq9j.js → index-52w0fvh8.js} +21 -4
  41. package/{index-04bk599g.js → index-5g4rkrvt.js} +10 -17
  42. package/index-5pvxf7z0.js +53 -0
  43. package/index-5q14pwzd.js +69 -0
  44. package/{index-vxtad5bd.js → index-66yspb67.js} +5 -8
  45. package/index-7md2g9vw.js +6 -0
  46. package/index-7p4c0yer.js +1058 -0
  47. package/{index-d43r08tf.js → index-8b639zes.js} +77 -150
  48. package/{index-ktb5njgy.js → index-8kvy8qb4.js} +49 -99
  49. package/index-94s080qm.js +266 -0
  50. package/index-9dp031by.js +12 -0
  51. package/{index-0g7r8xz3.js → index-a37by9hn.js} +114 -232
  52. package/{index-k2j1hc4r.js → index-b95yhqjr.js} +12 -12
  53. package/{index-3d9y066c.js → index-bjwxs904.js} +9 -8
  54. package/{index-2xp0kfkt.js → index-br8pkrk1.js} +37 -25
  55. package/index-c14nsvnv.js +700 -0
  56. package/index-c6eggbee.js +123 -0
  57. package/index-d2242ksy.js +99 -0
  58. package/{index-92zztqy1.js → index-dy0jx9ay.js} +2 -17
  59. package/{index-a64esmtb.js → index-fkvb79qe.js} +523 -1022
  60. package/index-h54yj9wr.js +1119 -0
  61. package/{index-by5gpp8x.js → index-hj6w4ka1.js} +2 -1
  62. package/{index-y6n8nmny.js → index-kn5d4jmg.js} +75 -203
  63. package/index-m3xsb1ms.js +4300 -0
  64. package/{index-gyd220p2.js → index-mb59b8x0.js} +554 -577
  65. package/{index-j9yhg404.js → index-mzjb6zp4.js} +4 -7
  66. package/index-p6pbz9n5.js +25 -0
  67. package/{index-sj5vxr8f.js → index-qe71g4ze.js} +983 -898
  68. package/index-rfcz04w9.js +187 -0
  69. package/{index-hwkygn9s.js → index-senscydg.js} +331 -36
  70. package/{index-ffvk10zz.js → index-vs8mefhy.js} +107 -241
  71. package/index-wa5jbxj1.js +760 -0
  72. package/index-y5ga5w9t.js +2729 -0
  73. package/{index-9077wzd2.js → index-y7hx1ygz.js} +43 -26
  74. package/{index-h7yw2z9n.js → index-zzvvc845.js} +8 -14
  75. package/index.js +23 -22
  76. package/{library.command-qzzbj6d8.js → library.command-keqjevpp.js} +4 -5
  77. package/{localRegistry.command-vyrgg4xw.js → localRegistry.command-pydeq5zf.js} +23 -43
  78. package/{module.command-rq5hq3ax.js → module.command-dkrnqx3v.js} +8 -12
  79. package/{package.command-d9hd6v9n.js → package.command-wmc0ys5y.js} +6 -7
  80. package/package.json +15 -7
  81. package/{page.command-126d56te.js → page.command-tf3erhrv.js} +4 -5
  82. package/{primitive.command-taxd1538.js → primitive.command-7hqpegj4.js} +9 -23
  83. package/prompter-76k56b37.js +8 -0
  84. package/{quality.command-6gsna0a3.js → quality.command-8122axq3.js} +205 -377
  85. package/{recipeScanner-fpagtgc1.js → recipeScanner-4b69ybe0.js} +1 -1
  86. package/{repair.command-tq2dgy72.js → repair.command-mcy12h0n.js} +11 -35
  87. package/{routeSourceValidator-apyqw7wk.js → routeSourceValidator-7ycnfz0e.js} +0 -6
  88. package/{scalar.command-3bcmrrkv.js → scalar.command-vvvbzttc.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-pzvqfy5h.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-82zz5xnq.js +129 -0
  155. package/{typeChecker-3xgrzc2v.js → typeChecker-px49mezc.js} +1 -1
  156. package/typecheck.proc.js +1 -1
  157. package/workflow.command-y8x3kgjv.js +79 -0
  158. package/{workspace.command-06wvstgr.js → workspace.command-jvsb7brc.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
package/index-rtxxan88.js DELETED
@@ -1,471 +0,0 @@
1
- // @bun
2
- import {
3
- getDefaultHostConfig,
4
- GlobalConfig,
5
- CloudApi
6
- } from "./index-m0xccmmm.js";
7
- import {
8
- WorkspaceExecutor,
9
- AppExecutor
10
- } from "./index-2tv3fdx4.js";
11
- import {
12
- AiSession
13
- } from "./index-te54x9zm.js";
14
- import {
15
- runner
16
- } from "./index-0g7r8xz3.js";
17
- import {
18
- openBrowser
19
- } from "./index-sj5vxr8f.js";
20
-
21
- // pkgs/@akanjs/cli/cloud/cloud.runner.ts
22
- import path from "path";
23
- import { confirm, input, select } from "@inquirer/prompts";
24
- import { Logger, sleep } from "akanjs/common";
25
- import chalk from "chalk";
26
- import * as QRcode from "qrcode";
27
-
28
- // pkgs/@akanjs/cli/npmRegistry.ts
29
- var defaultNpmRegistry = "https://registry.npmjs.org";
30
- var getNpmRegistryUrl = (registryUrl = process.env.AKAN_NPM_REGISTRY ?? defaultNpmRegistry) => registryUrl.replace(/\/+$/, "");
31
- async function getLatestPackageVersion(packageName, tag = "latest", registryUrl) {
32
- const registry = getNpmRegistryUrl(registryUrl);
33
- const url = `${registry}/${encodeURIComponent(packageName).replace(/^%40/, "@")}`;
34
- const res = await fetch(url);
35
- if (!res.ok)
36
- throw new Error(`Failed to fetch ${packageName} metadata from ${registry}`);
37
- const metadata = await res.json();
38
- const version = metadata["dist-tags"]?.[tag];
39
- if (!version)
40
- throw new Error(`No npm dist-tag "${tag}" found for ${packageName}`);
41
- return version;
42
- }
43
-
44
- // pkgs/@akanjs/cli/cloud/cloud.runner.ts
45
- var addRemoteEnvServerValue = "__addRemoteEnvServer";
46
- var removeRemoteEnvServerValue = "__removeRemoteEnvServer";
47
-
48
- class CloudRunner extends runner("cloud") {
49
- #akanFrameworkPackages = new Set(["akanjs", "@akanjs/devkit", "@akanjs/cli", "create-akan-workspace"]);
50
- #getRegistryArgs(registryUrl) {
51
- return registryUrl ? ["--registry", getNpmRegistryUrl(registryUrl)] : [];
52
- }
53
- #getLocalRegistryAuthArgs(registryUrl) {
54
- if (!registryUrl)
55
- return [];
56
- const { host, pathname } = new URL(getNpmRegistryUrl(registryUrl));
57
- const registryPath = pathname === "/" ? "/" : `${pathname.replace(/\/+$/, "")}/`;
58
- return [`--//${host}${registryPath}:_authToken=akan-local-registry`];
59
- }
60
- #getRegistryEnv(registryUrl) {
61
- return registryUrl ? {
62
- ...process.env,
63
- AKAN_NPM_REGISTRY: getNpmRegistryUrl(registryUrl),
64
- NPM_CONFIG_REGISTRY: getNpmRegistryUrl(registryUrl)
65
- } : process.env;
66
- }
67
- async#addRemoteEnvServer() {
68
- const name = (await input({
69
- message: "Remote server name: ",
70
- validate: (value) => value.trim() ? true : "Remote server name is required"
71
- })).trim();
72
- const host = (await input({
73
- message: "Remote server host: ",
74
- validate: (value) => value.trim() ? true : "Remote server host is required"
75
- })).trim();
76
- const username = (await input({ message: "Remote server username (optional): " })).trim() || undefined;
77
- const portInput = (await input({
78
- message: "Remote server SSH port (optional): ",
79
- validate: (value) => {
80
- const trimmed = value.trim();
81
- if (!trimmed)
82
- return true;
83
- const port = Number(trimmed);
84
- return Number.isInteger(port) && port > 0 ? true : "SSH port must be a positive integer";
85
- }
86
- })).trim();
87
- const config = {
88
- host,
89
- ...username ? { username } : {},
90
- ...portInput ? { port: Number(portInput) } : {}
91
- };
92
- await GlobalConfig.setRemoteEnvServer(name, config);
93
- return { name, config };
94
- }
95
- async#selectRemoteEnvServer() {
96
- const servers = await GlobalConfig.getRemoteEnvServers();
97
- const serverEntries = Object.entries(servers).sort(([nameA], [nameB]) => nameA.localeCompare(nameB));
98
- if (serverEntries.length === 0) {
99
- Logger.info("No remote env servers configured. Add the first remote server for SCP mode.");
100
- return await this.#addRemoteEnvServer();
101
- }
102
- const selectedName = await select({
103
- message: "Select the remote env server",
104
- choices: [
105
- ...serverEntries.map(([name, config]) => ({
106
- name: `${name} (${config.username ? `${config.username}@` : ""}${config.host}${config.port ? `:${config.port}` : ""})`,
107
- value: name
108
- })),
109
- { name: "Add new remote server", value: addRemoteEnvServerValue },
110
- { name: "Remove remote server", value: removeRemoteEnvServerValue }
111
- ]
112
- });
113
- if (selectedName === addRemoteEnvServerValue)
114
- return await this.#addRemoteEnvServer();
115
- if (selectedName === removeRemoteEnvServerValue) {
116
- await this.#removeRemoteEnvServer(serverEntries);
117
- return await this.#selectRemoteEnvServer();
118
- }
119
- const config = servers[selectedName];
120
- if (!config)
121
- throw new Error(`Remote env server is not found: ${selectedName}`);
122
- return { name: selectedName, config };
123
- }
124
- async#removeRemoteEnvServer(serverEntries) {
125
- const selectedName = await select({
126
- message: "Select the remote env server to remove",
127
- choices: serverEntries.map(([name, config]) => ({
128
- name: `${name} (${config.username ? `${config.username}@` : ""}${config.host}${config.port ? `:${config.port}` : ""})`,
129
- value: name
130
- }))
131
- });
132
- const shouldRemove = await confirm({
133
- message: `Remove remote env server "${selectedName}"?`,
134
- default: false
135
- });
136
- if (!shouldRemove)
137
- return;
138
- await GlobalConfig.removeRemoteEnvServer(selectedName);
139
- Logger.info(`Removed remote env server "${selectedName}"`);
140
- }
141
- async#getRemoteEnvServerWithUsername() {
142
- const remoteServer = await this.#selectRemoteEnvServer();
143
- if (remoteServer.config.username)
144
- return remoteServer;
145
- const username = (await input({
146
- message: `SSH username for ${remoteServer.config.host} (optional): `
147
- })).trim();
148
- return {
149
- ...remoteServer,
150
- config: {
151
- ...remoteServer.config,
152
- ...username ? { username } : {}
153
- }
154
- };
155
- }
156
- #getRemoteEnvArchivePath() {
157
- return `${this.#getRemoteEnvArchiveDir()}/env.tar`;
158
- }
159
- #getRemoteEnvArchiveDir() {
160
- const { repoName } = WorkspaceExecutor.getBaseDevEnv();
161
- return `~/secrets/${repoName}`;
162
- }
163
- #getScpTarget(config, remotePath) {
164
- return `${config.username ? `${config.username}@` : ""}${config.host}:${remotePath}`;
165
- }
166
- #getSshTarget(config) {
167
- return `${config.username ? `${config.username}@` : ""}${config.host}`;
168
- }
169
- #getScpArgs(config, source, target) {
170
- return [...config.port ? ["-P", config.port.toString()] : [], source, target];
171
- }
172
- #getSshArgs(config, command) {
173
- return [...config.port ? ["-p", config.port.toString()] : [], this.#getSshTarget(config), command];
174
- }
175
- async login(host, workspace) {
176
- const config = await GlobalConfig.getHostConfig(host);
177
- const cloudApi = new CloudApi(workspace, config);
178
- const self = config.auth ? await cloudApi.getRemoteSelf() : null;
179
- if (self) {
180
- Logger.rawLog(chalk.green(`
181
- \u2713 Already logged in akan cloud as ${self.nickname}
182
- `));
183
- return true;
184
- }
185
- const remoteId = crypto.randomUUID();
186
- const signinUrl = `${cloudApi.host}/remoteAuth?remoteId=${encodeURIComponent(remoteId)}`;
187
- Logger.rawLog(chalk.bold(`
188
- ${chalk.green("\u27A4")} Authentication Required`));
189
- Logger.rawLog(chalk.dim("Please visit or click the following URL:"));
190
- Logger.rawLog(`${chalk.cyan.underline(signinUrl)}
191
- `);
192
- try {
193
- const qrcode = await new Promise((resolve, reject) => {
194
- QRcode.toString(signinUrl, { type: "terminal", small: true }, (err, data) => {
195
- if (err)
196
- reject(err);
197
- resolve(data);
198
- });
199
- });
200
- Logger.rawLog(qrcode);
201
- await openBrowser(signinUrl);
202
- Logger.rawLog(chalk.dim("Opening browser..."));
203
- } catch {
204
- Logger.rawLog(chalk.yellow("Could not open browser. Please visit the URL manually."));
205
- }
206
- Logger.rawLog(chalk.dim("Waiting for authentication..."));
207
- const MAX_RETRY = 300;
208
- for (let i = 0;i < MAX_RETRY; i++) {
209
- const accessToken = await cloudApi.getRemoteAuthToken(remoteId);
210
- const self = await cloudApi.getRemoteSelf();
211
- if (accessToken && self) {
212
- await GlobalConfig.setHostConfig({ host: config.host, auth: { accessToken, self } });
213
- Logger.rawLog(chalk.green(`\r\u2713 Authentication successful!`));
214
- Logger.rawLog(chalk.green.bold(`
215
- \u2728 Welcome aboard, ${self.nickname ?? "anonymous"}!`));
216
- Logger.rawLog(chalk.dim(`You're now ready to use Akan CLI!
217
- `));
218
- return true;
219
- }
220
- await sleep(2000);
221
- }
222
- throw new Error(chalk.red("\u2716 Authentication timed out after 10 minutes. Please try again."));
223
- }
224
- async logout(host) {
225
- const config = await GlobalConfig.getHostConfig(host);
226
- if (config.auth?.self) {
227
- await GlobalConfig.setHostConfig(getDefaultHostConfig(config.host));
228
- Logger.rawLog(chalk.magenta.bold(`
229
- \uD83D\uDC4B Goodbye, ${config.auth.self.nickname ?? "anonymous"}!`));
230
- Logger.rawLog(chalk.dim(`\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
231
- `));
232
- Logger.rawLog(chalk.cyan("You have been successfully logged out."));
233
- Logger.rawLog(chalk.dim(`Thank you for using Akan CLI. Come back soon! \uD83C\uDF1F
234
- `));
235
- } else {
236
- Logger.rawLog(chalk.yellow.bold(`
237
- \u26A0\uFE0F No active session found`));
238
- Logger.rawLog(chalk.dim(`You were not logged in to begin with
239
- `));
240
- }
241
- }
242
- async setLlm() {
243
- await AiSession.init({ useExisting: false });
244
- }
245
- resetLlm() {
246
- AiSession.setLlmConfig(null);
247
- Logger.rawLog(chalk.green("\u2611\uFE0F LLM model config is cleared. Please run `akan set-llm` to set a new LLM model."));
248
- }
249
- async getAkanPkgs(workspace) {
250
- const pkgs = await workspace.getPkgs();
251
- return pkgs.filter((pkg) => pkg === "akanjs" || pkg === "create-akan-workspace" || pkg.startsWith("@akanjs/"));
252
- }
253
- async deployAkan(workspace, akanPkgs, { registryUrl, confirmPublish = true, tag: distTag } = {}) {
254
- const registry = registryUrl ? getNpmRegistryUrl(registryUrl) : undefined;
255
- const akanPackageJson = await workspace.readJson("pkgs/akanjs/package.json");
256
- const [majorVersion, minorVersion, patchVersion, devPatchVersion] = akanPackageJson.version.split(".");
257
- const isOfficialRelease = !devPatchVersion;
258
- const targetVersionPrefix = isOfficialRelease ? `${majorVersion}.${minorVersion}` : `${majorVersion}.${minorVersion}.${patchVersion}`;
259
- const tag = distTag ?? (isOfficialRelease ? "latest" : patchVersion.split("-").at(1) ?? "dev");
260
- const getNextVersion = async (prefix, tag) => {
261
- try {
262
- const latestPublishedVersion = await getLatestPackageVersion("akanjs", tag, registry);
263
- const latestPatch = latestPublishedVersion.startsWith(prefix) ? parseInt(latestPublishedVersion.split(".").at(-1) ?? "-1") : -1;
264
- const nextVersion = `${prefix}.${latestPatch + 1}`;
265
- return { nextVersion, latestPublishedVersion };
266
- } catch {
267
- return { nextVersion: `${prefix}.0`, latestPublishedVersion: null };
268
- }
269
- };
270
- const { nextVersion, latestPublishedVersion } = await getNextVersion(targetVersionPrefix, tag);
271
- Logger.info(`Latest published version of akanjs: ${latestPublishedVersion ?? "none"}`);
272
- Logger.info(`Next version of akanjs: ${nextVersion}`);
273
- for (const library of akanPkgs) {
274
- const packageJson = await workspace.readJson(`pkgs/${library}/package.json`);
275
- const newPackageJsonStr = JSON.stringify(this.#normalizeAkanPackageJson(packageJson, library, nextVersion), null, 2);
276
- await workspace.writeFile(`pkgs/${library}/package.json`, newPackageJsonStr);
277
- const distPackageJson = await workspace.readJson(`dist/pkgs/${library}/package.json`);
278
- const newDistPackageJson = this.#normalizeAkanPackageJson(distPackageJson, library, nextVersion);
279
- await workspace.writeJson(`dist/pkgs/${library}/package.json`, newDistPackageJson);
280
- }
281
- if (confirmPublish) {
282
- const isDeployConfirmed = await confirm({
283
- message: "Are you sure you want to deploy the libraries?"
284
- });
285
- if (!isDeployConfirmed) {
286
- Logger.error("Deployment cancelled");
287
- return;
288
- }
289
- }
290
- if (!registry) {
291
- Logger.info("Logging in to npm...");
292
- await workspace.spawn("npm", ["login"], { stdio: "inherit" });
293
- Logger.info("Logged in to npm");
294
- }
295
- for (const library of akanPkgs) {
296
- Logger.info(`Publishing ${library}@${nextVersion} to ${registry ?? "npm"}...`);
297
- await workspace.spawn("npm", ["publish", "--tag", tag, ...this.#getRegistryArgs(registry), ...this.#getLocalRegistryAuthArgs(registry)], {
298
- cwd: path.join(workspace.workspaceRoot, "dist/pkgs", library),
299
- env: this.#getRegistryEnv(registry),
300
- stdio: "inherit"
301
- });
302
- Logger.info(`${library}@${nextVersion} is published to ${registry ?? "npm"}`);
303
- }
304
- Logger.info(`All libraries are published to ${registry ?? "npm"}`);
305
- }
306
- async update(workspace, tag = "latest", { registryUrl } = {}) {
307
- const registry = registryUrl ? getNpmRegistryUrl(registryUrl) : undefined;
308
- const registryArgs = this.#getRegistryArgs(registry);
309
- const env = this.#getRegistryEnv(registry);
310
- if (!await workspace.exists("package.json"))
311
- await workspace.spawn("bun", ["update", "-g", "akanjs", "--latest", `--tag=${tag}`, ...registryArgs], { env });
312
- else
313
- await Promise.all([
314
- workspace.spawn("bun", ["update", "-g", "akanjs", "--latest", `--tag=${tag}`, ...registryArgs], { env }),
315
- this.#updateAkanPkgs(workspace, tag, registry)
316
- ]);
317
- }
318
- async#updateAkanPkgs(workspace, tag = "latest", registryUrl) {
319
- const latestPublishedVersion = await getLatestPackageVersion("akanjs", tag, registryUrl);
320
- const rootPackageJson = await workspace.getPackageJson();
321
- if (!rootPackageJson.dependencies)
322
- throw new Error("No dependencies found in package.json");
323
- if (rootPackageJson.dependencies.akanjs)
324
- rootPackageJson.dependencies.akanjs = latestPublishedVersion;
325
- if (rootPackageJson.devDependencies?.akanjs)
326
- rootPackageJson.devDependencies.akanjs = latestPublishedVersion;
327
- if (rootPackageJson.dependencies["@akanjs/devkit"])
328
- rootPackageJson.dependencies["@akanjs/devkit"] = latestPublishedVersion;
329
- if (rootPackageJson.devDependencies?.["@akanjs/devkit"])
330
- rootPackageJson.devDependencies["@akanjs/devkit"] = latestPublishedVersion;
331
- await workspace.setPackageJson(rootPackageJson);
332
- await workspace.spawn("bun", ["install", ...this.#getRegistryArgs(registryUrl)], {
333
- env: this.#getRegistryEnv(registryUrl)
334
- });
335
- }
336
- #normalizeAkanPackageJson(packageJson, packageName, version) {
337
- const normalized = { ...packageJson, version };
338
- for (const field of ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]) {
339
- const dependencies = normalized[field];
340
- if (!dependencies)
341
- continue;
342
- normalized[field] = Object.fromEntries(Object.entries(dependencies).map(([dep, depVersion]) => [
343
- dep,
344
- dep !== packageName && this.#akanFrameworkPackages.has(dep) ? version : depVersion
345
- ]));
346
- }
347
- return normalized;
348
- }
349
- async downloadEnv(cloudApi, workspace, workspaceId) {
350
- await workspace.mkdir("local");
351
- const localPath = await cloudApi.downloadEnv(workspaceId);
352
- const relativePath = path.relative(workspace.workspaceRoot, localPath).split(path.sep).join("/");
353
- await workspace.spawn("tar", ["-xf", relativePath], { cwd: workspace.workspaceRoot });
354
- await workspace.remove(localPath);
355
- }
356
- async uploadEnv(cloudApi, workspaceId, filePath) {
357
- const file = new File([Bun.file(filePath)], path.basename(filePath));
358
- await cloudApi.uploadEnv(workspaceId, file);
359
- }
360
- async downloadEnvByScp(workspace) {
361
- const envArchivePath = "local/env.tar";
362
- const remoteServer = await this.#getRemoteEnvServerWithUsername();
363
- const remoteArchivePath = this.#getRemoteEnvArchivePath();
364
- const remoteTarget = this.#getScpTarget(remoteServer.config, remoteArchivePath);
365
- await workspace.mkdir("local");
366
- await workspace.remove(envArchivePath);
367
- try {
368
- Logger.info(`Downloading env archive from remote server "${remoteServer.name}"...`);
369
- await workspace.spawn("scp", this.#getScpArgs(remoteServer.config, remoteTarget, envArchivePath), {
370
- cwd: workspace.workspaceRoot,
371
- stdio: "inherit"
372
- });
373
- await workspace.spawn("tar", ["-xf", envArchivePath], {
374
- cwd: workspace.workspaceRoot
375
- });
376
- await workspace.remove(envArchivePath);
377
- } catch (error) {
378
- throw new Error(`Failed to download env archive from remote server "${remoteServer.name}"`, { cause: error });
379
- }
380
- }
381
- async uploadEnvByScp(workspace, filePath) {
382
- const remoteServer = await this.#getRemoteEnvServerWithUsername();
383
- const remoteArchiveDir = this.#getRemoteEnvArchiveDir();
384
- const remoteArchivePath = this.#getRemoteEnvArchivePath();
385
- const remoteTarget = this.#getScpTarget(remoteServer.config, remoteArchivePath);
386
- try {
387
- await workspace.spawn("ssh", this.#getSshArgs(remoteServer.config, `mkdir -p ${remoteArchiveDir}`), {
388
- cwd: workspace.workspaceRoot,
389
- stdio: "inherit"
390
- });
391
- Logger.info(`Uploading env archive to remote server "${remoteServer.name}"...`);
392
- await workspace.spawn("scp", this.#getScpArgs(remoteServer.config, filePath, remoteTarget), {
393
- cwd: workspace.workspaceRoot,
394
- stdio: "inherit"
395
- });
396
- } catch (error) {
397
- throw new Error(`Failed to upload env archive to remote server "${remoteServer.name}"`, { cause: error });
398
- }
399
- }
400
- async gatherEnvFiles(workspace, { scope, archivePath = "local/env.tar" } = {}) {
401
- const envFilePattern = /^env\.(client|server)\.(?!(type|example)\.ts$).+\.ts$/;
402
- const [workspaceAppNames, workspaceLibNames] = await workspace.getExecs();
403
- const appNames = scope?.apps ?? workspaceAppNames;
404
- const libNames = scope?.libs ?? workspaceLibNames;
405
- const envDirs = [
406
- ...appNames.map((appName) => `apps/${appName}/env`),
407
- ...libNames.map((libName) => `libs/${libName}/env`)
408
- ];
409
- const defaultEnvFilePaths = (await Promise.all(envDirs.map(async (envDir) => (await workspace.readdir(envDir)).filter((fileName) => envFilePattern.test(fileName)).map((fileName) => `${envDir}/${fileName}`)))).flat();
410
- await this.#syncSecretGitignore(workspace, workspaceAppNames);
411
- const customSecretPaths = await this.#gatherCustomSecretFiles(workspace, appNames);
412
- const envFilePaths = [...new Set([...defaultEnvFilePaths, ...customSecretPaths])].sort();
413
- await workspace.mkdir("local");
414
- await workspace.remove(archivePath);
415
- if (envFilePaths.length === 0)
416
- throw new Error(scope ? `No environment files found to archive for ${appNames.join(", ") || "(no apps)"}` : "No environment files found to archive");
417
- await workspace.spawn("tar", ["-cf", archivePath, ...envFilePaths], {
418
- cwd: workspace.workspaceRoot
419
- });
420
- Logger.info(`Archived ${envFilePaths.length} environment files to ${archivePath}`);
421
- return { files: envFilePaths, path: archivePath };
422
- }
423
- async#gatherCustomSecretFiles(workspace, appNames) {
424
- const secretPaths = await Promise.all(appNames.map(async (appName) => {
425
- const config = await AppExecutor.from(workspace, appName).getConfig();
426
- const secretGlobs = config.secrets ?? [];
427
- if (secretGlobs.length === 0)
428
- return [];
429
- const appDir = path.join(workspace.workspaceRoot, "apps", appName);
430
- return secretGlobs.flatMap((pattern) => Array.from(new Bun.Glob(pattern).scanSync({ cwd: appDir, onlyFiles: true })).map((match) => `apps/${appName}/${match.split(path.sep).join("/")}`));
431
- }));
432
- return secretPaths.flat();
433
- }
434
- async#syncSecretGitignore(workspace, appNames) {
435
- const patterns = (await Promise.all(appNames.map(async (appName) => {
436
- const config = await AppExecutor.from(workspace, appName).getConfig();
437
- return (config.secrets ?? []).map((pattern) => `apps/${appName}/${pattern.replace(/^\/+/, "")}`);
438
- }))).flat();
439
- const uniquePatterns = [...new Set(patterns)].sort();
440
- const existing = await workspace.exists(".gitignore") ? await workspace.readFile(".gitignore") : "";
441
- const nextContent = this.#applySecretGitignoreBlock(existing, uniquePatterns);
442
- if (nextContent === existing)
443
- return;
444
- await workspace.writeFile(".gitignore", nextContent);
445
- Logger.info(uniquePatterns.length ? `Synced ${uniquePatterns.length} secret pattern(s) from akan.config.ts to .gitignore` : "Removed managed secret patterns from .gitignore");
446
- }
447
- #applySecretGitignoreBlock(content, patterns) {
448
- const beginMarker = "# akan:secrets (managed by akan.config.ts \u2014 do not edit)";
449
- const endMarker = "# akan:secrets:end";
450
- const lines = content.split(`
451
- `);
452
- const beginIdx = lines.indexOf(beginMarker);
453
- const endIdx = lines.indexOf(endMarker);
454
- const stripped = beginIdx !== -1 && endIdx !== -1 && endIdx >= beginIdx ? [...lines.slice(0, beginIdx), ...lines.slice(endIdx + 1)] : [...lines];
455
- while (stripped.length && stripped[stripped.length - 1]?.trim() === "")
456
- stripped.pop();
457
- if (patterns.length === 0)
458
- return stripped.length ? `${stripped.join(`
459
- `)}
460
- ` : "";
461
- const body = stripped.length ? `${stripped.join(`
462
- `)}
463
-
464
- ` : "";
465
- return `${body}${[beginMarker, ...patterns, endMarker].join(`
466
- `)}
467
- `;
468
- }
469
- }
470
-
471
- export { getNpmRegistryUrl, getLatestPackageVersion, CloudRunner };