@nilejs/cli 0.0.1 → 0.0.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/dist/index.js +49 -24
- package/package.json +1 -1
- package/template/README.md +4 -4
- package/template/src/index.ts +3 -3
package/dist/index.js
CHANGED
|
@@ -18,7 +18,7 @@ var writeFileSafe = async (filePath, content) => {
|
|
|
18
18
|
await ensureDir(dirname(filePath));
|
|
19
19
|
await writeFile(filePath, content, "utf-8");
|
|
20
20
|
};
|
|
21
|
-
var readFileContent =
|
|
21
|
+
var readFileContent = (filePath) => {
|
|
22
22
|
return readFile(filePath, "utf-8");
|
|
23
23
|
};
|
|
24
24
|
var copyDir = async (src, dest) => {
|
|
@@ -49,14 +49,33 @@ var replaceInFile = async (filePath, replacements) => {
|
|
|
49
49
|
|
|
50
50
|
// src/utils/log.ts
|
|
51
51
|
import pc from "picocolors";
|
|
52
|
+
var brand = () => console.log(`
|
|
53
|
+
${pc.bold(pc.cyan("~ Nile"))}
|
|
54
|
+
`);
|
|
55
|
+
var outro = () => console.log(pc.dim(`
|
|
56
|
+
Happy hacking. Let code flow like river Nile.
|
|
57
|
+
`));
|
|
52
58
|
var success = (msg) => console.log(pc.green(` ✓ ${msg}`));
|
|
53
|
-
var info = (msg) => console.log(pc.cyan(` ${msg}`));
|
|
54
59
|
var warn = (msg) => console.log(pc.yellow(` ⚠ ${msg}`));
|
|
55
60
|
var error = (msg) => console.error(pc.red(` ✗ ${msg}`));
|
|
56
|
-
var header = (msg) => console.log(`
|
|
57
|
-
${pc.bold(msg)}
|
|
58
|
-
`);
|
|
59
61
|
var hint = (msg) => console.log(pc.dim(` ${msg}`));
|
|
62
|
+
var SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
63
|
+
var createSpinner = (msg) => {
|
|
64
|
+
let i = 0;
|
|
65
|
+
const stream = process.stdout;
|
|
66
|
+
const id = setInterval(() => {
|
|
67
|
+
const frame = SPINNER_FRAMES[i % SPINNER_FRAMES.length];
|
|
68
|
+
stream.write(`\r ${pc.cyan(frame)} ${msg}`);
|
|
69
|
+
i++;
|
|
70
|
+
}, 80);
|
|
71
|
+
return {
|
|
72
|
+
stop: (finalMsg) => {
|
|
73
|
+
clearInterval(id);
|
|
74
|
+
stream.write(`\r ${pc.green("✓")} ${finalMsg}
|
|
75
|
+
`);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
};
|
|
60
79
|
|
|
61
80
|
// src/commands/generate-action.ts
|
|
62
81
|
var toCamelCase = (str) => str.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
|
|
@@ -92,7 +111,7 @@ var generateActionCommand = async (serviceName, actionName) => {
|
|
|
92
111
|
const serviceDir = resolve(process.cwd(), "src/services", serviceName);
|
|
93
112
|
if (!pathExists(serviceDir)) {
|
|
94
113
|
error(`Service "${serviceName}" not found at src/services/${serviceName}/`);
|
|
95
|
-
hint(
|
|
114
|
+
hint(`Create the service first: nile generate service ${serviceName}`);
|
|
96
115
|
process.exit(1);
|
|
97
116
|
}
|
|
98
117
|
const actionFile = resolve(serviceDir, `${actionName}.ts`);
|
|
@@ -100,13 +119,15 @@ var generateActionCommand = async (serviceName, actionName) => {
|
|
|
100
119
|
error(`Action file "${actionName}.ts" already exists in src/services/${serviceName}/`);
|
|
101
120
|
process.exit(1);
|
|
102
121
|
}
|
|
103
|
-
|
|
122
|
+
brand();
|
|
123
|
+
const spinner = createSpinner(`Creating action ${actionName}...`);
|
|
104
124
|
await writeFileSafe(actionFile, generateActionContent(actionName, serviceName));
|
|
105
|
-
|
|
125
|
+
spinner.stop(`Action created at src/services/${serviceName}/${actionName}.ts`);
|
|
106
126
|
const camel = toCamelCase(actionName);
|
|
107
|
-
|
|
108
|
-
hint("
|
|
127
|
+
console.log("");
|
|
128
|
+
hint("Register the action in your service config:");
|
|
109
129
|
hint(` import { ${camel}Action } from "./${serviceName}/${actionName}";`);
|
|
130
|
+
outro();
|
|
110
131
|
};
|
|
111
132
|
|
|
112
133
|
// src/commands/generate-service.ts
|
|
@@ -114,7 +135,7 @@ import { resolve as resolve2 } from "node:path";
|
|
|
114
135
|
|
|
115
136
|
// src/utils/prompt.ts
|
|
116
137
|
import { createInterface } from "node:readline";
|
|
117
|
-
var confirmPrompt =
|
|
138
|
+
var confirmPrompt = (question, defaultYes = true) => {
|
|
118
139
|
const suffix = defaultYes ? "[Y/n]" : "[y/N]";
|
|
119
140
|
const rl = createInterface({
|
|
120
141
|
input: process.stdin,
|
|
@@ -225,25 +246,26 @@ var generateServiceCommand = async (serviceName) => {
|
|
|
225
246
|
error(`Service "${serviceName}" already exists at src/services/${serviceName}/`);
|
|
226
247
|
process.exit(1);
|
|
227
248
|
}
|
|
228
|
-
|
|
249
|
+
brand();
|
|
250
|
+
const spinner = createSpinner(`Creating service ${serviceName}...`);
|
|
229
251
|
await ensureDir(serviceDir);
|
|
230
|
-
info("Creating demo action...");
|
|
231
252
|
await writeFileSafe(resolve2(serviceDir, "sample.ts"), generateActionContent2(serviceName));
|
|
232
|
-
info("Creating barrel export...");
|
|
233
253
|
await writeFileSafe(resolve2(serviceDir, "index.ts"), generateBarrelContent(serviceName));
|
|
234
|
-
|
|
254
|
+
spinner.stop(`Service created at src/services/${serviceName}/`);
|
|
235
255
|
const configPath = resolve2(servicesDir, "services.config.ts");
|
|
236
256
|
if (!pathExists(configPath)) {
|
|
237
257
|
warn("Could not find services.config.ts");
|
|
238
|
-
|
|
258
|
+
console.log("");
|
|
259
|
+
hint("Add this to your services config:");
|
|
239
260
|
console.log(generateConfigSnippet(serviceName));
|
|
261
|
+
outro();
|
|
240
262
|
return;
|
|
241
263
|
}
|
|
242
264
|
const shouldRegister = await confirmPrompt("Register this service in services.config.ts?");
|
|
243
265
|
if (shouldRegister) {
|
|
244
266
|
const registered = await autoRegisterService(configPath, serviceName);
|
|
245
267
|
if (registered) {
|
|
246
|
-
success("
|
|
268
|
+
success("Registered in services.config.ts");
|
|
247
269
|
} else {
|
|
248
270
|
warn("Could not auto-register. Add manually:");
|
|
249
271
|
console.log(`
|
|
@@ -251,9 +273,11 @@ ${generateConfigSnippet(serviceName)}
|
|
|
251
273
|
`);
|
|
252
274
|
}
|
|
253
275
|
} else {
|
|
254
|
-
|
|
276
|
+
console.log("");
|
|
277
|
+
hint("Add this to your services config:");
|
|
255
278
|
console.log(generateConfigSnippet(serviceName));
|
|
256
279
|
}
|
|
280
|
+
outro();
|
|
257
281
|
};
|
|
258
282
|
|
|
259
283
|
// src/commands/new.ts
|
|
@@ -277,11 +301,10 @@ var newCommand = async (projectName) => {
|
|
|
277
301
|
error(`Directory "${projectName}" already exists.`);
|
|
278
302
|
process.exit(1);
|
|
279
303
|
}
|
|
280
|
-
|
|
304
|
+
brand();
|
|
305
|
+
const spinner = createSpinner(`Creating ${projectName}...`);
|
|
281
306
|
const templateDir = resolveTemplateDir();
|
|
282
|
-
info("Copying project files...");
|
|
283
307
|
await copyDir(templateDir, targetDir);
|
|
284
|
-
info("Configuring project...");
|
|
285
308
|
const allFiles = await getFilesRecursive(targetDir);
|
|
286
309
|
const replacements = { "{{projectName}}": projectName };
|
|
287
310
|
for (const filePath of allFiles) {
|
|
@@ -289,12 +312,14 @@ var newCommand = async (projectName) => {
|
|
|
289
312
|
await replaceInFile(filePath, replacements);
|
|
290
313
|
}
|
|
291
314
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
315
|
+
spinner.stop("Project ready.");
|
|
316
|
+
success(`Created ${projectName}`);
|
|
317
|
+
console.log("");
|
|
318
|
+
hint("cd " + projectName);
|
|
295
319
|
hint("bun install");
|
|
296
320
|
hint("cp .env.example .env");
|
|
297
321
|
hint("bun run dev");
|
|
322
|
+
outro();
|
|
298
323
|
};
|
|
299
324
|
|
|
300
325
|
// src/index.ts
|
package/package.json
CHANGED
package/template/README.md
CHANGED
|
@@ -10,7 +10,7 @@ cp .env.example .env
|
|
|
10
10
|
bun run dev
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
The server starts at `http://localhost:
|
|
13
|
+
The server starts at `http://localhost:8000`. PGLite creates an embedded Postgres database automatically, no external database required.
|
|
14
14
|
|
|
15
15
|
## Scripts
|
|
16
16
|
|
|
@@ -51,7 +51,7 @@ All requests go through a single POST endpoint. The `intent` field determines th
|
|
|
51
51
|
### Explore available services
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
|
-
curl -X POST http://localhost:
|
|
54
|
+
curl -X POST http://localhost:8000/api/services \
|
|
55
55
|
-H "Content-Type: application/json" \
|
|
56
56
|
-d '{"intent":"explore","service":"*","action":"*","payload":{}}'
|
|
57
57
|
```
|
|
@@ -59,7 +59,7 @@ curl -X POST http://localhost:3000/api/services \
|
|
|
59
59
|
### Execute an action
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
|
-
curl -X POST http://localhost:
|
|
62
|
+
curl -X POST http://localhost:8000/api/services \
|
|
63
63
|
-H "Content-Type: application/json" \
|
|
64
64
|
-d '{"intent":"execute","service":"tasks","action":"create","payload":{"title":"My first task"}}'
|
|
65
65
|
```
|
|
@@ -67,7 +67,7 @@ curl -X POST http://localhost:3000/api/services \
|
|
|
67
67
|
### Get action schemas
|
|
68
68
|
|
|
69
69
|
```bash
|
|
70
|
-
curl -X POST http://localhost:
|
|
70
|
+
curl -X POST http://localhost:8000/api/services \
|
|
71
71
|
-H "Content-Type: application/json" \
|
|
72
72
|
-d '{"intent":"schema","service":"tasks","action":"*","payload":{}}'
|
|
73
73
|
```
|
package/template/src/index.ts
CHANGED
|
@@ -36,8 +36,8 @@ const server = createNileServer({
|
|
|
36
36
|
rest: {
|
|
37
37
|
baseUrl: "/api",
|
|
38
38
|
host: "localhost",
|
|
39
|
-
port:
|
|
40
|
-
allowedOrigins: ["http://localhost:
|
|
39
|
+
port: 8000,
|
|
40
|
+
allowedOrigins: ["http://localhost:8000"],
|
|
41
41
|
enableStatus: true,
|
|
42
42
|
},
|
|
43
43
|
onBoot: {
|
|
@@ -52,7 +52,7 @@ const server = createNileServer({
|
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
if (server.rest) {
|
|
55
|
-
const port = server.config.rest?.port ??
|
|
55
|
+
const port = server.config.rest?.port ?? 8000;
|
|
56
56
|
const { fetch } = server.rest.app;
|
|
57
57
|
|
|
58
58
|
Bun.serve({ port, fetch });
|