create-loandai 0.1.0-alpha.0

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/LICENSE +21 -0
  2. package/dist/bin-create.d.ts +6 -0
  3. package/dist/bin-create.d.ts.map +1 -0
  4. package/dist/bin-create.js +16 -0
  5. package/dist/bin-create.js.map +1 -0
  6. package/dist/bin.d.ts +14 -0
  7. package/dist/bin.d.ts.map +1 -0
  8. package/dist/bin.js +46 -0
  9. package/dist/bin.js.map +1 -0
  10. package/dist/config-load.d.ts +19 -0
  11. package/dist/config-load.d.ts.map +1 -0
  12. package/dist/config-load.js +31 -0
  13. package/dist/config-load.js.map +1 -0
  14. package/dist/help.d.ts +5 -0
  15. package/dist/help.d.ts.map +1 -0
  16. package/dist/help.js +19 -0
  17. package/dist/help.js.map +1 -0
  18. package/dist/init.d.ts +11 -0
  19. package/dist/init.d.ts.map +1 -0
  20. package/dist/init.js +87 -0
  21. package/dist/init.js.map +1 -0
  22. package/dist/migrate-generate.d.ts +14 -0
  23. package/dist/migrate-generate.d.ts.map +1 -0
  24. package/dist/migrate-generate.js +62 -0
  25. package/dist/migrate-generate.js.map +1 -0
  26. package/dist/migrate.d.ts +10 -0
  27. package/dist/migrate.d.ts.map +1 -0
  28. package/dist/migrate.js +48 -0
  29. package/dist/migrate.js.map +1 -0
  30. package/dist/pkg-manager.d.ts +10 -0
  31. package/dist/pkg-manager.d.ts.map +1 -0
  32. package/dist/pkg-manager.js +30 -0
  33. package/dist/pkg-manager.js.map +1 -0
  34. package/package.json +40 -0
  35. package/template/.env.example +12 -0
  36. package/template/README.md +62 -0
  37. package/template/package.json +18 -0
  38. package/template/skills/example.md +14 -0
  39. package/template/src/agents/example.ts +19 -0
  40. package/template/src/app.ts +27 -0
  41. package/template/src/config.ts +38 -0
  42. package/template/src/tools/example.ts +23 -0
  43. package/template/tsconfig.json +19 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Londai
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `create-loandai <name>` — alias to `londai init <name>`.
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=bin-create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin-create.d.ts","sourceRoot":"","sources":["../src/bin-create.ts"],"names":[],"mappings":";AACA;;GAEG"}
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `create-loandai <name>` — alias to `londai init <name>`.
4
+ */
5
+ import { runInit } from "./init.js";
6
+ const args = process.argv.slice(2);
7
+ const name = args.find((arg) => !arg.startsWith("-"));
8
+ if (!name) {
9
+ console.error("Usage: npx create-loandai <project-name> [--no-install]");
10
+ process.exit(1);
11
+ }
12
+ runInit(name, { noInstall: args.includes("--no-install") }).catch((error) => {
13
+ console.error(error instanceof Error ? error.message : String(error));
14
+ process.exit(1);
15
+ });
16
+ //# sourceMappingURL=bin-create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin-create.js","sourceRoot":"","sources":["../src/bin-create.ts"],"names":[],"mappings":";AACA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AACtD,IAAI,CAAC,IAAI,EAAE,CAAC;IACX,OAAO,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;IACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC;AAED,OAAO,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IAC3E,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"}
package/dist/bin.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `londai` CLI entry point.
4
+ *
5
+ * Sub-commands:
6
+ * - `migrate` — apply bundled loandai migrations
7
+ * - `migrate:generate` — generate SQL migration files
8
+ * - `init` — scaffold a new londai project in cwd
9
+ * - `help` — print usage
10
+ *
11
+ * Also aliased as `create-loandai <name>` via `bin-create.ts`.
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG"}
package/dist/bin.js ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `londai` CLI entry point.
4
+ *
5
+ * Sub-commands:
6
+ * - `migrate` — apply bundled loandai migrations
7
+ * - `migrate:generate` — generate SQL migration files
8
+ * - `init` — scaffold a new londai project in cwd
9
+ * - `help` — print usage
10
+ *
11
+ * Also aliased as `create-loandai <name>` via `bin-create.ts`.
12
+ */
13
+ import { runHelp } from "./help.js";
14
+ import { runInit } from "./init.js";
15
+ import { runMigrate } from "./migrate.js";
16
+ import { runMigrateGenerate } from "./migrate-generate.js";
17
+ const cmd = process.argv[2];
18
+ const args = process.argv.slice(3);
19
+ async function main() {
20
+ switch (cmd) {
21
+ case "migrate":
22
+ await runMigrate();
23
+ break;
24
+ case "migrate:generate":
25
+ await runMigrateGenerate();
26
+ break;
27
+ case "init":
28
+ await runInit(args.find((arg) => !arg.startsWith("-")) ?? ".", { noInstall: args.includes("--no-install") });
29
+ break;
30
+ case "help":
31
+ case undefined:
32
+ case "--help":
33
+ case "-h":
34
+ runHelp();
35
+ break;
36
+ default:
37
+ console.error(`Unknown command: ${cmd}`);
38
+ runHelp();
39
+ process.exit(1);
40
+ }
41
+ }
42
+ main().catch((error) => {
43
+ console.error(error instanceof Error ? error.message : String(error));
44
+ process.exit(1);
45
+ });
46
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE3D,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC5B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAEnC,KAAK,UAAU,IAAI;IAClB,QAAQ,GAAG,EAAE,CAAC;QACb,KAAK,SAAS;YACb,MAAM,UAAU,EAAE,CAAC;YACnB,MAAM;QACP,KAAK,kBAAkB;YACtB,MAAM,kBAAkB,EAAE,CAAC;YAC3B,MAAM;QACP,KAAK,MAAM;YACV,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;YAC7G,MAAM;QACP,KAAK,MAAM,CAAC;QACZ,KAAK,SAAS,CAAC;QACf,KAAK,QAAQ,CAAC;QACd,KAAK,IAAI;YACR,OAAO,EAAE,CAAC;YACV,MAAM;QACP;YACC,OAAO,CAAC,KAAK,CAAC,oBAAoB,GAAG,EAAE,CAAC,CAAC;YACzC,OAAO,EAAE,CAAC;YACV,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACF,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACtB,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Load user's `config.ts` via jiti.
3
+ *
4
+ * Resolves:
5
+ * 1. `./londai.config.ts`
6
+ * 2. `./config.ts`
7
+ * 3. `./src/config.ts`
8
+ *
9
+ * Returns the resolved config spec (default export of type `ConfigSpec`),
10
+ * or throws a clear error if none found.
11
+ */
12
+ export interface LondaiConfig {
13
+ session?: {
14
+ url: string;
15
+ schema?: string;
16
+ };
17
+ }
18
+ export declare function loadUserConfig(cwd?: string): LondaiConfig;
19
+ //# sourceMappingURL=config-load.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-load.d.ts","sourceRoot":"","sources":["../src/config-load.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,MAAM,WAAW,YAAY;IAC5B,OAAO,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAED,wBAAgB,cAAc,CAAC,GAAG,SAAgB,GAAG,YAAY,CAiBhE"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Load user's `config.ts` via jiti.
3
+ *
4
+ * Resolves:
5
+ * 1. `./londai.config.ts`
6
+ * 2. `./config.ts`
7
+ * 3. `./src/config.ts`
8
+ *
9
+ * Returns the resolved config spec (default export of type `ConfigSpec`),
10
+ * or throws a clear error if none found.
11
+ */
12
+ import { existsSync } from "node:fs";
13
+ import { resolve } from "node:path";
14
+ import { createJiti } from "jiti";
15
+ const CANDIDATES = ["londai.config.ts", "config.ts", "src/config.ts"];
16
+ export function loadUserConfig(cwd = process.cwd()) {
17
+ for (const candidate of CANDIDATES) {
18
+ const path = resolve(cwd, candidate);
19
+ if (existsSync(path)) {
20
+ const jiti = createJiti(cwd, { alias: {} });
21
+ const mod = jiti(path);
22
+ const exports = mod.default ?? mod;
23
+ if (exports && typeof exports === "object") {
24
+ return exports;
25
+ }
26
+ }
27
+ }
28
+ throw new Error(`londai: no config file found. Buat config.ts di project root (atau src/config.ts).\n` +
29
+ ` Cek 'npx create-loandai my_app' untuk contoh scaffold.`);
30
+ }
31
+ //# sourceMappingURL=config-load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-load.js","sourceRoot":"","sources":["../src/config-load.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAElC,MAAM,UAAU,GAAG,CAAC,kBAAkB,EAAE,WAAW,EAAE,eAAe,CAAU,CAAC;AAM/E,MAAM,UAAU,cAAc,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;IACjD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACrC,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC;YAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAoD,CAAC;YAC1E,MAAM,OAAO,GAAI,GAA6B,CAAC,OAAO,IAAI,GAAG,CAAC;YAC9D,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAC5C,OAAO,OAAuB,CAAC;YAChC,CAAC;QACF,CAAC;IACF,CAAC;IAED,MAAM,IAAI,KAAK,CACd,sFAAsF;QACrF,0DAA0D,CAC3D,CAAC;AACH,CAAC"}
package/dist/help.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Print CLI usage.
3
+ */
4
+ export declare function runHelp(): void;
5
+ //# sourceMappingURL=help.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,wBAAgB,OAAO,IAAI,IAAI,CAc9B"}
package/dist/help.js ADDED
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Print CLI usage.
3
+ */
4
+ export function runHelp() {
5
+ console.log(`londai CLI
6
+
7
+ Usage:
8
+ npx londai migrate Apply bundled loandai migrations to the database
9
+ npx londai migrate:generate Generate SQL migration files to ./migrations/
10
+ npx londai init [dir] [--no-install]
11
+ Scaffold a new londai project (in cwd or <dir>)
12
+ npx create-loandai <name> [--no-install]
13
+ Create a new londai project in ./<name>/
14
+
15
+ Environment:
16
+ DATABASE_URL PostgreSQL connection string (for migrate)
17
+ `);
18
+ }
19
+ //# sourceMappingURL=help.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,UAAU,OAAO;IACtB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;CAYZ,CAAC,CAAC;AACH,CAAC"}
package/dist/init.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * `londai init [dir]` / `create-loandai <name>` — project scaffolding.
3
+ *
4
+ * Copies the `template/` directory, substitutes `{{name}}` / `{{pkgManager}}`
5
+ * placeholders, and optionally runs the detected package manager to install deps.
6
+ */
7
+ export interface InitOptions {
8
+ noInstall?: boolean;
9
+ }
10
+ export declare function runInit(name: string, opts: InitOptions): Promise<void>;
11
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,MAAM,WAAW,WAAW;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC5E"}
package/dist/init.js ADDED
@@ -0,0 +1,87 @@
1
+ /**
2
+ * `londai init [dir]` / `create-loandai <name>` — project scaffolding.
3
+ *
4
+ * Copies the `template/` directory, substitutes `{{name}}` / `{{pkgManager}}`
5
+ * placeholders, and optionally runs the detected package manager to install deps.
6
+ */
7
+ import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
8
+ import { basename, join, resolve } from "node:path";
9
+ import { fileURLToPath } from "node:url";
10
+ import { detectPackageManager, installDeps } from "./pkg-manager.js";
11
+ const __dirname = fileURLToPath(new URL(".", import.meta.url));
12
+ const TEMPLATE_DIR = resolve(__dirname, "../template");
13
+ const PACKAGE_JSON = resolve(__dirname, "../package.json");
14
+ export async function runInit(name, opts) {
15
+ const cwd = process.cwd();
16
+ const targetPath = name === "." || name === "./" ? cwd : resolve(cwd, name);
17
+ const projectName = name === "." || name === "./" ? basename(cwd) : basename(name);
18
+ if (!existsSync(TEMPLATE_DIR)) {
19
+ console.error("londai init: template/ directory not found — likely a packaging issue.");
20
+ process.exit(1);
21
+ }
22
+ // Create project folder if needed.
23
+ if (targetPath !== cwd) {
24
+ mkdirSync(targetPath, { recursive: true });
25
+ }
26
+ // Copy template recursively.
27
+ copyDir(TEMPLATE_DIR, targetPath, projectName);
28
+ // Substitute placeholders in files.
29
+ renderTemplateDir(targetPath, { name: projectName, londaiVersion: packageVersion() });
30
+ const manager = detectPackageManager(cwd);
31
+ if (!opts.noInstall) {
32
+ installDeps(targetPath, manager);
33
+ }
34
+ console.log(`\nCreated ${projectName}.`);
35
+ console.log(` cd ${projectName === basename(cwd) ? "." : projectName}`);
36
+ console.log(` ${runScriptCommand(manager, "dev")}`);
37
+ console.log(`\nOr with real providers:`);
38
+ console.log(` cp .env.example .env # edit with your API keys`);
39
+ console.log(` ${runScriptCommand(manager, "dev")}`);
40
+ }
41
+ function packageVersion() {
42
+ try {
43
+ const pkg = JSON.parse(readFileSync(PACKAGE_JSON, "utf-8"));
44
+ return typeof pkg.version === "string" ? pkg.version : "next";
45
+ }
46
+ catch {
47
+ return "next";
48
+ }
49
+ }
50
+ function runScriptCommand(manager, script) {
51
+ return manager === "npm" ? `npm run ${script}` : `${manager} ${script}`;
52
+ }
53
+ function copyDir(src, dest, projectName) {
54
+ mkdirSync(dest, { recursive: true });
55
+ const entries = readdirSync(src);
56
+ for (const entry of entries) {
57
+ const srcPath = join(src, entry);
58
+ const destPath = join(dest, entry);
59
+ const stat = statSync(srcPath);
60
+ if (stat.isDirectory()) {
61
+ if (entry === ".git" || entry === "node_modules")
62
+ continue;
63
+ copyDir(srcPath, destPath, projectName);
64
+ }
65
+ else {
66
+ writeFileSync(destPath, readFileSync(srcPath));
67
+ }
68
+ }
69
+ }
70
+ function renderTemplateDir(dir, vars) {
71
+ const entries = readdirSync(dir);
72
+ for (const entry of entries) {
73
+ const path = join(dir, entry);
74
+ const stat = statSync(path);
75
+ if (stat.isDirectory()) {
76
+ renderTemplateDir(path, vars);
77
+ }
78
+ else if (path.endsWith(".ts") || path.endsWith(".json") || path.endsWith(".md") || path.endsWith(".example")) {
79
+ let content = readFileSync(path, "utf-8");
80
+ for (const [key, value] of Object.entries(vars)) {
81
+ content = content.replaceAll(`{{${key}}}`, value);
82
+ }
83
+ writeFileSync(path, content);
84
+ }
85
+ }
86
+ }
87
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * `npx londai migrate:generate` — generate SQL migration files.
3
+ *
4
+ * Shell-outs to `drizzle-kit generate` in the user's cwd, writing output to
5
+ * `./migrations/`.
6
+ */
7
+ export interface MigrateGenerateCommand {
8
+ command: string;
9
+ args: string[];
10
+ outDir: string;
11
+ }
12
+ export declare function buildMigrateGenerateCommand(cwd: string, extraArgs?: string[]): MigrateGenerateCommand;
13
+ export declare function runMigrateGenerate(): Promise<void>;
14
+ //# sourceMappingURL=migrate-generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate-generate.d.ts","sourceRoot":"","sources":["../src/migrate-generate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAUH,MAAM,WAAW,sBAAsB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,GAAE,MAAM,EAAO,GAAG,sBAAsB,CAqBzG;AAYD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAmBxD"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * `npx londai migrate:generate` — generate SQL migration files.
3
+ *
4
+ * Shell-outs to `drizzle-kit generate` in the user's cwd, writing output to
5
+ * `./migrations/`.
6
+ */
7
+ import { spawnSync } from "node:child_process";
8
+ import { existsSync, mkdirSync } from "node:fs";
9
+ import { createRequire } from "node:module";
10
+ import { dirname, resolve } from "node:path";
11
+ import { fileURLToPath } from "node:url";
12
+ const require = createRequire(import.meta.url);
13
+ export function buildMigrateGenerateCommand(cwd, extraArgs = []) {
14
+ const cliDir = dirname(fileURLToPath(import.meta.url));
15
+ const schemaPath = resolveSessionSchemaPath(cliDir);
16
+ const outDir = resolve(cwd, "migrations");
17
+ const outArg = "migrations";
18
+ const drizzleKitBin = resolve(dirname(require.resolve("drizzle-kit")), "bin.cjs");
19
+ return {
20
+ command: process.execPath,
21
+ args: [
22
+ drizzleKitBin,
23
+ "generate",
24
+ "--schema",
25
+ schemaPath,
26
+ "--out",
27
+ outArg,
28
+ "--dialect",
29
+ "postgresql",
30
+ ...extraArgs,
31
+ ],
32
+ outDir,
33
+ };
34
+ }
35
+ function resolveSessionSchemaPath(cliDir) {
36
+ try {
37
+ const publishedSchemaPath = require.resolve("@londai/session/schema");
38
+ if (existsSync(publishedSchemaPath))
39
+ return publishedSchemaPath;
40
+ }
41
+ catch {
42
+ // Workspace tests can run before dist exists; fall back to source schema.
43
+ }
44
+ return resolve(cliDir, "../../session/src/schema.ts");
45
+ }
46
+ export async function runMigrateGenerate() {
47
+ console.log("Generating drizzle migration...");
48
+ const cmd = buildMigrateGenerateCommand(process.cwd(), process.argv.slice(3));
49
+ const outDir = cmd.outDir;
50
+ mkdirSync(outDir, { recursive: true });
51
+ const result = spawnSync(cmd.command, cmd.args, {
52
+ stdio: "inherit",
53
+ cwd: process.cwd(),
54
+ env: { ...process.env },
55
+ });
56
+ if (result.status !== 0) {
57
+ console.error("londai migrate:generate failed.");
58
+ process.exit(result.status ?? 1);
59
+ }
60
+ console.log("Migration files written to ./migrations/");
61
+ }
62
+ //# sourceMappingURL=migrate-generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate-generate.js","sourceRoot":"","sources":["../src/migrate-generate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAQ/C,MAAM,UAAU,2BAA2B,CAAC,GAAW,EAAE,YAAsB,EAAE;IAChF,MAAM,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACvD,MAAM,UAAU,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;IACpD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,YAAY,CAAC;IAC5B,MAAM,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAClF,OAAO;QACN,OAAO,EAAE,OAAO,CAAC,QAAQ;QACzB,IAAI,EAAE;YACL,aAAa;YACb,UAAU;YACV,UAAU;YACV,UAAU;YACV,OAAO;YACP,MAAM;YACN,WAAW;YACX,YAAY;YACZ,GAAG,SAAS;SACZ;QACD,MAAM;KACN,CAAC;AACH,CAAC;AAED,SAAS,wBAAwB,CAAC,MAAc;IAC/C,IAAI,CAAC;QACJ,MAAM,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;QACtE,IAAI,UAAU,CAAC,mBAAmB,CAAC;YAAE,OAAO,mBAAmB,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACR,0EAA0E;IAC3E,CAAC;IACD,OAAO,OAAO,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACvC,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IAE/C,MAAM,GAAG,GAAG,2BAA2B,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IAC1B,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEvC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,EAAE;QAC/C,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;KACvB,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `npx londai migrate` — apply bundled migrations.
3
+ *
4
+ * 1. Load user's config.ts → get `session.url` + `session.schema`.
5
+ * 2. Connect drizzle + postgres-js.
6
+ * 3. Run bundled migration files from `@londai/session/migrations`.
7
+ * 4. Output applied count.
8
+ */
9
+ export declare function runMigrate(): Promise<void>;
10
+ //# sourceMappingURL=migrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAyChD"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * `npx londai migrate` — apply bundled migrations.
3
+ *
4
+ * 1. Load user's config.ts → get `session.url` + `session.schema`.
5
+ * 2. Connect drizzle + postgres-js.
6
+ * 3. Run bundled migration files from `@londai/session/migrations`.
7
+ * 4. Output applied count.
8
+ */
9
+ import { fileURLToPath } from "node:url";
10
+ import { loadUserConfig } from "./config-load.js";
11
+ export async function runMigrate() {
12
+ const config = loadUserConfig();
13
+ const sessionUrl = config.session?.url ?? process.env.DATABASE_URL;
14
+ if (!sessionUrl) {
15
+ console.error("londai migrate: DATABASE_URL not set. Set `session.url` di config.ts, atau export DATABASE_URL env var.");
16
+ process.exit(1);
17
+ }
18
+ const schema = config.session?.schema ?? "loandai";
19
+ if (schema !== "loandai") {
20
+ console.error("londai migrate: bundled migrations currently support only schema `loandai`.");
21
+ process.exit(1);
22
+ }
23
+ // Dynamic import to keep deps optional for other commands.
24
+ const { drizzle } = await import("drizzle-orm/postgres-js");
25
+ const { migrate } = await import("drizzle-orm/postgres-js/migrator");
26
+ const postgresModule = await import("postgres");
27
+ const sql = postgresModule.default(sessionUrl, { max: 1 });
28
+ const db = drizzle(sql);
29
+ // Resolve bundled migrations from @londai/session package.
30
+ const _sessionPkg = await import("@londai/session");
31
+ // @londai/session has `exports["./migrations"]` which resolves to the migrations folder.
32
+ // Use import.meta.resolve to get the actual path.
33
+ const migrationsUrl = import.meta.resolve("@londai/session/migrations");
34
+ const migrationsFolder = fileURLToPath(migrationsUrl);
35
+ try {
36
+ await migrate(db, { migrationsFolder });
37
+ console.log("Migrations applied successfully.");
38
+ }
39
+ catch (error) {
40
+ const msg = error instanceof Error ? error.message : String(error);
41
+ console.error(`londai migrate: ${msg}`);
42
+ process.exit(1);
43
+ }
44
+ finally {
45
+ await sql.end();
46
+ }
47
+ }
48
+ //# sourceMappingURL=migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,MAAM,CAAC,KAAK,UAAU,UAAU;IAC/B,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;IAChC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IACnE,IAAI,CAAC,UAAU,EAAE,CAAC;QACjB,OAAO,CAAC,KAAK,CACZ,yGAAyG,CACzG,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,EAAE,MAAM,IAAI,SAAS,CAAC;IACnD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,6EAA6E,CAAC,CAAC;QAC7F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IAED,2DAA2D;IAC3D,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,yBAAyB,CAAC,CAAC;IAC5D,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,kCAAkC,CAAC,CAAC;IACrE,MAAM,cAAc,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IAEhD,MAAM,GAAG,GAAG,cAAc,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;IAC3D,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAExB,2DAA2D;IAC3D,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACpD,yFAAyF;IACzF,kDAAkD;IAClD,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,4BAA4B,CAAC,CAAC;IACxE,MAAM,gBAAgB,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;IAEtD,IAAI,CAAC;QACJ,MAAM,OAAO,CAAC,EAAE,EAAE,EAAE,gBAAgB,EAAE,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnE,OAAO,CAAC,KAAK,CAAC,mBAAmB,GAAG,EAAE,CAAC,CAAC;QACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;YAAS,CAAC;QACV,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC;IACjB,CAAC;AACF,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Package manager detection.
3
+ *
4
+ * Detects the user's preferred package manager from lockfiles in the
5
+ * current directory and provides install helpers.
6
+ */
7
+ export type PackageManager = "npm" | "yarn" | "pnpm";
8
+ export declare function detectPackageManager(cwd: string): PackageManager;
9
+ export declare function installDeps(cwd: string, manager: PackageManager): void;
10
+ //# sourceMappingURL=pkg-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkg-manager.d.ts","sourceRoot":"","sources":["../src/pkg-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAErD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAIhE;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,IAAI,CActE"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Package manager detection.
3
+ *
4
+ * Detects the user's preferred package manager from lockfiles in the
5
+ * current directory and provides install helpers.
6
+ */
7
+ import { spawnSync } from "node:child_process";
8
+ import { existsSync } from "node:fs";
9
+ import { resolve } from "node:path";
10
+ export function detectPackageManager(cwd) {
11
+ if (existsSync(resolve(cwd, "pnpm-lock.yaml")))
12
+ return "pnpm";
13
+ if (existsSync(resolve(cwd, "yarn.lock")))
14
+ return "yarn";
15
+ return "npm";
16
+ }
17
+ export function installDeps(cwd, manager) {
18
+ const cmd = manager === "npm" ? "npm" : manager === "yarn" ? "yarn" : "pnpm";
19
+ const args = manager === "npm" ? ["install"] : manager === "yarn" ? [] : ["install"];
20
+ console.log(`Installing dependencies with ${manager}...`);
21
+ const result = spawnSync(cmd, args, {
22
+ stdio: "inherit",
23
+ cwd,
24
+ shell: true,
25
+ });
26
+ if (result.status !== 0) {
27
+ console.warn(`Dependency install returned non-zero exit code. Run '${manager} install' manually.`);
28
+ }
29
+ }
30
+ //# sourceMappingURL=pkg-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkg-manager.js","sourceRoot":"","sources":["../src/pkg-manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC/C,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC;IAC9D,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC;IACzD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,OAAuB;IAC/D,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;IAC7E,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAErF,OAAO,CAAC,GAAG,CAAC,gCAAgC,OAAO,KAAK,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE;QACnC,KAAK,EAAE,SAAS;QAChB,GAAG;QACH,KAAK,EAAE,IAAI;KACX,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,wDAAwD,OAAO,qBAAqB,CAAC,CAAC;IACpG,CAAC;AACF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "create-loandai",
3
+ "version": "0.1.0-alpha.0",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "bin": {
7
+ "londai": "./dist/bin.js",
8
+ "create-loandai": "./dist/bin-create.js"
9
+ },
10
+ "exports": {
11
+ "./bin": "./dist/bin.js",
12
+ "./create": "./dist/bin-create.js"
13
+ },
14
+ "files": [
15
+ "dist/**/*.js",
16
+ "dist/**/*.js.map",
17
+ "dist/**/*.d.ts",
18
+ "dist/**/*.d.ts.map",
19
+ "template"
20
+ ],
21
+ "engines": {
22
+ "node": ">=24"
23
+ },
24
+ "publishConfig": {
25
+ "tag": "next"
26
+ },
27
+ "dependencies": {
28
+ "@londai/session": "0.1.0-alpha.0",
29
+ "drizzle-kit": "^0.31.6",
30
+ "drizzle-orm": "^0.44.7",
31
+ "jiti": "^2.4.2",
32
+ "postgres": "^3.4.7"
33
+ },
34
+ "devDependencies": {
35
+ "vitest": "^3.2.4"
36
+ },
37
+ "scripts": {
38
+ "build": "tsc -b"
39
+ }
40
+ }
@@ -0,0 +1,12 @@
1
+ # API keys for real providers (uncomment and fill in)
2
+ ANTHROPIC_API_KEY=
3
+ OPENAI_API_KEY=
4
+ GEMINI_API_KEY=
5
+ GOOGLE_API_KEY=
6
+ GOOGLE_GENERATIVE_AI_API_KEY=
7
+
8
+ # Database (PostgreSQL) for session persistence
9
+ DATABASE_URL=postgres://localhost:5432/{{name}}
10
+
11
+ # JWT secret for auth (production only)
12
+ JWT_SECRET=change-me-in-production
@@ -0,0 +1,62 @@
1
+ # {{name}}
2
+
3
+ Londai AI agent project. Created with `npx create-loandai`.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ # Install dependencies
9
+ pnpm install # or npm install / yarn
10
+
11
+ # Set up environment (for real providers)
12
+ cp .env.example .env
13
+ # Set GEMINI_API_KEY for Google AI Studio / Gemini.
14
+
15
+ # Optional: run migration if you enabled session persistence in src/config.ts
16
+ npx londai migrate
17
+
18
+ # Start dev server
19
+ pnpm dev # or npm run dev / yarn dev
20
+ ```
21
+
22
+ The server starts at `http://localhost:3000`.
23
+
24
+ ## API
25
+
26
+ - `POST /chat/stream` — SSE streaming chat
27
+ - `POST /chat/completion` — Non-streaming chat
28
+ - `GET /health` — Health check
29
+
30
+ ## Project structure
31
+
32
+ ```
33
+ src/
34
+ app.ts — Entry point (londai.run())
35
+ config.ts — Providers, session, auth configuration
36
+ agents/ — Agent definitions
37
+ example.ts
38
+ tools/ — Tool definitions
39
+ example.ts
40
+ skills/ — Skill markdown files
41
+ example.md
42
+ ```
43
+
44
+ ## Adding agents
45
+
46
+ ```ts
47
+ // src/agents/my-agent.ts
48
+ import { defineAgent } from "londai";
49
+
50
+ export const myAgent = defineAgent({
51
+ name: "my-agent",
52
+ provider: "google", // or "faux", "anthropic", "openai", etc.
53
+ model: "gemini-2.5-flash",
54
+ systemPrompt: "You are a helpful assistant.",
55
+ tools: [],
56
+ skills: [],
57
+ });
58
+ ```
59
+
60
+ ## Production
61
+
62
+ Set `NODE_ENV=production` and configure `auth` in `config.ts`.
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "{{name}}",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "start": "node --env-file-if-exists=.env --experimental-strip-types src/app.ts",
8
+ "dev": "node --env-file-if-exists=.env --watch --experimental-strip-types src/app.ts",
9
+ "migrate": "londai migrate"
10
+ },
11
+ "dependencies": {
12
+ "londai": "{{londaiVersion}}",
13
+ "zod": "^3.25.0"
14
+ },
15
+ "devDependencies": {
16
+ "@types/node": "^22"
17
+ }
18
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ name: example
3
+ description: An example skill. Skills are loaded from markdown files and injected into the agent's system prompt.
4
+ disableModelInvocation: false
5
+ ---
6
+
7
+ # Example Skill
8
+
9
+ This is a placeholder skill. Replace it with your own skill instructions.
10
+
11
+ Skills are markdown files with YAML frontmatter. The `name` and `description` fields
12
+ help the agent decide when to invoke this skill.
13
+
14
+ Write skill content below — guides, workflows, rules, or domain knowledge.
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Example agent — minimal londai agent with a single tool.
3
+ */
4
+
5
+ import { defineAgent } from "londai";
6
+ import { echoTool } from "../tools/example.ts";
7
+
8
+ const useGemini = Boolean(process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY || process.env.GOOGLE_GENERATIVE_AI_API_KEY);
9
+
10
+ export const exampleAgent = defineAgent({
11
+ name: "example",
12
+ description: "A minimal example agent that echoes text.",
13
+ provider: useGemini ? "google" : "faux",
14
+ model: useGemini ? "gemini-2.5-flash" : "faux-1",
15
+ systemPrompt:
16
+ "You are a helpful AI assistant. You can use the echo tool to repeat user input when asked.",
17
+ tools: [echoTool],
18
+ skills: [],
19
+ });
@@ -0,0 +1,27 @@
1
+ /**
2
+ * {{name}} — app entry point.
3
+ *
4
+ * `londai.run()` boots the Hono server with the example agent.
5
+ * `import "./config"` triggers the side-effect that registers providers.
6
+ */
7
+
8
+ import { londai } from "londai";
9
+ import "./config.ts";
10
+ import { exampleAgent } from "./agents/example.ts";
11
+
12
+ const handle = await londai.run({
13
+ agent: exampleAgent,
14
+ port: Number(process.env.PORT) || 3000,
15
+ });
16
+
17
+ console.log(`Londai server ready at http://localhost:${handle.port}`);
18
+
19
+ // Graceful shutdown
20
+ process.on("SIGTERM", () => {
21
+ console.log("Shutting down...");
22
+ handle.close();
23
+ });
24
+ process.on("SIGINT", () => {
25
+ console.log("Shutting down...");
26
+ handle.close();
27
+ });
@@ -0,0 +1,38 @@
1
+ /**
2
+ * {{name}} — londai configuration.
3
+ *
4
+ * This file registers providers, session persistence, and auth settings.
5
+ * It's loaded as a side-effect before `londai.run()`.
6
+ *
7
+ * Default: faux provider (no API key needed). Set env vars for real providers.
8
+ */
9
+
10
+ import { defineConfig } from "londai";
11
+
12
+ export default defineConfig({
13
+ providers: {
14
+ // Built-in providers (auto-detect env keys):
15
+ // anthropic: {}, // uses ANTHROPIC_API_KEY
16
+ // openai: {}, // uses OPENAI_API_KEY
17
+ google: {}, // uses GEMINI_API_KEY
18
+
19
+ // Custom OpenAI-compatible endpoints:
20
+ // ollama: { baseUrl: "http://localhost:11434/v1" },
21
+ // groq: { baseUrl: "https://api.groq.com/openai/v1", apiKey: "gsk_xxx" },
22
+
23
+ // Faux provider for dev/testing (no API key needed):
24
+ faux: {},
25
+ },
26
+
27
+ // Session persistence (PostgreSQL). Leave undefined for stateless mode.
28
+ // session: {
29
+ // url: process.env.DATABASE_URL ?? "postgres://localhost:5432/{{name}}",
30
+ // schema: "loandai",
31
+ // },
32
+
33
+ // Auth: false = no auth (dev), jwt/api-key for production.
34
+ auth: false,
35
+
36
+ // Logger level: "debug" | "info" | "warn" | "error"
37
+ logger: { level: "info" },
38
+ });
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Example tool — echoes the input text.
3
+ */
4
+
5
+ import { defineTool } from "londai";
6
+ import { z } from "zod";
7
+
8
+ export const echoTool = defineTool({
9
+ name: "echo",
10
+ description: "Echoes the given text back.",
11
+ label: "Echo",
12
+ parameters: z.object({
13
+ text: z.string().describe("The text to echo."),
14
+ }),
15
+ risk: "safe",
16
+ async execute(toolCallId, params) {
17
+ const { text } = params as { text: string };
18
+ return {
19
+ content: [{ type: "text" as const, text: `Echo: ${text}` }],
20
+ details: { echoed: text },
21
+ };
22
+ },
23
+ });
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "Node16",
5
+ "lib": ["ES2022"],
6
+ "strict": true,
7
+ "erasableSyntaxOnly": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "declaration": true,
12
+ "moduleResolution": "Node16",
13
+ "resolveJsonModule": true,
14
+ "allowImportingTsExtensions": true,
15
+ "rewriteRelativeImportExtensions": true,
16
+ "types": ["node"]
17
+ },
18
+ "include": ["src/**/*.ts"]
19
+ }