@akanjs/cli 3.0.0-beta.12 → 3.0.0-beta.14

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 (43) hide show
  1. package/.build-stamp +1 -1
  2. package/{TunnelShare-sbsaggmb.js → TunnelShare-r5tc2qk5.js} +2 -2
  3. package/{agent.command-7357vxd8.js → agent.command-bhwsc2aj.js} +1 -1
  4. package/{application.command-pc8mdn3w.js → application.command-436y543n.js} +1 -11
  5. package/{cloud.command-cawrd5nq.js → cloud.command-3xn0xpz8.js} +4 -17
  6. package/{cloud.script-1bmptvw0.js → cloud.script-0a76c2g8.js} +4 -5
  7. package/commandManifest.json +1 -1
  8. package/{context.command-982b6kdp.js → context.command-hxh96cc3.js} +4 -6
  9. package/{devTui-hmteztv3.js → devTui-4ted58a6.js} +1 -1
  10. package/{devTuiView-40jvjnyz.js → devTuiView-1dj2yq7t.js} +1 -1
  11. package/guideline.command-cyw8c0m0.js +48 -0
  12. package/guidelines/agentRule/agentRule.instruction.md +24 -13
  13. package/guidelines/conventions/conventions.instruction.md +6 -3
  14. package/guidelines/moduleCodegen/moduleCodegen.instruction.md +1 -1
  15. package/guidelines/workspaceRecipes/workspaceRecipes.generate.json +1 -0
  16. package/guidelines/workspaceRecipes/workspaceRecipes.instruction.md +62 -0
  17. package/index-1mrmve4s.js +61 -0
  18. package/{index-s3fvrydw.js → index-31hmq4ys.js} +1 -1
  19. package/{index-ay8wj00x.js → index-8tcj5wk8.js} +6 -19
  20. package/index-9fbk3dbh.js +234 -0
  21. package/{index-3pvkjza8.js → index-fad0hhty.js} +3 -3
  22. package/{index-jcekapz4.js → index-gm76f0qb.js} +1 -1
  23. package/{index-bw2marpf.js → index-myj01w9r.js} +18 -19
  24. package/{index-kbsach1y.js → index-r73ha1rf.js} +1 -1
  25. package/{index-r8bd61d9.js → index-sg1bgdhe.js} +65 -68
  26. package/{index-8tfmh0v6.js → index-tt6kzwj5.js} +5 -15
  27. package/index.js +14 -14
  28. package/{localRegistry.command-rx758ajg.js → localRegistry.command-4cbgz63s.js} +3 -4
  29. package/{module.command-c2eve036.js → module.command-ew0484va.js} +4 -7
  30. package/package.json +2 -5
  31. package/{primitive.command-c44f7z1s.js → primitive.command-50ecfzg4.js} +2 -5
  32. package/{quality.command-5evdd263.js → quality.command-a2jytczs.js} +63 -3
  33. package/{scalar.command-xyzerygj.js → scalar.command-bptz6aj6.js} +3 -6
  34. package/{subspace.command-ebfwzypw.js → subspace.command-kmemx1vm.js} +2 -2
  35. package/{tunnel.command-v6a7at16.js → tunnel.command-67q8vsg5.js} +2 -2
  36. package/{workflow.command-t174m6sy.js → workflow.command-2ze5y2xp.js} +4 -7
  37. package/{workspace.command-bg3eveth.js → workspace.command-2n385jkt.js} +9 -10
  38. package/abstractCompactor-bqh31fk5.js +0 -102
  39. package/guideline.command-jn0vwszx.js +0 -360
  40. package/index-ceph7zqj.js +0 -229
  41. package/index-fr2x3qvv.js +0 -841
  42. package/index-meh558jy.js +0 -65
  43. package/index-yc1keaer.js +0 -338
@@ -0,0 +1,234 @@
1
+ // @bun
2
+ import {
3
+ runner,
4
+ script
5
+ } from "./index-b3ae16mg.js";
6
+ import {
7
+ ModuleExecutor
8
+ } from "./index-5nyznra1.js";
9
+ import {
10
+ sourceFile,
11
+ moduleSourcePaths,
12
+ generatedFilesForSync,
13
+ createPassedPrimitiveReport,
14
+ bilingualLabelForField,
15
+ bilingualDescriptionForField
16
+ } from "./index-jwjaf9fy.js";
17
+ import {
18
+ PageScript
19
+ } from "./index-sh88vtye.js";
20
+ import {
21
+ pluralizeName
22
+ } from "./index-nz8prx9g.js";
23
+
24
+ // pkgs/@akanjs/cli/module/module.script.ts
25
+ import { capitalize as capitalize2 } from "akanjs/common";
26
+
27
+ // pkgs/@akanjs/cli/module/module.runner.ts
28
+ import { capitalize } from "akanjs/common";
29
+ var purposeByModule = {
30
+ budget: "Budget represents planned or actual money allocated inside the app.",
31
+ project: "Project represents a project workspace or business initiative managed by the app.",
32
+ task: "Task represents work items that move through the app workflow."
33
+ };
34
+ var moduleAbstractContent = (moduleName) => {
35
+ const title = capitalize(moduleName);
36
+ const label = bilingualLabelForField(moduleName);
37
+ const purpose = purposeByModule[moduleName] ?? `${title} represents ${label.en.toLowerCase()} records managed by the app.`;
38
+ return `# ${title} Module Abstract
39
+
40
+ ## Purpose
41
+
42
+ ${purpose}
43
+
44
+ ## Domain Rules
45
+
46
+ - Keep ${label.en.toLowerCase()} data consistent with user-facing dictionary labels.
47
+
48
+ ## Data Meaning
49
+
50
+ ${label.en} (${label.ko}) is the primary business concept for this module.
51
+
52
+ ## Workflows
53
+
54
+ No lifecycle workflow yet.
55
+
56
+ ## Agent Notes
57
+
58
+ - Read this abstract before changing the module.
59
+ - Update this file when business invariants, workflows, or public behavior change.
60
+ - Do not update this file for formatting-only, import-only, or style-only changes.
61
+
62
+ ## Related Modules
63
+
64
+ - None yet.
65
+ `;
66
+ };
67
+ var localModuleFilename = (moduleName, pathKey) => moduleSourcePaths(moduleName)[pathKey].replace(`lib/${moduleName}/`, "");
68
+
69
+ class ModuleRunner extends runner("module") {
70
+ async createService(module) {
71
+ const serviceName = module.name.replace(/^_+/, "");
72
+ await module.applyTemplate({
73
+ basePath: `.`,
74
+ template: "service",
75
+ dict: { model: serviceName, sysName: module.sys.name }
76
+ });
77
+ const [abstractContent, dictionaryContent, serviceContent, signalContent, storeContent] = await Promise.all([
78
+ module.readFile(`${serviceName}.abstract.md`),
79
+ module.readFile(`${serviceName}.dictionary.ts`),
80
+ module.readFile(`${serviceName}.service.ts`),
81
+ module.readFile(`${serviceName}.signal.ts`),
82
+ module.readFile(`${serviceName}.store.ts`)
83
+ ]);
84
+ return {
85
+ abstract: { filename: `${serviceName}.abstract.md`, content: abstractContent },
86
+ dictionary: { filename: `${serviceName}.dictionary.ts`, content: dictionaryContent },
87
+ service: { filename: `${serviceName}.service.ts`, content: serviceContent },
88
+ signal: { filename: `${serviceName}.signal.ts`, content: signalContent },
89
+ store: { filename: `${serviceName}.store.ts`, content: storeContent }
90
+ };
91
+ }
92
+ async removeModule(module) {
93
+ await module.sys.removeDir(`lib/${module.name}`);
94
+ }
95
+ async createComponentTemplate(module, type) {
96
+ await module.sys.applyTemplate({
97
+ basePath: `./lib/${module.name}`,
98
+ template: `module/__Model__.${capitalize(type)}.tsx`,
99
+ dict: { model: module.name, sysName: module.sys.name, sysType: module.sys.type }
100
+ });
101
+ return {
102
+ component: {
103
+ filename: `${capitalize(module.name)}.${capitalize(type)}.tsx`,
104
+ content: await module.sys.readFile(`lib/${module.name}/${capitalize(module.name)}.${capitalize(type)}.tsx`)
105
+ }
106
+ };
107
+ }
108
+ async createModuleTemplate(module) {
109
+ const names = pluralizeName(module.name);
110
+ const modelLabel = bilingualLabelForField(module.name);
111
+ const modelDescription = bilingualDescriptionForField(module.name);
112
+ const filenames = {
113
+ abstract: localModuleFilename(module.name, "abstract"),
114
+ constant: localModuleFilename(module.name, "constant"),
115
+ dictionary: localModuleFilename(module.name, "dictionary"),
116
+ service: localModuleFilename(module.name, "service"),
117
+ store: localModuleFilename(module.name, "store"),
118
+ signal: localModuleFilename(module.name, "signal"),
119
+ unit: localModuleFilename(module.name, "unit"),
120
+ view: localModuleFilename(module.name, "view"),
121
+ template: localModuleFilename(module.name, "template"),
122
+ zone: localModuleFilename(module.name, "zone"),
123
+ util: localModuleFilename(module.name, "util")
124
+ };
125
+ await module.applyTemplate({
126
+ basePath: `.`,
127
+ template: "module",
128
+ dict: {
129
+ model: module.name,
130
+ models: names,
131
+ sysName: module.sys.name,
132
+ sysType: module.sys.type,
133
+ modelLabelEn: modelLabel.en,
134
+ modelLabelKo: modelLabel.ko,
135
+ modelDescEn: modelDescription.en,
136
+ modelDescKo: modelDescription.ko
137
+ }
138
+ });
139
+ await module.writeFile(filenames.abstract, moduleAbstractContent(module.name));
140
+ const [
141
+ abstractContent,
142
+ constantContent,
143
+ dictionaryContent,
144
+ serviceContent,
145
+ storeContent,
146
+ signalContent,
147
+ unitContent,
148
+ viewContent,
149
+ templateContent,
150
+ zoneContent,
151
+ utilContent
152
+ ] = await Promise.all([
153
+ module.readFile(filenames.abstract),
154
+ module.readFile(filenames.constant),
155
+ module.readFile(filenames.dictionary),
156
+ module.readFile(filenames.service),
157
+ module.readFile(filenames.store),
158
+ module.readFile(filenames.signal),
159
+ module.readFile(filenames.unit),
160
+ module.readFile(filenames.view),
161
+ module.readFile(filenames.template),
162
+ module.readFile(filenames.zone),
163
+ module.readFile(filenames.util)
164
+ ]);
165
+ return {
166
+ abstract: { filename: filenames.abstract, content: abstractContent },
167
+ constant: { filename: filenames.constant, content: constantContent },
168
+ dictionary: { filename: filenames.dictionary, content: dictionaryContent },
169
+ service: { filename: filenames.service, content: serviceContent },
170
+ store: { filename: filenames.store, content: storeContent },
171
+ signal: { filename: filenames.signal, content: signalContent },
172
+ unit: { filename: filenames.unit, content: unitContent },
173
+ view: { filename: filenames.view, content: viewContent },
174
+ template: { filename: filenames.template, content: templateContent },
175
+ zone: { filename: filenames.zone, content: zoneContent },
176
+ util: { filename: filenames.util, content: utilContent }
177
+ };
178
+ }
179
+ }
180
+
181
+ // pkgs/@akanjs/cli/module/module.script.ts
182
+ var moduleChangedFiles = (sys, moduleName, files) => Object.values(files).map((file) => sourceFile(sys, `lib/${moduleName}/${file.filename}`, "create", "Module source file was created."));
183
+
184
+ class ModuleScript extends script("module", [ModuleRunner, PageScript]) {
185
+ async createModuleTemplate(sys, name, { page = false } = {}) {
186
+ const mod = ModuleExecutor.from(sys, name);
187
+ const files = await this.moduleRunner.createModuleTemplate(mod);
188
+ if (page && sys.type === "app")
189
+ await this.pageScript.createCrudPage(mod, { app: sys, basePath: null, single: false });
190
+ await sys.scan();
191
+ return createPassedPrimitiveReport({
192
+ command: "create-module",
193
+ changedFiles: moduleChangedFiles(sys, name, files),
194
+ generatedFiles: generatedFilesForSync(sys, "Generated files were refreshed after module creation."),
195
+ target: sys.name
196
+ });
197
+ }
198
+ async removeModule(mod) {
199
+ await this.moduleRunner.removeModule(mod);
200
+ }
201
+ async createService(sys, name) {
202
+ const service = ModuleExecutor.from(sys, `_${name}`);
203
+ const files = await this.moduleRunner.createService(service);
204
+ await sys.scan();
205
+ return createPassedPrimitiveReport({
206
+ command: "create-service",
207
+ changedFiles: moduleChangedFiles(sys, `_${name}`, files),
208
+ generatedFiles: generatedFilesForSync(sys, "Generated files were refreshed after service creation."),
209
+ target: sys.name
210
+ });
211
+ }
212
+ async createTest(workspace, name) {}
213
+ async createTemplate(mod) {
214
+ return await this.#createComponent(mod, "template");
215
+ }
216
+ async createUnit(mod) {
217
+ return await this.#createComponent(mod, "unit");
218
+ }
219
+ async createView(mod) {
220
+ return await this.#createComponent(mod, "view");
221
+ }
222
+ async#createComponent(mod, type) {
223
+ const { component } = await this.moduleRunner.createComponentTemplate(mod, type);
224
+ return createPassedPrimitiveReport({
225
+ command: `create-${type}`,
226
+ changedFiles: [
227
+ sourceFile(mod.sys, `lib/${mod.name}/${component.filename}`, "create", `${capitalize2(type)} UI source was created.`)
228
+ ],
229
+ target: mod.sys.name
230
+ });
231
+ }
232
+ }
233
+
234
+ export { ModuleScript };
@@ -39,13 +39,13 @@ import {
39
39
  } from "./index-8pkvrcv1.js";
40
40
  import {
41
41
  ModuleScript
42
- } from "./index-fr2x3qvv.js";
42
+ } from "./index-9fbk3dbh.js";
43
43
  import {
44
44
  PrimitiveScript
45
- } from "./index-kbsach1y.js";
45
+ } from "./index-r73ha1rf.js";
46
46
  import {
47
47
  ScalarScript
48
- } from "./index-ceph7zqj.js";
48
+ } from "./index-1mrmve4s.js";
49
49
  import {
50
50
  getMobileTargets
51
51
  } from "./index-47pj3aee.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  GlobalConfig,
4
4
  CloudApi
5
- } from "./index-bw2marpf.js";
5
+ } from "./index-myj01w9r.js";
6
6
 
7
7
  // pkgs/@akanjs/cli/tunnel/TunnelShare.ts
8
8
  import { TunnelAgent } from "akanjs/server/tunnel";
@@ -13,8 +13,7 @@ var configPath = `${basePath}/config.json`;
13
13
  var getDefaultHostConfig = (host = GlobalConfig.akanCloudHost) => ({ host });
14
14
  var defaultAkanGlobalConfig = {
15
15
  cloudHost: {},
16
- remoteEnvServers: {},
17
- llm: null
16
+ remoteEnvServers: {}
18
17
  };
19
18
 
20
19
  // pkgs/@akanjs/devkit/cloud/globalConfig.ts
@@ -44,14 +43,6 @@ class GlobalConfig {
44
43
  akanConfig.cloudHost[config.host] = GlobalConfig.toHostConfigDto(config);
45
44
  await GlobalConfig.#setAkanGlobalConfig(akanConfig);
46
45
  }
47
- static async getLlmConfig() {
48
- const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
49
- return akanConfig.llm ?? null;
50
- }
51
- static async setLlmConfig(llmConfig) {
52
- const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
53
- await GlobalConfig.#setAkanGlobalConfig({ ...akanConfig, llm: llmConfig });
54
- }
55
46
  static async getRemoteEnvServers() {
56
47
  const akanConfig = await GlobalConfig.#getAkanGlobalConfig();
57
48
  return akanConfig.remoteEnvServers;
@@ -119,15 +110,16 @@ class HttpClient {
119
110
  this.baseUrl = baseUrl;
120
111
  this.headers = headers;
121
112
  }
122
- async get(url, { headers } = {}) {
113
+ async get(url, { headers, signal } = {}) {
123
114
  const response = await fetch(`${this.baseUrl}${url}`, {
124
115
  headers: {
125
116
  "Content-Type": "application/json",
126
117
  ...this.headers,
127
118
  ...headers
128
- }
119
+ },
120
+ ...signal ? { signal } : {}
129
121
  });
130
- return await response.json();
122
+ return await HttpClient.#body(response, url);
131
123
  }
132
124
  async getFile(url, localPath, headers) {
133
125
  const response = await fetch(`${this.baseUrl}${url}`, {
@@ -137,14 +129,21 @@ class HttpClient {
137
129
  throw new Error(`Failed to download file: ${response.status} ${response.statusText}`);
138
130
  await Bun.write(localPath, response);
139
131
  }
140
- async post(url, data, { headers } = {}) {
132
+ async post(url, data, { headers, signal } = {}) {
141
133
  const isFormData = data instanceof FormData;
142
134
  const response = await fetch(`${this.baseUrl}${url}`, {
143
135
  method: "POST",
144
136
  body: isFormData ? data : JSON.stringify(data),
145
- headers: isFormData ? { ...this.headers, ...headers } : { "Content-Type": "application/json", ...this.headers, ...headers }
137
+ headers: isFormData ? { ...this.headers, ...headers } : { "Content-Type": "application/json", ...this.headers, ...headers },
138
+ ...signal ? { signal } : {}
146
139
  });
147
- return await response.json();
140
+ return await HttpClient.#body(response, url);
141
+ }
142
+ static async#body(response, url) {
143
+ const text = await response.text();
144
+ if (!response.ok)
145
+ throw new Error(`${response.status} ${response.statusText} from ${url}: ${text.slice(0, 200)}`);
146
+ return JSON.parse(text);
148
147
  }
149
148
  setHeaders(headers) {
150
149
  Object.assign(this.headers, headers);
@@ -217,13 +216,13 @@ class CloudApi {
217
216
  return this.#accessToken;
218
217
  }
219
218
  async requestTunnel(input) {
220
- return await this.#api.post(`/requestTunnel`, input);
219
+ return await this.#api.post(`/tunnel/requestTunnel`, input);
221
220
  }
222
221
  async tunnelListInSelf() {
223
- return await this.#api.get(`/tunnelListInSelf`);
222
+ return await this.#api.get(`/tunnel/tunnelListInSelf`);
224
223
  }
225
224
  async revokeTunnel(code) {
226
- return await this.#api.post(`/revokeTunnel`, { code });
225
+ return await this.#api.post(`/tunnel/revokeTunnel`, { code }, { signal: AbortSignal.timeout(5000) });
227
226
  }
228
227
  async getRemoteSelf() {
229
228
  try {
@@ -42,7 +42,7 @@ import {
42
42
  } from "./index-jwjaf9fy.js";
43
43
  import {
44
44
  ModuleScript
45
- } from "./index-fr2x3qvv.js";
45
+ } from "./index-9fbk3dbh.js";
46
46
 
47
47
  // pkgs/@akanjs/cli/primitive/primitive.script.ts
48
48
  import { capitalize } from "akanjs/common";
@@ -166,7 +166,7 @@ Caused by: ${ApplicationBuildReporter.formatError(error.cause)}` : "";
166
166
 
167
167
  // pkgs/@akanjs/cli/application/application.script.ts
168
168
  import { confirm } from "@inquirer/prompts";
169
- import { Logger as Logger6 } from "akanjs/common";
169
+ import { Logger as Logger7 } from "akanjs/common";
170
170
 
171
171
  // pkgs/@akanjs/cli/application/application.runner.ts
172
172
  import path5 from "path";
@@ -2048,11 +2048,9 @@ ${uniqueCandidates.map((candidate) => ` - ${candidate}`).join(`
2048
2048
 
2049
2049
  // pkgs/@akanjs/cli/application/application.runner.ts
2050
2050
  import { Logger as Logger4 } from "akanjs/common";
2051
- import ora from "ora";
2052
2051
  var loadBuildRunner = async () => (await import("./applicationBuildRunner-4f1wrba0.js")).ApplicationBuildRunner;
2053
2052
  var loadReleasePackager = async () => (await import("./applicationReleasePackager-jkjmy5ee.js")).ApplicationReleasePackager;
2054
2053
  var loadCapacitorApp = async () => (await import("./capacitorApp-hqvsrec4.js")).CapacitorApp;
2055
- var loadAbstractCompactor = async () => (await import("./abstractCompactor-bqh31fk5.js")).AbstractCompactor;
2056
2054
  var loadPrompts = async () => await import("@inquirer/prompts");
2057
2055
 
2058
2056
  class ApplicationRunner extends runner("application") {
@@ -2193,10 +2191,6 @@ try {
2193
2191
  async typecheck(app, options = {}) {
2194
2192
  await new (await loadBuildRunner())(app).typecheck(options);
2195
2193
  }
2196
- async compact(sys, { module, minLines, interactive } = {}) {
2197
- const compactor = new (await loadAbstractCompactor())(sys, { minLines, interactive });
2198
- return await compactor.compactAll({ module });
2199
- }
2200
2194
  async test(exec) {
2201
2195
  const isSignalTarget = exec instanceof AppExecutor || exec instanceof LibExecutor;
2202
2196
  const preloadPath = isSignalTarget ? await resolveSignalTestPreloadPath(exec) : null;
@@ -2434,28 +2428,6 @@ ${detail}`
2434
2428
  });
2435
2429
  return;
2436
2430
  }
2437
- async generateApplicationTemplate(app) {
2438
- const openAIApiKey = process.env.OPENAI_API_KEY;
2439
- if (!openAIApiKey)
2440
- throw new Error("OPENAI_API_KEY is not set");
2441
- const [{ StringOutputParser }, { PromptTemplate }, { RunnableSequence }, { ChatOpenAI }, prompts] = await Promise.all([
2442
- import("@langchain/core/output_parsers"),
2443
- import("@langchain/core/prompts"),
2444
- import("@langchain/core/runnables"),
2445
- import("@langchain/openai"),
2446
- loadPrompts()
2447
- ]);
2448
- const chatModel = new ChatOpenAI({ modelName: "gpt-4o", openAIApiKey });
2449
- const projectName = await prompts.input({ message: "please enter project name." });
2450
- const projectDesc = await prompts.input({
2451
- message: "please enter project description. (40 ~ 60 characters)"
2452
- });
2453
- const spinner = ora("Gerating project files...");
2454
- const mainPrompt = PromptTemplate.fromTemplate(`prompt.requestApplication()`);
2455
- const chain = RunnableSequence.from([mainPrompt, chatModel, new StringOutputParser]);
2456
- await chain.invoke({ projectName, projectDesc });
2457
- spinner.succeed("Loading complete!");
2458
- }
2459
2431
  }
2460
2432
 
2461
2433
  // pkgs/@akanjs/cli/application/devPortReclaimer.ts
@@ -3054,9 +3026,54 @@ var resolveDevUi = (plain, { isTty = !!process.stdout.isTTY, columns = process.s
3054
3026
  return { mode: "tui", downgraded: false };
3055
3027
  };
3056
3028
 
3029
+ // pkgs/@akanjs/cli/application/interruptTeardown.ts
3030
+ import { Logger as Logger6 } from "akanjs/common";
3031
+
3032
+ class InterruptTeardown {
3033
+ #teardowns = [];
3034
+ #exit;
3035
+ #listen;
3036
+ #report;
3037
+ #interrupted = false;
3038
+ ownsExit = true;
3039
+ constructor({ exit, listen, report } = {}) {
3040
+ this.#exit = exit ?? ((code) => process.exit(code));
3041
+ this.#listen = listen ?? ((onSignal) => {
3042
+ process.on("SIGINT", onSignal);
3043
+ });
3044
+ this.#report = report ?? ((message) => Logger6.rawLog(message, undefined, "error"));
3045
+ }
3046
+ add(run, abandoned) {
3047
+ this.#teardowns.push({ run, abandoned, running: false });
3048
+ if (this.#teardowns.length === 1)
3049
+ this.#listen(() => this.#onSignal());
3050
+ }
3051
+ #onSignal() {
3052
+ if (this.#interrupted) {
3053
+ for (const one of this.#teardowns)
3054
+ if (one.running)
3055
+ this.#report(one.abandoned);
3056
+ this.#exit(130);
3057
+ return;
3058
+ }
3059
+ this.#interrupted = true;
3060
+ Promise.all(this.#teardowns.map(async (one) => {
3061
+ one.running = true;
3062
+ await one.run().catch(() => {
3063
+ return;
3064
+ });
3065
+ one.running = false;
3066
+ })).finally(() => {
3067
+ if (this.ownsExit)
3068
+ this.#exit(0);
3069
+ });
3070
+ }
3071
+ }
3072
+
3057
3073
  // pkgs/@akanjs/cli/application/application.script.ts
3058
3074
  class ApplicationScript extends script("application", [ApplicationRunner, LibraryScript]) {
3059
3075
  static dbShutdownTimeoutMs = 20000;
3076
+ #interrupt = new InterruptTeardown;
3060
3077
  async confirmDatabaseModeDependencyInstall(databaseMode, installSpecs) {
3061
3078
  return await confirm({
3062
3079
  message: [
@@ -3148,7 +3165,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3148
3165
  const spinner = app.spinning("Planning distributable slice...");
3149
3166
  const plan = await this.applicationRunner.planSlice(app);
3150
3167
  spinner.succeed(`Slice planned (${plan.libs.length} libs, ${plan.warnings.length} warnings)`);
3151
- Logger6.rawLog(format === "json" ? JSON.stringify(plan, null, 2) : formatSlicePlan(plan));
3168
+ Logger7.rawLog(format === "json" ? JSON.stringify(plan, null, 2) : formatSlicePlan(plan));
3152
3169
  }
3153
3170
  async sync(sys) {
3154
3171
  if (sys.type === "app")
@@ -3156,17 +3173,6 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3156
3173
  else
3157
3174
  await this.libraryScript.syncLibrary(sys);
3158
3175
  }
3159
- async compact(sys, { module = null, minLines, interactive = false } = {}) {
3160
- const { scanned, reports } = await this.applicationRunner.compact(sys, { module, minLines, interactive });
3161
- if (!reports.length) {
3162
- Logger6.rawLog(`No abstract file long enough to compact in ${sys.name} (${scanned} scanned)`);
3163
- return;
3164
- }
3165
- for (const report of reports)
3166
- Logger6.rawLog(`${report.status}: ${report.path} (${report.beforeLines} -> ${report.afterLines} lines)`);
3167
- const compactedNum = reports.filter((report) => report.status === "compacted").length;
3168
- Logger6.rawLog(`Compacted ${compactedNum}/${reports.length} abstract files in ${sys.name}`);
3169
- }
3170
3176
  async script(app, filename) {
3171
3177
  const scriptFilename = filename ?? await this.applicationRunner.getScriptFilename(app);
3172
3178
  await app.scanSync();
@@ -3182,18 +3188,18 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3182
3188
  async build(app, { write = true, fast = false, quiet = false } = {}) {
3183
3189
  await app.scanSync({ write });
3184
3190
  if (!quiet)
3185
- Logger6.rawLog(`Creating an optimized production build for ${app.name}...`);
3191
+ Logger7.rawLog(`Creating an optimized production build for ${app.name}...`);
3186
3192
  try {
3187
3193
  const result = await this.applicationRunner.build(app, {
3188
3194
  fast,
3189
3195
  spinner: !quiet
3190
3196
  });
3191
- Logger6.rawLog(`${app.name} built in dist/apps/${app.name}`);
3197
+ Logger7.rawLog(`${app.name} built in dist/apps/${app.name}`);
3192
3198
  if (!quiet)
3193
3199
  ApplicationBuildReporter.printSummary(result);
3194
3200
  } catch (error) {
3195
- Logger6.rawLog(`${app.name} build failed in dist/apps/${app.name}`, undefined, "error");
3196
- Logger6.rawLog(ApplicationBuildReporter.formatError(error), undefined, "error");
3201
+ Logger7.rawLog(`${app.name} build failed in dist/apps/${app.name}`, undefined, "error");
3202
+ Logger7.rawLog(ApplicationBuildReporter.formatError(error), undefined, "error");
3197
3203
  throw error;
3198
3204
  }
3199
3205
  }
@@ -3205,7 +3211,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3205
3211
  spinner.succeed(`${app.name} typechecked`);
3206
3212
  } catch (error) {
3207
3213
  spinner.fail(`${app.name} typecheck failed`);
3208
- Logger6.rawLog(ApplicationBuildReporter.formatError(error), undefined, "error");
3214
+ Logger7.rawLog(ApplicationBuildReporter.formatError(error), undefined, "error");
3209
3215
  throw error;
3210
3216
  }
3211
3217
  }
@@ -3251,6 +3257,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3251
3257
  await this.#shareOnInterrupt(apps);
3252
3258
  if (mode === "stream" && apps.length === 1)
3253
3259
  return await this.startOne(first, { open, dbup, write, ...DevSupervisor.childHooks() });
3260
+ this.#interrupt.ownsExit = false;
3254
3261
  await this.#startMany(apps, { open, dbup, write, mode, concurrency });
3255
3262
  }
3256
3263
  async startOne(app, { open = false, dbup = true, stdio = "inherit", write = true, onDevEvent } = {}) {
@@ -3283,7 +3290,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3283
3290
  for (const holder of killed)
3284
3291
  workspace.log(`freed port ${holder.port} \u2014 killed pid ${holder.pid} (${holder.command})`);
3285
3292
  for (const holder of foreign)
3286
- Logger6.rawLog(`port ${holder.port} is held by pid ${holder.pid} and was left alone: ${holder.command}`, undefined, "error");
3293
+ Logger7.rawLog(`port ${holder.port} is held by pid ${holder.pid} and was left alone: ${holder.command}`, undefined, "error");
3287
3294
  if (killed.length === 0 && foreign.length === 0)
3288
3295
  workspace.log("dev ports are free; nothing to kill");
3289
3296
  }
@@ -3299,7 +3306,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3299
3306
  throw new Error("No app selected to start");
3300
3307
  const startedDatabase = dbup ? await this.#prepareSharedDatabase(apps) : false;
3301
3308
  const supervisor = new DevSupervisor({ apps, mode, concurrency, open, write });
3302
- const view = mode === "tui" ? await (await import("./devTuiView-40jvjnyz.js")).createDevTuiView(supervisor) : new DevStreamView(apps.map((app) => app.name));
3309
+ const view = mode === "tui" ? await (await import("./devTuiView-1dj2yq7t.js")).createDevTuiView(supervisor) : new DevStreamView(apps.map((app) => app.name));
3303
3310
  await supervisor.run(view);
3304
3311
  if (startedDatabase)
3305
3312
  await this.#stopDatabase(workspace);
@@ -3420,32 +3427,22 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3420
3427
  #shareOnInterrupt(apps) {
3421
3428
  const shares = [];
3422
3429
  const open = Promise.all(apps.map(async (app) => {
3423
- const { TunnelShare } = await import("./TunnelShare-sbsaggmb.js");
3430
+ const { TunnelShare } = await import("./TunnelShare-r5tc2qk5.js");
3424
3431
  const share = await TunnelShare.open(app, { workspace: app.workspace });
3425
3432
  shares.push(share);
3426
- Logger6.rawLog(`${app.name} is shared at ${share.url}`);
3433
+ Logger7.rawLog(`${app.name} is shared at ${share.url}`);
3427
3434
  })).catch((error) => {
3428
- Logger6.rawLog(`Could not open the tunnel: ${error instanceof Error ? error.message : String(error)}`, undefined, "error");
3429
- });
3430
- let closing = false;
3431
- process.on("SIGINT", () => {
3432
- if (closing)
3433
- return;
3434
- closing = true;
3435
- Promise.all(shares.map(async (share) => await share.close()));
3435
+ Logger7.rawLog(`Could not open the tunnel: ${error instanceof Error ? error.message : String(error)}`, undefined, "error");
3436
3436
  });
3437
+ this.#interrupt.add(async () => {
3438
+ await Promise.all(shares.map(async (share) => await share.close()));
3439
+ }, "Abandoning the tunnel release; the shares expire on their own.");
3437
3440
  return open;
3438
3441
  }
3439
3442
  #stopDatabaseOnInterrupt(workspace) {
3440
- let stopping = false;
3441
- process.on("SIGINT", () => {
3442
- if (stopping) {
3443
- Logger6.rawLog("Abandoning the local database teardown; containers are left running.", undefined, "error");
3444
- process.exit(130);
3445
- }
3446
- stopping = true;
3447
- this.#stopDatabase(workspace).finally(() => process.exit(0));
3448
- });
3443
+ this.#interrupt.add(async () => {
3444
+ await this.#stopDatabase(workspace);
3445
+ }, "Abandoning the local database teardown; containers are left running.");
3449
3446
  }
3450
3447
  async#stopDatabase(workspace) {
3451
3448
  let timer = null;
@@ -3458,7 +3455,7 @@ class ApplicationScript extends script("application", [ApplicationRunner, Librar
3458
3455
  }), timeout]);
3459
3456
  if (result !== "timeout")
3460
3457
  return;
3461
- Logger6.rawLog(`Local database did not stop within ${ApplicationScript.dbShutdownTimeoutMs}ms; run \`akan dbdown\` once Docker responds.`, undefined, "error");
3458
+ Logger7.rawLog(`Local database did not stop within ${ApplicationScript.dbShutdownTimeoutMs}ms; run \`akan dbdown\` once Docker responds.`, undefined, "error");
3462
3459
  } finally {
3463
3460
  if (timer)
3464
3461
  clearTimeout(timer);
@@ -3,20 +3,17 @@ import {
3
3
  getDefaultHostConfig,
4
4
  GlobalConfig,
5
5
  CloudApi
6
- } from "./index-bw2marpf.js";
6
+ } from "./index-myj01w9r.js";
7
+ import {
8
+ runner
9
+ } from "./index-b3ae16mg.js";
7
10
  import {
8
11
  WorkspaceExecutor,
9
12
  AppExecutor
10
13
  } from "./index-5nyznra1.js";
11
- import {
12
- AiSession
13
- } from "./index-yc1keaer.js";
14
- import {
15
- runner
16
- } from "./index-b3ae16mg.js";
17
14
  import {
18
15
  openBrowser
19
- } from "./index-r8bd61d9.js";
16
+ } from "./index-sg1bgdhe.js";
20
17
 
21
18
  // pkgs/@akanjs/cli/cloud/cloud.runner.ts
22
19
  import path from "path";
@@ -239,13 +236,6 @@ ${chalk.green("\u27A4")} Authentication Required`));
239
236
  `));
240
237
  }
241
238
  }
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
239
  async getAkanPkgs(workspace) {
250
240
  const pkgs = await workspace.getPkgs();
251
241
  return pkgs.filter((pkg) => pkg === "akanjs" || pkg === "create-akan-workspace" || pkg.startsWith("@akanjs/"));