@voltx/cli 0.3.2 → 0.3.3
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/chunk-HAFJKS2O.mjs +141 -0
- package/dist/chunk-HM7F67C2.mjs +405 -0
- package/dist/cli.js +3 -3
- package/dist/create.js +1 -1
- package/dist/create.mjs +1 -1
- package/dist/generate.js +1 -1
- package/dist/generate.mjs +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -3
- package/dist/index.mjs +3 -3
- package/package.json +1 -1
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// src/generate.ts
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from "fs";
|
|
3
|
+
import { join, dirname } from "path";
|
|
4
|
+
async function runGenerate(options) {
|
|
5
|
+
const cwd = process.cwd();
|
|
6
|
+
const { type, name } = options;
|
|
7
|
+
switch (type) {
|
|
8
|
+
case "route":
|
|
9
|
+
generateRoute(cwd, name, options.method);
|
|
10
|
+
break;
|
|
11
|
+
case "agent":
|
|
12
|
+
generateAgent(cwd, name);
|
|
13
|
+
break;
|
|
14
|
+
case "tool":
|
|
15
|
+
generateTool(cwd, name);
|
|
16
|
+
break;
|
|
17
|
+
case "job":
|
|
18
|
+
generateJob(cwd, name);
|
|
19
|
+
break;
|
|
20
|
+
default:
|
|
21
|
+
console.error(`[voltx] Unknown generator type: ${type}`);
|
|
22
|
+
console.error("[voltx] Available: route, agent, tool, job");
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function generateRoute(cwd, name, method = "POST") {
|
|
27
|
+
const routePath = name.startsWith("/") ? name.slice(1) : name;
|
|
28
|
+
const filePath = join(cwd, "src", "routes", `${routePath}.ts`);
|
|
29
|
+
if (existsSync(filePath)) {
|
|
30
|
+
console.error(`[voltx] Route already exists: src/routes/${routePath}.ts`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
const upperMethod = method.toUpperCase();
|
|
34
|
+
const urlPath = "/" + routePath;
|
|
35
|
+
const content = `// ${upperMethod} ${urlPath}
|
|
36
|
+
import type { Context } from "@voltx/server";
|
|
37
|
+
|
|
38
|
+
export async function ${upperMethod}(c: Context) {
|
|
39
|
+
return c.json({ message: "Hello from ${urlPath}" });
|
|
40
|
+
}
|
|
41
|
+
`;
|
|
42
|
+
writeFileSafe(filePath, content);
|
|
43
|
+
console.log(` \u2713 Created route: src/routes/${routePath}.ts`);
|
|
44
|
+
console.log(` ${upperMethod} ${urlPath}`);
|
|
45
|
+
}
|
|
46
|
+
function generateAgent(cwd, name) {
|
|
47
|
+
const filePath = join(cwd, "src", "agents", `${name}.ts`);
|
|
48
|
+
if (existsSync(filePath)) {
|
|
49
|
+
console.error(`[voltx] Agent already exists: src/agents/${name}.ts`);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
const content = `// Agent: ${name}
|
|
53
|
+
import { createAgent } from "@voltx/agents";
|
|
54
|
+
|
|
55
|
+
export const ${toCamelCase(name)} = createAgent({
|
|
56
|
+
name: "${name}",
|
|
57
|
+
model: "cerebras:llama3.1-8b",
|
|
58
|
+
instructions: "You are a helpful AI assistant named ${name}.",
|
|
59
|
+
tools: [
|
|
60
|
+
// Add tools here:
|
|
61
|
+
// {
|
|
62
|
+
// name: "example",
|
|
63
|
+
// description: "An example tool",
|
|
64
|
+
// parameters: { type: "object", properties: { input: { type: "string" } }, required: ["input"] },
|
|
65
|
+
// execute: async (params) => \`Processed: \${params.input}\`,
|
|
66
|
+
// },
|
|
67
|
+
],
|
|
68
|
+
});
|
|
69
|
+
`;
|
|
70
|
+
writeFileSafe(filePath, content);
|
|
71
|
+
console.log(` \u2713 Created agent: src/agents/${name}.ts`);
|
|
72
|
+
}
|
|
73
|
+
function generateTool(cwd, name) {
|
|
74
|
+
const filePath = join(cwd, "src", "tools", `${name}.ts`);
|
|
75
|
+
if (existsSync(filePath)) {
|
|
76
|
+
console.error(`[voltx] Tool already exists: src/tools/${name}.ts`);
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
const content = `// Tool: ${name}
|
|
80
|
+
|
|
81
|
+
export const ${toCamelCase(name)}Tool = {
|
|
82
|
+
name: "${name}",
|
|
83
|
+
description: "TODO: Describe what this tool does",
|
|
84
|
+
parameters: {
|
|
85
|
+
type: "object" as const,
|
|
86
|
+
properties: {
|
|
87
|
+
input: { type: "string", description: "The input to process" },
|
|
88
|
+
},
|
|
89
|
+
required: ["input"],
|
|
90
|
+
},
|
|
91
|
+
execute: async (params: { input: string }): Promise<string> => {
|
|
92
|
+
// TODO: Implement tool logic
|
|
93
|
+
return \`${name} result for: \${params.input}\`;
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
`;
|
|
97
|
+
writeFileSafe(filePath, content);
|
|
98
|
+
console.log(` \u2713 Created tool: src/tools/${name}.ts`);
|
|
99
|
+
}
|
|
100
|
+
function generateJob(cwd, name) {
|
|
101
|
+
const filePath = join(cwd, "src", "jobs", `${name}.ts`);
|
|
102
|
+
if (existsSync(filePath)) {
|
|
103
|
+
console.error(`[voltx] Job already exists: src/jobs/${name}.ts`);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
const content = `// Job: ${name}
|
|
107
|
+
// Runs on a schedule or triggered via ctx.jobs.enqueue("${name}", data)
|
|
108
|
+
|
|
109
|
+
export const config = {
|
|
110
|
+
// Cron schedule (uncomment to enable):
|
|
111
|
+
// schedule: "0 */6 * * *", // every 6 hours
|
|
112
|
+
//
|
|
113
|
+
// Or make it a queue job (triggered on-demand):
|
|
114
|
+
queue: true,
|
|
115
|
+
retries: 3,
|
|
116
|
+
timeout: "5m",
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export async function run(ctx: any, data?: Record<string, unknown>) {
|
|
120
|
+
console.log("[job:${name}] Running...", data);
|
|
121
|
+
|
|
122
|
+
// TODO: Implement job logic
|
|
123
|
+
|
|
124
|
+
console.log("[job:${name}] Done.");
|
|
125
|
+
}
|
|
126
|
+
`;
|
|
127
|
+
writeFileSafe(filePath, content);
|
|
128
|
+
console.log(` \u2713 Created job: src/jobs/${name}.ts`);
|
|
129
|
+
}
|
|
130
|
+
function writeFileSafe(filePath, content) {
|
|
131
|
+
const dir = dirname(filePath);
|
|
132
|
+
mkdirSync(dir, { recursive: true });
|
|
133
|
+
writeFileSync(filePath, content, "utf-8");
|
|
134
|
+
}
|
|
135
|
+
function toCamelCase(str) {
|
|
136
|
+
return str.replace(/[-_](.)/g, (_, c) => c.toUpperCase()).replace(/^(.)/, (_, c) => c.toLowerCase());
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export {
|
|
140
|
+
runGenerate
|
|
141
|
+
};
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import {
|
|
2
|
+
printWelcomeBanner
|
|
3
|
+
} from "./chunk-IV352HZA.mjs";
|
|
4
|
+
import {
|
|
5
|
+
__require
|
|
6
|
+
} from "./chunk-Y6FXYEAI.mjs";
|
|
7
|
+
|
|
8
|
+
// src/create.ts
|
|
9
|
+
import * as fs from "fs";
|
|
10
|
+
import * as path from "path";
|
|
11
|
+
async function createProject(options) {
|
|
12
|
+
const { name, template = "blank", auth = "none" } = options;
|
|
13
|
+
const targetDir = path.resolve(process.cwd(), name);
|
|
14
|
+
if (fs.existsSync(targetDir)) {
|
|
15
|
+
console.error(`[voltx] Directory "${name}" already exists.`);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
19
|
+
const templateDeps = {
|
|
20
|
+
blank: {
|
|
21
|
+
"@voltx/core": "^0.3.0",
|
|
22
|
+
"@voltx/server": "^0.3.0"
|
|
23
|
+
},
|
|
24
|
+
chatbot: {
|
|
25
|
+
"@voltx/core": "^0.3.0",
|
|
26
|
+
"@voltx/ai": "^0.3.0",
|
|
27
|
+
"@voltx/server": "^0.3.0",
|
|
28
|
+
"@voltx/memory": "^0.3.0"
|
|
29
|
+
},
|
|
30
|
+
"rag-app": {
|
|
31
|
+
"@voltx/core": "^0.3.0",
|
|
32
|
+
"@voltx/ai": "^0.3.0",
|
|
33
|
+
"@voltx/server": "^0.3.0",
|
|
34
|
+
"@voltx/rag": "^0.3.0",
|
|
35
|
+
"@voltx/db": "^0.3.0"
|
|
36
|
+
},
|
|
37
|
+
"agent-app": {
|
|
38
|
+
"@voltx/core": "^0.3.0",
|
|
39
|
+
"@voltx/ai": "^0.3.0",
|
|
40
|
+
"@voltx/server": "^0.3.0",
|
|
41
|
+
"@voltx/agents": "^0.3.0",
|
|
42
|
+
"@voltx/memory": "^0.3.0"
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const packageJson = {
|
|
46
|
+
name,
|
|
47
|
+
version: "0.1.0",
|
|
48
|
+
private: true,
|
|
49
|
+
scripts: {
|
|
50
|
+
dev: "voltx dev",
|
|
51
|
+
build: "voltx build",
|
|
52
|
+
start: "voltx start"
|
|
53
|
+
},
|
|
54
|
+
dependencies: {
|
|
55
|
+
...templateDeps[template] ?? templateDeps["blank"],
|
|
56
|
+
"@voltx/cli": "^0.3.0",
|
|
57
|
+
...auth === "better-auth" ? { "@voltx/auth": "^0.3.0", "better-auth": "^1.5.0" } : {},
|
|
58
|
+
...auth === "jwt" ? { "@voltx/auth": "^0.3.0", "jose": "^6.0.0" } : {}
|
|
59
|
+
},
|
|
60
|
+
devDependencies: {
|
|
61
|
+
typescript: "^5.7.0",
|
|
62
|
+
tsx: "^4.21.0",
|
|
63
|
+
tsup: "^8.0.0",
|
|
64
|
+
"@types/node": "^22.0.0"
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
fs.writeFileSync(
|
|
68
|
+
path.join(targetDir, "package.json"),
|
|
69
|
+
JSON.stringify(packageJson, null, 2)
|
|
70
|
+
);
|
|
71
|
+
const hasDb = template === "rag-app" || template === "agent-app" || auth === "better-auth";
|
|
72
|
+
const provider = template === "rag-app" ? "openai" : "cerebras";
|
|
73
|
+
const model = template === "rag-app" ? "gpt-4o" : "llama3.1-8b";
|
|
74
|
+
let configContent = `import { defineConfig } from "@voltx/core";
|
|
75
|
+
|
|
76
|
+
export default defineConfig({
|
|
77
|
+
name: "${name}",
|
|
78
|
+
port: 3000,
|
|
79
|
+
ai: {
|
|
80
|
+
provider: "${provider}",
|
|
81
|
+
model: "${model}",
|
|
82
|
+
},`;
|
|
83
|
+
if (hasDb) {
|
|
84
|
+
configContent += `
|
|
85
|
+
db: {
|
|
86
|
+
url: process.env.DATABASE_URL,
|
|
87
|
+
},`;
|
|
88
|
+
}
|
|
89
|
+
if (auth !== "none") {
|
|
90
|
+
configContent += `
|
|
91
|
+
auth: {
|
|
92
|
+
provider: "${auth}",
|
|
93
|
+
},`;
|
|
94
|
+
}
|
|
95
|
+
configContent += `
|
|
96
|
+
server: {
|
|
97
|
+
routesDir: "src/routes",
|
|
98
|
+
staticDir: "public",
|
|
99
|
+
cors: true,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
`;
|
|
103
|
+
fs.writeFileSync(path.join(targetDir, "voltx.config.ts"), configContent);
|
|
104
|
+
fs.mkdirSync(path.join(targetDir, "src", "routes", "api"), { recursive: true });
|
|
105
|
+
fs.mkdirSync(path.join(targetDir, "public"), { recursive: true });
|
|
106
|
+
fs.writeFileSync(
|
|
107
|
+
path.join(targetDir, "src", "index.ts"),
|
|
108
|
+
`import { createApp } from "@voltx/core";
|
|
109
|
+
import config from "../voltx.config";
|
|
110
|
+
|
|
111
|
+
const app = createApp(config);
|
|
112
|
+
app.start();
|
|
113
|
+
`
|
|
114
|
+
);
|
|
115
|
+
fs.writeFileSync(
|
|
116
|
+
path.join(targetDir, "src", "routes", "index.ts"),
|
|
117
|
+
`// GET / \u2014 Health check
|
|
118
|
+
import type { Context } from "@voltx/server";
|
|
119
|
+
|
|
120
|
+
export function GET(c: Context) {
|
|
121
|
+
return c.json({ name: "${name}", status: "ok" });
|
|
122
|
+
}
|
|
123
|
+
`
|
|
124
|
+
);
|
|
125
|
+
if (template === "chatbot" || template === "agent-app") {
|
|
126
|
+
fs.writeFileSync(
|
|
127
|
+
path.join(targetDir, "src", "routes", "api", "chat.ts"),
|
|
128
|
+
`// POST /api/chat \u2014 Streaming chat with conversation memory
|
|
129
|
+
import type { Context } from "@voltx/server";
|
|
130
|
+
import { streamText } from "@voltx/ai";
|
|
131
|
+
import { createMemory } from "@voltx/memory";
|
|
132
|
+
|
|
133
|
+
// In-memory for dev; swap to createMemory("postgres", { url }) for production
|
|
134
|
+
const memory = createMemory({ maxMessages: 50 });
|
|
135
|
+
|
|
136
|
+
export async function POST(c: Context) {
|
|
137
|
+
const { messages, conversationId = "default" } = await c.req.json();
|
|
138
|
+
|
|
139
|
+
// Store the latest user message
|
|
140
|
+
const lastMessage = messages[messages.length - 1];
|
|
141
|
+
if (lastMessage?.role === "user") {
|
|
142
|
+
await memory.add(conversationId, { role: "user", content: lastMessage.content });
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Get conversation history from memory
|
|
146
|
+
const history = await memory.get(conversationId);
|
|
147
|
+
|
|
148
|
+
const result = await streamText({
|
|
149
|
+
model: "${provider}:${model}",
|
|
150
|
+
system: "You are a helpful AI assistant.",
|
|
151
|
+
messages: history.map((m) => ({ role: m.role, content: m.content })),
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Store assistant response after stream completes
|
|
155
|
+
result.text.then(async (text) => {
|
|
156
|
+
await memory.add(conversationId, { role: "assistant", content: text });
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
return result.toSSEResponse();
|
|
160
|
+
}
|
|
161
|
+
`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
if (template === "agent-app") {
|
|
165
|
+
fs.mkdirSync(path.join(targetDir, "src", "agents"), { recursive: true });
|
|
166
|
+
fs.mkdirSync(path.join(targetDir, "src", "tools"), { recursive: true });
|
|
167
|
+
fs.writeFileSync(
|
|
168
|
+
path.join(targetDir, "src", "agents", "assistant.ts"),
|
|
169
|
+
`import { createAgent } from "@voltx/agents";
|
|
170
|
+
import { searchTool } from "../tools/search";
|
|
171
|
+
|
|
172
|
+
export const assistant = createAgent({
|
|
173
|
+
name: "assistant",
|
|
174
|
+
model: "${provider}:${model}",
|
|
175
|
+
instructions: "You are a helpful AI assistant. Use your tools when needed.",
|
|
176
|
+
tools: [searchTool],
|
|
177
|
+
maxIterations: 5,
|
|
178
|
+
});
|
|
179
|
+
`
|
|
180
|
+
);
|
|
181
|
+
fs.writeFileSync(
|
|
182
|
+
path.join(targetDir, "src", "tools", "search.ts"),
|
|
183
|
+
`import type { Tool } from "@voltx/agents";
|
|
184
|
+
|
|
185
|
+
export const searchTool: Tool = {
|
|
186
|
+
name: "search",
|
|
187
|
+
description: "Search for information on a topic.",
|
|
188
|
+
parameters: {
|
|
189
|
+
type: "object",
|
|
190
|
+
properties: { query: { type: "string", description: "The search query" } },
|
|
191
|
+
required: ["query"],
|
|
192
|
+
},
|
|
193
|
+
async execute(args: { query: string }) {
|
|
194
|
+
return \`Search results for "\${args.query}": Placeholder \u2014 connect a real search API.\`;
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
`
|
|
198
|
+
);
|
|
199
|
+
fs.writeFileSync(
|
|
200
|
+
path.join(targetDir, "src", "routes", "api", "agent.ts"),
|
|
201
|
+
`import type { Context } from "@voltx/server";
|
|
202
|
+
import { assistant } from "../../agents/assistant";
|
|
203
|
+
|
|
204
|
+
export async function POST(c: Context) {
|
|
205
|
+
const { input } = await c.req.json();
|
|
206
|
+
if (!input) return c.json({ error: "Missing 'input' field" }, 400);
|
|
207
|
+
const result = await assistant.run(input);
|
|
208
|
+
return c.json({ content: result.content, steps: result.steps });
|
|
209
|
+
}
|
|
210
|
+
`
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
if (template === "rag-app") {
|
|
214
|
+
const embedModel = "openai:text-embedding-3-small";
|
|
215
|
+
fs.mkdirSync(path.join(targetDir, "src", "routes", "api", "rag"), { recursive: true });
|
|
216
|
+
fs.writeFileSync(
|
|
217
|
+
path.join(targetDir, "src", "routes", "api", "rag", "query.ts"),
|
|
218
|
+
`// POST /api/rag/query \u2014 Query documents with RAG
|
|
219
|
+
import type { Context } from "@voltx/server";
|
|
220
|
+
import { streamText } from "@voltx/ai";
|
|
221
|
+
import { createRAGPipeline, createEmbedder } from "@voltx/rag";
|
|
222
|
+
import { createVectorStore } from "@voltx/db";
|
|
223
|
+
|
|
224
|
+
const vectorStore = createVectorStore(); // swap to "pinecone" or "pgvector" for production
|
|
225
|
+
const embedder = createEmbedder({ model: "${embedModel}" });
|
|
226
|
+
const rag = createRAGPipeline({ embedder, vectorStore });
|
|
227
|
+
|
|
228
|
+
export async function POST(c: Context) {
|
|
229
|
+
const { question } = await c.req.json();
|
|
230
|
+
|
|
231
|
+
const context = await rag.getContext(question, { topK: 5 });
|
|
232
|
+
|
|
233
|
+
const result = await streamText({
|
|
234
|
+
model: "${provider}:${model}",
|
|
235
|
+
system: \`Answer the user's question based on the following context. If the context doesn't contain relevant information, say so.\\n\\nContext:\\n\${context}\`,
|
|
236
|
+
messages: [{ role: "user", content: question }],
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
return result.toSSEResponse();
|
|
240
|
+
}
|
|
241
|
+
`
|
|
242
|
+
);
|
|
243
|
+
fs.writeFileSync(
|
|
244
|
+
path.join(targetDir, "src", "routes", "api", "rag", "ingest.ts"),
|
|
245
|
+
`// POST /api/rag/ingest \u2014 Ingest documents into the vector store
|
|
246
|
+
import type { Context } from "@voltx/server";
|
|
247
|
+
import { createRAGPipeline, createEmbedder } from "@voltx/rag";
|
|
248
|
+
import { createVectorStore } from "@voltx/db";
|
|
249
|
+
|
|
250
|
+
const vectorStore = createVectorStore();
|
|
251
|
+
const embedder = createEmbedder({ model: "${embedModel}" });
|
|
252
|
+
const rag = createRAGPipeline({ embedder, vectorStore });
|
|
253
|
+
|
|
254
|
+
export async function POST(c: Context) {
|
|
255
|
+
const { text, idPrefix } = await c.req.json();
|
|
256
|
+
|
|
257
|
+
if (!text || typeof text !== "string") {
|
|
258
|
+
return c.json({ error: "Missing 'text' field" }, 400);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const result = await rag.ingest(text, idPrefix ?? "doc");
|
|
262
|
+
return c.json({ status: "ok", chunks: result.chunks, ids: result.ids });
|
|
263
|
+
}
|
|
264
|
+
`
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
if (auth === "better-auth") {
|
|
268
|
+
fs.mkdirSync(path.join(targetDir, "src", "routes", "api", "auth"), { recursive: true });
|
|
269
|
+
fs.writeFileSync(
|
|
270
|
+
path.join(targetDir, "src", "routes", "api", "auth", "[...path].ts"),
|
|
271
|
+
`// ALL /api/auth/* \u2014 Better Auth handler
|
|
272
|
+
import type { Context } from "@voltx/server";
|
|
273
|
+
import { auth } from "../../../lib/auth";
|
|
274
|
+
import { createAuthHandler } from "@voltx/auth";
|
|
275
|
+
|
|
276
|
+
const handler = createAuthHandler(auth);
|
|
277
|
+
|
|
278
|
+
export const GET = (c: Context) => handler(c);
|
|
279
|
+
export const POST = (c: Context) => handler(c);
|
|
280
|
+
`
|
|
281
|
+
);
|
|
282
|
+
fs.mkdirSync(path.join(targetDir, "src", "lib"), { recursive: true });
|
|
283
|
+
fs.writeFileSync(
|
|
284
|
+
path.join(targetDir, "src", "lib", "auth.ts"),
|
|
285
|
+
`// Auth configuration \u2014 Better Auth with DB-backed sessions
|
|
286
|
+
import { createAuth, createAuthMiddleware } from "@voltx/auth";
|
|
287
|
+
|
|
288
|
+
export const auth = createAuth("better-auth", {
|
|
289
|
+
database: process.env.DATABASE_URL!,
|
|
290
|
+
emailAndPassword: true,
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
export const authMiddleware = createAuthMiddleware({
|
|
294
|
+
provider: auth,
|
|
295
|
+
publicPaths: ["/api/auth", "/api/health", "/"],
|
|
296
|
+
});
|
|
297
|
+
`
|
|
298
|
+
);
|
|
299
|
+
} else if (auth === "jwt") {
|
|
300
|
+
fs.mkdirSync(path.join(targetDir, "src", "lib"), { recursive: true });
|
|
301
|
+
fs.writeFileSync(
|
|
302
|
+
path.join(targetDir, "src", "lib", "auth.ts"),
|
|
303
|
+
`// Auth configuration \u2014 JWT (stateless)
|
|
304
|
+
import { createAuth, createAuthMiddleware } from "@voltx/auth";
|
|
305
|
+
|
|
306
|
+
export const jwt = createAuth("jwt", {
|
|
307
|
+
secret: process.env.JWT_SECRET!,
|
|
308
|
+
expiresIn: "7d",
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
export const authMiddleware = createAuthMiddleware({
|
|
312
|
+
provider: jwt,
|
|
313
|
+
publicPaths: ["/api/auth", "/api/health", "/"],
|
|
314
|
+
});
|
|
315
|
+
`
|
|
316
|
+
);
|
|
317
|
+
fs.writeFileSync(
|
|
318
|
+
path.join(targetDir, "src", "routes", "api", "auth.ts"),
|
|
319
|
+
`// POST /api/auth/login \u2014 Example JWT login route
|
|
320
|
+
import type { Context } from "@voltx/server";
|
|
321
|
+
import { jwt } from "../../lib/auth";
|
|
322
|
+
|
|
323
|
+
export async function POST(c: Context) {
|
|
324
|
+
const { email, password } = await c.req.json();
|
|
325
|
+
|
|
326
|
+
if (!email || !password) {
|
|
327
|
+
return c.json({ error: "Email and password are required" }, 400);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const token = await jwt.sign({ sub: email, email });
|
|
331
|
+
return c.json({ token });
|
|
332
|
+
}
|
|
333
|
+
`
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
let envContent = "";
|
|
337
|
+
if (template === "rag-app") {
|
|
338
|
+
envContent += "# \u2500\u2500\u2500 LLM Provider \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nOPENAI_API_KEY=sk-...\n\n";
|
|
339
|
+
envContent += "# \u2500\u2500\u2500 Database (Neon Postgres) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nDATABASE_URL=postgresql://user:pass@ep-xxx.us-east-2.aws.neon.tech/dbname?sslmode=require\n\n";
|
|
340
|
+
envContent += "# \u2500\u2500\u2500 Vector Database (Pinecone) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nPINECONE_API_KEY=pc-...\nPINECONE_INDEX=voltx-embeddings\n\n";
|
|
341
|
+
} else if (template === "chatbot" || template === "agent-app") {
|
|
342
|
+
envContent += "# \u2500\u2500\u2500 LLM Provider \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nCEREBRAS_API_KEY=csk-...\n\n";
|
|
343
|
+
if (template === "agent-app") {
|
|
344
|
+
envContent += "# \u2500\u2500\u2500 Database (Neon Postgres \u2014 optional) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nDATABASE_URL=\n\n";
|
|
345
|
+
}
|
|
346
|
+
} else {
|
|
347
|
+
envContent += "# \u2500\u2500\u2500 LLM Provider (add your key) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n# OPENAI_API_KEY=sk-...\n# CEREBRAS_API_KEY=csk-...\n\n";
|
|
348
|
+
}
|
|
349
|
+
if (auth === "better-auth") {
|
|
350
|
+
envContent += "# \u2500\u2500\u2500 Auth (Better Auth) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nBETTER_AUTH_SECRET=your-secret-key-min-32-chars-here\nBETTER_AUTH_URL=http://localhost:3000\n";
|
|
351
|
+
if (template !== "rag-app" && template !== "agent-app") {
|
|
352
|
+
envContent += "DATABASE_URL=postgresql://user:pass@ep-xxx.us-east-2.aws.neon.tech/dbname?sslmode=require\n";
|
|
353
|
+
}
|
|
354
|
+
envContent += "# GITHUB_CLIENT_ID=\n# GITHUB_CLIENT_SECRET=\n\n";
|
|
355
|
+
} else if (auth === "jwt") {
|
|
356
|
+
envContent += "# \u2500\u2500\u2500 Auth (JWT) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nJWT_SECRET=your-jwt-secret-key\n\n";
|
|
357
|
+
}
|
|
358
|
+
envContent += "# \u2500\u2500\u2500 App \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nPORT=3000\nNODE_ENV=development\n";
|
|
359
|
+
fs.writeFileSync(path.join(targetDir, ".env.example"), envContent);
|
|
360
|
+
fs.writeFileSync(
|
|
361
|
+
path.join(targetDir, ".gitignore"),
|
|
362
|
+
"node_modules\ndist\n.env\n"
|
|
363
|
+
);
|
|
364
|
+
fs.writeFileSync(
|
|
365
|
+
path.join(targetDir, "tsconfig.json"),
|
|
366
|
+
JSON.stringify(
|
|
367
|
+
{
|
|
368
|
+
compilerOptions: {
|
|
369
|
+
target: "ES2022",
|
|
370
|
+
module: "ESNext",
|
|
371
|
+
moduleResolution: "bundler",
|
|
372
|
+
strict: true,
|
|
373
|
+
esModuleInterop: true,
|
|
374
|
+
skipLibCheck: true,
|
|
375
|
+
outDir: "dist",
|
|
376
|
+
rootDir: "src"
|
|
377
|
+
},
|
|
378
|
+
include: ["src"]
|
|
379
|
+
},
|
|
380
|
+
null,
|
|
381
|
+
2
|
|
382
|
+
)
|
|
383
|
+
);
|
|
384
|
+
printWelcomeBanner(name);
|
|
385
|
+
}
|
|
386
|
+
var isDirectRun = typeof __require !== "undefined" && __require.main === module && process.argv[1]?.includes("create");
|
|
387
|
+
if (isDirectRun) {
|
|
388
|
+
const projectName = process.argv[2];
|
|
389
|
+
if (!projectName) {
|
|
390
|
+
console.log("Usage: create-voltx-app <project-name> [--template chatbot] [--auth jwt]");
|
|
391
|
+
process.exit(1);
|
|
392
|
+
}
|
|
393
|
+
const templateFlag = process.argv.indexOf("--template");
|
|
394
|
+
const template = templateFlag !== -1 ? process.argv[templateFlag + 1] : "blank";
|
|
395
|
+
const authFlag = process.argv.indexOf("--auth");
|
|
396
|
+
const auth = authFlag !== -1 ? process.argv[authFlag + 1] : "none";
|
|
397
|
+
createProject({ name: projectName, template, auth }).catch((err) => {
|
|
398
|
+
console.error("[voltx] Error:", err);
|
|
399
|
+
process.exit(1);
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
export {
|
|
404
|
+
createProject
|
|
405
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -207,7 +207,7 @@ async function createProject(options) {
|
|
|
207
207
|
);
|
|
208
208
|
const hasDb = template === "rag-app" || template === "agent-app" || auth === "better-auth";
|
|
209
209
|
const provider = template === "rag-app" ? "openai" : "cerebras";
|
|
210
|
-
const model = template === "rag-app" ? "gpt-4o" : "
|
|
210
|
+
const model = template === "rag-app" ? "gpt-4o" : "llama3.1-8b";
|
|
211
211
|
let configContent = `import { defineConfig } from "@voltx/core";
|
|
212
212
|
|
|
213
213
|
export default defineConfig({
|
|
@@ -972,7 +972,7 @@ import { createAgent } from "@voltx/agents";
|
|
|
972
972
|
|
|
973
973
|
export const ${toCamelCase(name)} = createAgent({
|
|
974
974
|
name: "${name}",
|
|
975
|
-
model: "cerebras:
|
|
975
|
+
model: "cerebras:llama3.1-8b",
|
|
976
976
|
instructions: "You are a helpful AI assistant named ${name}.",
|
|
977
977
|
tools: [
|
|
978
978
|
// Add tools here:
|
|
@@ -1081,7 +1081,7 @@ var init_index = __esm({
|
|
|
1081
1081
|
init_build();
|
|
1082
1082
|
init_start();
|
|
1083
1083
|
init_generate();
|
|
1084
|
-
CLI_VERSION = "0.3.
|
|
1084
|
+
CLI_VERSION = "0.3.3";
|
|
1085
1085
|
}
|
|
1086
1086
|
});
|
|
1087
1087
|
|
package/dist/create.js
CHANGED
|
@@ -204,7 +204,7 @@ async function createProject(options) {
|
|
|
204
204
|
);
|
|
205
205
|
const hasDb = template === "rag-app" || template === "agent-app" || auth === "better-auth";
|
|
206
206
|
const provider = template === "rag-app" ? "openai" : "cerebras";
|
|
207
|
-
const model = template === "rag-app" ? "gpt-4o" : "
|
|
207
|
+
const model = template === "rag-app" ? "gpt-4o" : "llama3.1-8b";
|
|
208
208
|
let configContent = `import { defineConfig } from "@voltx/core";
|
|
209
209
|
|
|
210
210
|
export default defineConfig({
|
package/dist/create.mjs
CHANGED
package/dist/generate.js
CHANGED
|
@@ -78,7 +78,7 @@ import { createAgent } from "@voltx/agents";
|
|
|
78
78
|
|
|
79
79
|
export const ${toCamelCase(name)} = createAgent({
|
|
80
80
|
name: "${name}",
|
|
81
|
-
model: "cerebras:
|
|
81
|
+
model: "cerebras:llama3.1-8b",
|
|
82
82
|
instructions: "You are a helpful AI assistant named ${name}.",
|
|
83
83
|
tools: [
|
|
84
84
|
// Add tools here:
|
package/dist/generate.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -4,6 +4,6 @@ export { BuildOptions, runBuild } from './build.mjs';
|
|
|
4
4
|
export { StartOptions, runStart } from './start.mjs';
|
|
5
5
|
export { GenerateOptions, GeneratorType, runGenerate } from './generate.mjs';
|
|
6
6
|
|
|
7
|
-
declare const CLI_VERSION = "0.3.
|
|
7
|
+
declare const CLI_VERSION = "0.3.3";
|
|
8
8
|
|
|
9
9
|
export { CLI_VERSION };
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ export { BuildOptions, runBuild } from './build.js';
|
|
|
4
4
|
export { StartOptions, runStart } from './start.js';
|
|
5
5
|
export { GenerateOptions, GeneratorType, runGenerate } from './generate.js';
|
|
6
6
|
|
|
7
|
-
declare const CLI_VERSION = "0.3.
|
|
7
|
+
declare const CLI_VERSION = "0.3.3";
|
|
8
8
|
|
|
9
9
|
export { CLI_VERSION };
|
package/dist/index.js
CHANGED
|
@@ -210,7 +210,7 @@ async function createProject(options) {
|
|
|
210
210
|
);
|
|
211
211
|
const hasDb = template === "rag-app" || template === "agent-app" || auth === "better-auth";
|
|
212
212
|
const provider = template === "rag-app" ? "openai" : "cerebras";
|
|
213
|
-
const model = template === "rag-app" ? "gpt-4o" : "
|
|
213
|
+
const model = template === "rag-app" ? "gpt-4o" : "llama3.1-8b";
|
|
214
214
|
let configContent = `import { defineConfig } from "@voltx/core";
|
|
215
215
|
|
|
216
216
|
export default defineConfig({
|
|
@@ -934,7 +934,7 @@ import { createAgent } from "@voltx/agents";
|
|
|
934
934
|
|
|
935
935
|
export const ${toCamelCase(name)} = createAgent({
|
|
936
936
|
name: "${name}",
|
|
937
|
-
model: "cerebras:
|
|
937
|
+
model: "cerebras:llama3.1-8b",
|
|
938
938
|
instructions: "You are a helpful AI assistant named ${name}.",
|
|
939
939
|
tools: [
|
|
940
940
|
// Add tools here:
|
|
@@ -1017,7 +1017,7 @@ function toCamelCase(str) {
|
|
|
1017
1017
|
}
|
|
1018
1018
|
|
|
1019
1019
|
// src/index.ts
|
|
1020
|
-
var CLI_VERSION = "0.3.
|
|
1020
|
+
var CLI_VERSION = "0.3.3";
|
|
1021
1021
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1022
1022
|
0 && (module.exports = {
|
|
1023
1023
|
CLI_VERSION,
|
package/dist/index.mjs
CHANGED
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
} from "./chunk-ZB2F3WTS.mjs";
|
|
4
4
|
import {
|
|
5
5
|
createProject
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-HM7F67C2.mjs";
|
|
7
7
|
import {
|
|
8
8
|
runDev
|
|
9
9
|
} from "./chunk-QND74HUW.mjs";
|
|
10
10
|
import {
|
|
11
11
|
runGenerate
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-HAFJKS2O.mjs";
|
|
13
13
|
import {
|
|
14
14
|
runStart
|
|
15
15
|
} from "./chunk-BXHQORLN.mjs";
|
|
@@ -17,7 +17,7 @@ import "./chunk-IV352HZA.mjs";
|
|
|
17
17
|
import "./chunk-Y6FXYEAI.mjs";
|
|
18
18
|
|
|
19
19
|
// src/index.ts
|
|
20
|
-
var CLI_VERSION = "0.3.
|
|
20
|
+
var CLI_VERSION = "0.3.3";
|
|
21
21
|
export {
|
|
22
22
|
CLI_VERSION,
|
|
23
23
|
createProject,
|