@akanjs/devkit 2.1.0-rc.0 → 2.1.0-rc.2
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.
- package/README.ko.md +65 -0
- package/README.md +63 -0
- package/commandDecorators/command.ts +40 -6
- package/executors.test.ts +36 -1
- package/executors.ts +90 -3
- package/incrementalBuilder/incrementalBuilder.host.ts +1 -0
- package/package.json +2 -2
package/README.ko.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# @akanjs/devkit
|
|
2
|
+
|
|
3
|
+
[문서](https://akanjs.com/docs) | [npm](https://www.npmjs.com/package/@akanjs/devkit) | [런타임](https://www.npmjs.com/package/akanjs)
|
|
4
|
+
|
|
5
|
+
Akan.js를 위한 development tooling primitive입니다.
|
|
6
|
+
|
|
7
|
+
`@akanjs/devkit`은 Akan CLI와 프레임워크 수준 tooling에서 사용하는 build runner, workspace
|
|
8
|
+
executor, config loader, dependency scanner, frontend artifact builder, command decorator, prompt,
|
|
9
|
+
release helper를 담고 있습니다. 애플리케이션 런타임 코드가 아니라 tooling과 package author를 위한
|
|
10
|
+
패키지입니다.
|
|
11
|
+
|
|
12
|
+
## 설치
|
|
13
|
+
|
|
14
|
+
대부분의 사용자는 devkit 대신 CLI를 설치하면 됩니다.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
bun install -g @akanjs/cli@latest
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Akan-aware tooling을 직접 만들 때만 `@akanjs/devkit`을 설치하세요.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
bun add -d @akanjs/devkit
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## 사용 예시
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { ApplicationBuildRunner, WorkspaceExecutor } from "@akanjs/devkit";
|
|
30
|
+
|
|
31
|
+
const workspace = WorkspaceExecutor.fromRoot();
|
|
32
|
+
const app = await workspace.getApp("my-app");
|
|
33
|
+
const runner = new ApplicationBuildRunner(app);
|
|
34
|
+
|
|
35
|
+
await runner.build();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 제공하는 것
|
|
39
|
+
|
|
40
|
+
- Workspace, app, library, package, module executor.
|
|
41
|
+
- `akan.config.ts` 로딩과 정규화.
|
|
42
|
+
- Application build, typecheck, SSR, CSR, release runner.
|
|
43
|
+
- Dependency scanning과 package metadata 생성 helper.
|
|
44
|
+
- Frontend build transform과 RSC/SSR artifact builder.
|
|
45
|
+
- `@akanjs/cli`가 사용하는 command/script decorator.
|
|
46
|
+
- AI prompt, guideline, code-generation 지원 utility.
|
|
47
|
+
- Capacitor와 mobile release helper.
|
|
48
|
+
|
|
49
|
+
## 패키지 경계
|
|
50
|
+
|
|
51
|
+
- 런타임 코드는 `akanjs`에서 import해야 합니다. `AppConfig`, `LibConfig`, `AppInfo`, `LibInfo` 같은
|
|
52
|
+
공유 config 타입도 `akanjs`에서 가져옵니다.
|
|
53
|
+
- CLI 사용자는 `@akanjs/cli`를 설치하면 됩니다. published CLI는 이 devkit을 내부에 번들링합니다.
|
|
54
|
+
- Tooling author는 Akan workspace introspection이나 build API가 필요할 때 `@akanjs/devkit`을 직접
|
|
55
|
+
import할 수 있습니다.
|
|
56
|
+
|
|
57
|
+
## 요구사항
|
|
58
|
+
|
|
59
|
+
- [Bun](https://bun.sh) `>=1.3.13`
|
|
60
|
+
- TypeScript
|
|
61
|
+
- Optional peer는 Capacitor integration처럼 해당 기능을 사용할 때만 필요합니다.
|
|
62
|
+
|
|
63
|
+
## 라이선스
|
|
64
|
+
|
|
65
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# @akanjs/devkit
|
|
2
|
+
|
|
3
|
+
[Docs](https://akanjs.com/docs) | [npm](https://www.npmjs.com/package/@akanjs/devkit) | [Runtime](https://www.npmjs.com/package/akanjs)
|
|
4
|
+
|
|
5
|
+
Development tooling primitives for Akan.js.
|
|
6
|
+
|
|
7
|
+
`@akanjs/devkit` contains the build runners, workspace executors, config loaders, dependency scanners,
|
|
8
|
+
frontend artifact builders, command decorators, prompts, and release helpers used by the Akan CLI and by
|
|
9
|
+
framework-level tooling. It is intended for tools and package authors, not for application runtime code.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
Most users should install the CLI instead:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun install -g @akanjs/cli@latest
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Install `@akanjs/devkit` directly only when building Akan-aware tooling:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
bun add -d @akanjs/devkit
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { ApplicationBuildRunner, WorkspaceExecutor } from "@akanjs/devkit";
|
|
29
|
+
|
|
30
|
+
const workspace = WorkspaceExecutor.fromRoot();
|
|
31
|
+
const app = await workspace.getApp("my-app");
|
|
32
|
+
const runner = new ApplicationBuildRunner(app);
|
|
33
|
+
|
|
34
|
+
await runner.build();
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## What It Provides
|
|
38
|
+
|
|
39
|
+
- Workspace, app, library, package, and module executors.
|
|
40
|
+
- `akan.config.ts` loading and normalization.
|
|
41
|
+
- Application build, typecheck, SSR, CSR, and release runners.
|
|
42
|
+
- Dependency scanning and package metadata generation helpers.
|
|
43
|
+
- Frontend build transforms and RSC/SSR artifact builders.
|
|
44
|
+
- Command/script decorators used by `@akanjs/cli`.
|
|
45
|
+
- AI prompt, guideline, and code-generation support utilities.
|
|
46
|
+
- Capacitor and mobile release helpers.
|
|
47
|
+
|
|
48
|
+
## Package Boundary
|
|
49
|
+
|
|
50
|
+
- Runtime code should import from `akanjs`, including shared config types such as `AppConfig`, `LibConfig`,
|
|
51
|
+
`AppInfo`, and `LibInfo`.
|
|
52
|
+
- CLI users should install `@akanjs/cli`; the published CLI bundles this devkit internally.
|
|
53
|
+
- Tooling authors can import `@akanjs/devkit` directly when they need Akan workspace introspection or build APIs.
|
|
54
|
+
|
|
55
|
+
## Requirements
|
|
56
|
+
|
|
57
|
+
- [Bun](https://bun.sh) `>=1.3.13`
|
|
58
|
+
- TypeScript
|
|
59
|
+
- Optional peers are only needed for the features that use them, such as Capacitor integration.
|
|
60
|
+
|
|
61
|
+
## License
|
|
62
|
+
|
|
63
|
+
MIT
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import { confirm, input, select } from "@inquirer/prompts";
|
|
2
3
|
import { Logger } from "akanjs/common";
|
|
3
4
|
import chalk from "chalk";
|
|
@@ -18,6 +19,32 @@ import { formatCommandHelp, formatHelp } from "./helpFormatter";
|
|
|
18
19
|
import { type CommandCls, getTargetMetas } from "./targetMeta";
|
|
19
20
|
|
|
20
21
|
const camelToKebabCase = (str: string) => str.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
22
|
+
const loggedCliErrorObjects = new WeakSet<object>();
|
|
23
|
+
const loggedCliErrorMessages = new Set<string>();
|
|
24
|
+
|
|
25
|
+
const formatCliError = (error: unknown): string => {
|
|
26
|
+
if (error instanceof Error) return error.message || error.name;
|
|
27
|
+
if (typeof error === "string") return error.trim() || "Unknown error";
|
|
28
|
+
if (error === null || error === undefined) return "Unknown error";
|
|
29
|
+
try {
|
|
30
|
+
const json = JSON.stringify(error);
|
|
31
|
+
if (json) return json;
|
|
32
|
+
} catch {
|
|
33
|
+
return String(error);
|
|
34
|
+
}
|
|
35
|
+
return String(error) || "Unknown error";
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const printCliError = (error: unknown) => {
|
|
39
|
+
if (typeof error === "object" && error !== null) {
|
|
40
|
+
if (loggedCliErrorObjects.has(error)) return;
|
|
41
|
+
loggedCliErrorObjects.add(error);
|
|
42
|
+
}
|
|
43
|
+
const message = formatCliError(error);
|
|
44
|
+
if (loggedCliErrorMessages.has(message)) return;
|
|
45
|
+
loggedCliErrorMessages.add(message);
|
|
46
|
+
Logger.rawLog(`\n${chalk.red(message)}`);
|
|
47
|
+
};
|
|
21
48
|
|
|
22
49
|
const handleOption = (programCommand: Command, argMeta: ArgMeta) => {
|
|
23
50
|
const {
|
|
@@ -218,13 +245,21 @@ const getInternalArgumentValue = async (
|
|
|
218
245
|
|
|
219
246
|
export const runCommands = async (...commands: CommandCls[]) => {
|
|
220
247
|
process.on("unhandledRejection", (error) => {
|
|
248
|
+
printCliError(error);
|
|
221
249
|
process.exit(1);
|
|
222
250
|
});
|
|
223
251
|
const __dirname = getDirname(import.meta.url);
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
252
|
+
const packageJsonCandidates = [`${path.dirname(Bun.main)}/package.json`, `${__dirname}/../package.json`];
|
|
253
|
+
let cliPackageJson: PackageJson | null = null;
|
|
254
|
+
for (const packageJsonPath of packageJsonCandidates) {
|
|
255
|
+
if (!(await FileSys.fileExists(packageJsonPath))) continue;
|
|
256
|
+
const packageJson = await FileSys.readJson<PackageJson>(packageJsonPath);
|
|
257
|
+
if (packageJson.name === "@akanjs/cli" || packageJson.name === "@akanjs/devkit") {
|
|
258
|
+
cliPackageJson = packageJson;
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
process.env.AKAN_VERSION = cliPackageJson?.version ?? "0.0.1";
|
|
228
263
|
|
|
229
264
|
// Custom help handling
|
|
230
265
|
const hasHelpFlag = process.argv.includes("--help") || process.argv.includes("-h");
|
|
@@ -331,8 +366,7 @@ It may cause unexpected behavior. Run \`akan update\` to update latest akanjs.`,
|
|
|
331
366
|
await targetMeta.handler.call(cmd, ...commandArgs);
|
|
332
367
|
Logger.rawLog();
|
|
333
368
|
} catch (e) {
|
|
334
|
-
|
|
335
|
-
Logger.rawLog(`\n${chalk.red(errMsg)}`);
|
|
369
|
+
printCliError(e);
|
|
336
370
|
throw e;
|
|
337
371
|
}
|
|
338
372
|
});
|
package/executors.test.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { mkdir, mkdtemp, readFile, rm, stat, writeFile } from "node:fs/promises"
|
|
|
3
3
|
import os from "node:os";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { AkanAppConfig } from "./akanConfig";
|
|
6
|
-
import { AppExecutor, Executor, PkgExecutor, WorkspaceExecutor } from "./executors";
|
|
6
|
+
import { AppExecutor, CommandExecutionError, Executor, PkgExecutor, WorkspaceExecutor } from "./executors";
|
|
7
7
|
import { AppInfo } from "./scanInfo";
|
|
8
8
|
import type { PackageJson } from "./types";
|
|
9
9
|
|
|
@@ -48,6 +48,41 @@ afterEach(async () => {
|
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
describe("Executor filesystem helpers", () => {
|
|
51
|
+
test("reports command failures with command context and captured output", async () => {
|
|
52
|
+
const root = await makeTempRoot();
|
|
53
|
+
const exec = new Executor("fixture", root);
|
|
54
|
+
|
|
55
|
+
let error: unknown;
|
|
56
|
+
try {
|
|
57
|
+
await exec.spawn(process.execPath, ["--eval", "console.error('spawn failed'); process.exit(7)"]);
|
|
58
|
+
} catch (caught) {
|
|
59
|
+
error = caught;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
expect(error).toBeInstanceOf(CommandExecutionError);
|
|
63
|
+
expect((error as CommandExecutionError).message).toContain(`Command failed: ${process.execPath}`);
|
|
64
|
+
expect((error as CommandExecutionError).message).toContain(`cwd: ${root}`);
|
|
65
|
+
expect((error as CommandExecutionError).message).toContain("exit code: 7");
|
|
66
|
+
expect((error as CommandExecutionError).message).toContain("spawn failed");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("reports inherited stdio command failures with a fallback message", async () => {
|
|
70
|
+
const root = await makeTempRoot();
|
|
71
|
+
const exec = new Executor("fixture", root);
|
|
72
|
+
|
|
73
|
+
let error: unknown;
|
|
74
|
+
try {
|
|
75
|
+
await exec.spawn(process.execPath, ["--eval", "process.exit(3)"], { stdio: "inherit" });
|
|
76
|
+
} catch (caught) {
|
|
77
|
+
error = caught;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
expect(error).toBeInstanceOf(CommandExecutionError);
|
|
81
|
+
expect((error as CommandExecutionError).message).toContain(`Command failed: ${process.execPath}`);
|
|
82
|
+
expect((error as CommandExecutionError).message).toContain(`cwd: ${root}`);
|
|
83
|
+
expect((error as CommandExecutionError).message).toContain("exit code: 3");
|
|
84
|
+
});
|
|
85
|
+
|
|
51
86
|
test("resolves paths and reads/writes files relative to cwd", async () => {
|
|
52
87
|
const root = await makeTempRoot();
|
|
53
88
|
const exec = new Executor("fixture", root);
|
package/executors.ts
CHANGED
|
@@ -64,6 +64,58 @@ const staticTemplateFileExtensions = new Set([
|
|
|
64
64
|
".xml",
|
|
65
65
|
]);
|
|
66
66
|
|
|
67
|
+
const formatCommandArg = (value: string) => (/^[\w@%+=:,./-]+$/.test(value) ? value : JSON.stringify(value));
|
|
68
|
+
|
|
69
|
+
const formatCommandForDisplay = (command: string, args: string[] = []) =>
|
|
70
|
+
[command, ...args].map(formatCommandArg).join(" ");
|
|
71
|
+
|
|
72
|
+
export interface CommandExecutionErrorOptions {
|
|
73
|
+
command: string;
|
|
74
|
+
args?: string[];
|
|
75
|
+
cwd: string;
|
|
76
|
+
code: number | null;
|
|
77
|
+
signal: string | null;
|
|
78
|
+
stdout?: string;
|
|
79
|
+
stderr?: string;
|
|
80
|
+
cause?: unknown;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export class CommandExecutionError extends Error {
|
|
84
|
+
command: string;
|
|
85
|
+
args: string[];
|
|
86
|
+
cwd: string;
|
|
87
|
+
code: number | null;
|
|
88
|
+
signal: string | null;
|
|
89
|
+
stdout: string;
|
|
90
|
+
stderr: string;
|
|
91
|
+
|
|
92
|
+
constructor({
|
|
93
|
+
command,
|
|
94
|
+
args = [],
|
|
95
|
+
cwd,
|
|
96
|
+
code,
|
|
97
|
+
signal,
|
|
98
|
+
stdout = "",
|
|
99
|
+
stderr = "",
|
|
100
|
+
cause,
|
|
101
|
+
}: CommandExecutionErrorOptions) {
|
|
102
|
+
const displayCommand = formatCommandForDisplay(command, args);
|
|
103
|
+
const status = signal ? `signal: ${signal}` : `exit code: ${code ?? "unknown"}`;
|
|
104
|
+
const output = (stderr || stdout).trim();
|
|
105
|
+
super([`Command failed: ${displayCommand}`, `cwd: ${cwd}`, status, output ? `\n${output}` : ""].join("\n"), {
|
|
106
|
+
cause,
|
|
107
|
+
});
|
|
108
|
+
this.name = "CommandExecutionError";
|
|
109
|
+
this.command = command;
|
|
110
|
+
this.args = args;
|
|
111
|
+
this.cwd = cwd;
|
|
112
|
+
this.code = code;
|
|
113
|
+
this.signal = signal;
|
|
114
|
+
this.stdout = stdout;
|
|
115
|
+
this.stderr = stderr;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
67
119
|
export const execEmoji = {
|
|
68
120
|
workspace: "🏠",
|
|
69
121
|
app: "🚀",
|
|
@@ -197,22 +249,31 @@ export class Executor {
|
|
|
197
249
|
Logger.raw(chalk.red(data.toString()));
|
|
198
250
|
}
|
|
199
251
|
exec(command: string, options: ExecOptions = {}) {
|
|
252
|
+
const cwd = options.cwd?.toString() ?? this.cwdPath;
|
|
200
253
|
const proc = exec(command, { cwd: this.cwdPath, ...options });
|
|
254
|
+
let stdout = "";
|
|
255
|
+
let stderr = "";
|
|
201
256
|
proc.stdout?.on("data", (data: Buffer) => {
|
|
257
|
+
stdout += data.toString();
|
|
202
258
|
this.#stdout(data);
|
|
203
259
|
});
|
|
204
260
|
proc.stderr?.on("data", (data: Buffer) => {
|
|
261
|
+
stderr += data.toString();
|
|
205
262
|
this.#stdout(data); // 정상로그도 stderr로 나옴
|
|
206
263
|
});
|
|
207
264
|
return new Promise((resolve, reject) => {
|
|
265
|
+
proc.on("error", (error) => {
|
|
266
|
+
reject(new CommandExecutionError({ command, cwd, code: null, signal: null, stdout, stderr, cause: error }));
|
|
267
|
+
});
|
|
208
268
|
proc.on("exit", (code, signal) => {
|
|
209
|
-
if (!!code || signal) reject({ code, signal });
|
|
269
|
+
if (!!code || signal) reject(new CommandExecutionError({ command, cwd, code, signal, stdout, stderr }));
|
|
210
270
|
else resolve({ code, signal });
|
|
211
271
|
});
|
|
212
272
|
});
|
|
213
273
|
}
|
|
214
274
|
|
|
215
275
|
spawn(command: string, args: string[] = [], options: SpawnOptions = {}): Promise<string> {
|
|
276
|
+
const cwd = options.cwd?.toString() ?? this.cwdPath;
|
|
216
277
|
const proc = spawn(command, args, {
|
|
217
278
|
cwd: this.cwdPath,
|
|
218
279
|
// stdio: "inherit",
|
|
@@ -232,8 +293,14 @@ export class Executor {
|
|
|
232
293
|
this.#stdout(data); // 정상로그도 stderr로 나옴
|
|
233
294
|
});
|
|
234
295
|
return new Promise((resolve, reject) => {
|
|
296
|
+
proc.on("error", (error) => {
|
|
297
|
+
reject(
|
|
298
|
+
new CommandExecutionError({ command, args, cwd, code: null, signal: null, stdout, stderr, cause: error }),
|
|
299
|
+
);
|
|
300
|
+
});
|
|
235
301
|
proc.on("close", (code, signal) => {
|
|
236
|
-
if (code !== 0 || signal)
|
|
302
|
+
if (code !== 0 || signal)
|
|
303
|
+
reject(new CommandExecutionError({ command, args, cwd, code, signal, stdout, stderr }));
|
|
237
304
|
else resolve(stdout);
|
|
238
305
|
});
|
|
239
306
|
});
|
|
@@ -247,20 +314,40 @@ export class Executor {
|
|
|
247
314
|
return proc;
|
|
248
315
|
}
|
|
249
316
|
fork(modulePath: string, args: string[] = [], options: ForkOptions = {}) {
|
|
317
|
+
const cwd = options.cwd?.toString() ?? this.cwdPath;
|
|
250
318
|
const proc = fork(modulePath, args, {
|
|
251
319
|
cwd: this.cwdPath,
|
|
252
320
|
// stdio: ["ignore", "inherit", "inherit", "ipc"],
|
|
253
321
|
...options,
|
|
254
322
|
});
|
|
323
|
+
let stdout = "";
|
|
324
|
+
let stderr = "";
|
|
255
325
|
proc.stdout?.on("data", (data: Buffer) => {
|
|
326
|
+
stdout += data.toString();
|
|
256
327
|
this.#stdout(data);
|
|
257
328
|
});
|
|
258
329
|
proc.stderr?.on("data", (data: Buffer) => {
|
|
330
|
+
stderr += data.toString();
|
|
259
331
|
this.#stderr(data);
|
|
260
332
|
});
|
|
261
333
|
return new Promise((resolve, reject) => {
|
|
334
|
+
proc.on("error", (error) => {
|
|
335
|
+
reject(
|
|
336
|
+
new CommandExecutionError({
|
|
337
|
+
command: modulePath,
|
|
338
|
+
args,
|
|
339
|
+
cwd,
|
|
340
|
+
code: null,
|
|
341
|
+
signal: null,
|
|
342
|
+
stdout,
|
|
343
|
+
stderr,
|
|
344
|
+
cause: error,
|
|
345
|
+
}),
|
|
346
|
+
);
|
|
347
|
+
});
|
|
262
348
|
proc.on("exit", (code, signal) => {
|
|
263
|
-
if (!!code || signal)
|
|
349
|
+
if (!!code || signal)
|
|
350
|
+
reject(new CommandExecutionError({ command: modulePath, args, cwd, code, signal, stdout, stderr }));
|
|
264
351
|
else resolve({ code, signal });
|
|
265
352
|
});
|
|
266
353
|
});
|
|
@@ -143,6 +143,7 @@ export class IncrementalBuilderHost {
|
|
|
143
143
|
app.workspace.workspaceRoot,
|
|
144
144
|
"node_modules/@akanjs/devkit/incrementalBuilder/incrementalBuilder.proc.ts",
|
|
145
145
|
),
|
|
146
|
+
path.join(import.meta.dir, "incrementalBuilder.proc.js"),
|
|
146
147
|
path.join(import.meta.dir, "incrementalBuilder.proc.ts"),
|
|
147
148
|
];
|
|
148
149
|
for (const c of candidates)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akanjs/devkit",
|
|
3
|
-
"version": "2.1.0-rc.
|
|
3
|
+
"version": "2.1.0-rc.2",
|
|
4
4
|
"sourceType": "module",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@langchain/deepseek": "^1.0.26",
|
|
37
37
|
"@langchain/openai": "^1.4.6",
|
|
38
38
|
"@trapezedev/project": "^7.1.4",
|
|
39
|
-
"akanjs": "2.1.0-rc.
|
|
39
|
+
"akanjs": "2.1.0-rc.1",
|
|
40
40
|
"chalk": "^5.6.2",
|
|
41
41
|
"commander": "^14.0.3",
|
|
42
42
|
"fontaine": "^0.8.0",
|