@valerypopoff/rivet2-cli 2.0.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.
- package/LICENSE +7 -0
- package/README.md +28 -0
- package/bin/cli.js +10 -0
- package/bin/commands/run.js +98 -0
- package/bin/commands/serve.js +271 -0
- package/dist/types/cli.d.ts +2 -0
- package/dist/types/commands/run.d.ts +22 -0
- package/dist/types/commands/serve.d.ts +37 -0
- package/package.json +34 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright 2026 Val P.
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# @valerypopoff/rivet2-cli
|
|
2
|
+
|
|
3
|
+
Command-line tools for running and serving Rivet 2.0 projects through the Node runtime.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @valerypopoff/rivet2-cli --help
|
|
9
|
+
npx @valerypopoff/rivet2-cli run my-project.rivet-project
|
|
10
|
+
npx @valerypopoff/rivet2-cli serve my-project.rivet-project --port 8080
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The CLI package exposes the `rivet` binary when installed globally:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g @valerypopoff/rivet2-cli
|
|
17
|
+
rivet --help
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Development
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
yarn workspace @valerypopoff/rivet2-cli run build
|
|
24
|
+
yarn workspace @valerypopoff/rivet2-cli run test
|
|
25
|
+
yarn workspace @valerypopoff/rivet2-cli run lint
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
See the root [README](../../README.md), [package docs](../../developer-docs/PACKAGES.md), and public CLI docs under [packages/docs/docs/cli.md](../docs/docs/cli.md).
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import yargs from 'yargs';
|
|
3
|
+
import { hideBin } from 'yargs/helpers';
|
|
4
|
+
import { makeCommand as makeRunCommand, run } from './commands/run.js';
|
|
5
|
+
import { makeCommand as makeServeCommand, serve } from './commands/serve.js';
|
|
6
|
+
await yargs(hideBin(process.argv))
|
|
7
|
+
.command('run <projectFile> [graphName]', 'Run a graph in a project file, or the main graph if graphName is not specified.', (y) => makeRunCommand(y), (args) => run(args))
|
|
8
|
+
.command('serve [projectFile]', 'Serve a project file as a REST API.', (y) => makeServeCommand(y), (args) => serve(args))
|
|
9
|
+
.demandCommand()
|
|
10
|
+
.parseAsync();
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { createProcessor, loadProjectFromFile } from '@valerypopoff/rivet2-node';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
export function makeCommand(y) {
|
|
4
|
+
return y
|
|
5
|
+
.positional('projectFile', {
|
|
6
|
+
describe: 'The project file to run',
|
|
7
|
+
type: 'string',
|
|
8
|
+
demandOption: true,
|
|
9
|
+
})
|
|
10
|
+
.positional('graphName', {
|
|
11
|
+
describe: 'The name of the graph to run',
|
|
12
|
+
type: 'string',
|
|
13
|
+
})
|
|
14
|
+
.option('inputs-stdin', {
|
|
15
|
+
describe: 'Read inputs from stdin as JSON',
|
|
16
|
+
type: 'boolean',
|
|
17
|
+
default: false,
|
|
18
|
+
})
|
|
19
|
+
.option('include-cost', {
|
|
20
|
+
describe: 'Include the total cost in the output',
|
|
21
|
+
type: 'boolean',
|
|
22
|
+
default: false,
|
|
23
|
+
})
|
|
24
|
+
.option('context', {
|
|
25
|
+
describe: 'Adds a context value to the graph run',
|
|
26
|
+
type: 'string',
|
|
27
|
+
array: true,
|
|
28
|
+
default: [],
|
|
29
|
+
})
|
|
30
|
+
.option('input', {
|
|
31
|
+
describe: 'Adds an input to the graph run',
|
|
32
|
+
type: 'string',
|
|
33
|
+
array: true,
|
|
34
|
+
default: [],
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
export async function run(args) {
|
|
38
|
+
try {
|
|
39
|
+
const projectPath = resolve(process.cwd(), args.projectFile);
|
|
40
|
+
const project = await loadProjectFromFile(projectPath);
|
|
41
|
+
if (!args.graphName && !project.metadata.mainGraphId) {
|
|
42
|
+
const validGraphs = Object.values(project.graphs).map((graph) => [graph.metadata.id, graph.metadata.name]);
|
|
43
|
+
const validGraphNames = validGraphs.map(([id, name]) => `• "${name}" (${id})`);
|
|
44
|
+
console.error(`No graph name provided, and project does not specify a main graph. Valid graphs are: \n${validGraphNames.join('\n')}\n\n Use either the graph's name or its ID. For example, \`rivet run my-project.rivet-project my-graph\` or \`rivet run my-project.rivet-project 1234abcd\``);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
let inputs = {};
|
|
48
|
+
if (args.inputsStdin) {
|
|
49
|
+
// Read json from stdin
|
|
50
|
+
const stdin = process.stdin;
|
|
51
|
+
stdin.setEncoding('utf8');
|
|
52
|
+
let input = '';
|
|
53
|
+
for await (const chunk of stdin) {
|
|
54
|
+
input += chunk;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
inputs = JSON.parse(input);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
console.error('Failed to parse input JSON');
|
|
61
|
+
console.error(err);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
inputs = Object.fromEntries(args.input.map((input) => {
|
|
67
|
+
const [key, value] = input.split('=');
|
|
68
|
+
if (!key || !value) {
|
|
69
|
+
console.error(`Invalid input value: ${input}`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
return [key, value];
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
const contextValues = Object.fromEntries(args.context.map((context) => {
|
|
76
|
+
const [key, value] = context.split('=');
|
|
77
|
+
if (!key || !value) {
|
|
78
|
+
console.error(`Invalid context value: ${context}`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
return [key, value];
|
|
82
|
+
}));
|
|
83
|
+
const { run } = createProcessor(project, {
|
|
84
|
+
graph: args.graphName,
|
|
85
|
+
inputs,
|
|
86
|
+
context: contextValues,
|
|
87
|
+
});
|
|
88
|
+
const outputs = await run();
|
|
89
|
+
if (!args.includeCost) {
|
|
90
|
+
delete outputs.cost;
|
|
91
|
+
}
|
|
92
|
+
console.log(JSON.stringify(outputs, null, 2));
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
console.error(err);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { serve as serveHono } from '@hono/node-server';
|
|
3
|
+
import { readdir, stat } from 'node:fs/promises';
|
|
4
|
+
import { extname, isAbsolute, join } from 'node:path';
|
|
5
|
+
import didYouMean from 'didyoumean2';
|
|
6
|
+
import { createProcessor, loadProjectFromFile, getSingleNodeStream, } from '@valerypopoff/rivet2-node';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { configDotenv } from 'dotenv';
|
|
9
|
+
export function makeCommand(y) {
|
|
10
|
+
return y
|
|
11
|
+
.option('port', {
|
|
12
|
+
describe: 'The port to serve on',
|
|
13
|
+
type: 'number',
|
|
14
|
+
default: 3000,
|
|
15
|
+
})
|
|
16
|
+
.option('dev', {
|
|
17
|
+
describe: 'Run in development mode: rereads the project file on each request',
|
|
18
|
+
type: 'boolean',
|
|
19
|
+
default: false,
|
|
20
|
+
})
|
|
21
|
+
.option('graph', {
|
|
22
|
+
describe: 'The ID or name of the graph to run. If omitted, the main graph is used.',
|
|
23
|
+
type: 'string',
|
|
24
|
+
demandOption: false,
|
|
25
|
+
})
|
|
26
|
+
.option('allow-specifying-graph-id', {
|
|
27
|
+
describe: 'Allow specifying the graph ID in the URL path',
|
|
28
|
+
type: 'boolean',
|
|
29
|
+
default: false,
|
|
30
|
+
})
|
|
31
|
+
.option('openai-api-key', {
|
|
32
|
+
describe: 'The OpenAI API key to use for the project. If omitted, the environment variable OPENAI_API_KEY is used.',
|
|
33
|
+
type: 'string',
|
|
34
|
+
demandOption: false,
|
|
35
|
+
})
|
|
36
|
+
.option('openai-endpoint', {
|
|
37
|
+
describe: 'The OpenAI API endpoint to use for the project. If omitted, the environment variable OPENAI_ENDPOINT is used.',
|
|
38
|
+
type: 'string',
|
|
39
|
+
demandOption: false,
|
|
40
|
+
})
|
|
41
|
+
.option('openai-organization', {
|
|
42
|
+
describe: 'The OpenAI organization to use for the project. If omitted, the environment variable OPENAI_ORGANIZATION is used.',
|
|
43
|
+
type: 'string',
|
|
44
|
+
demandOption: false,
|
|
45
|
+
})
|
|
46
|
+
.option('expose-cost', {
|
|
47
|
+
describe: 'Expose the cost of the graph run in the response',
|
|
48
|
+
type: 'boolean',
|
|
49
|
+
default: false,
|
|
50
|
+
})
|
|
51
|
+
.option('stream', {
|
|
52
|
+
describe: 'Turns on streaming mode. Rivet events will be sent to the client using SSE (Server-Sent Events). If this is set to a Node ID or node title, only events for that node will be sent.',
|
|
53
|
+
type: 'string',
|
|
54
|
+
demandOption: false,
|
|
55
|
+
})
|
|
56
|
+
.option('stream-node', {
|
|
57
|
+
describe: 'Streams the partial outputs of a specific node. Requires --stream to be set.',
|
|
58
|
+
type: 'string',
|
|
59
|
+
demandOption: false,
|
|
60
|
+
})
|
|
61
|
+
.positional('projectFile', {
|
|
62
|
+
describe: 'The project file to serve. If omitted, the project file in the current directory is used. There cannot be multiple project files in the current directory.',
|
|
63
|
+
type: 'string',
|
|
64
|
+
demandOption: false,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export async function serve(args) {
|
|
68
|
+
try {
|
|
69
|
+
configDotenv();
|
|
70
|
+
const app = new Hono();
|
|
71
|
+
const projectFilePath = await getProjectFile(args.projectFile);
|
|
72
|
+
const initialProject = await loadProjectFromFile(projectFilePath);
|
|
73
|
+
throwIfNoMainGraph(initialProject, args.graph, projectFilePath);
|
|
74
|
+
throwIfInvalidGraph(initialProject, args.graph);
|
|
75
|
+
if (args.stream != null) {
|
|
76
|
+
console.log('Streaming is enabled');
|
|
77
|
+
}
|
|
78
|
+
if (args.streamNode != null) {
|
|
79
|
+
console.log(`Streaming node ${chalk.bold(args.streamNode)}`);
|
|
80
|
+
}
|
|
81
|
+
app.post('/', async (c) => {
|
|
82
|
+
const project = args.dev ? await loadProjectFromFile(projectFilePath) : initialProject;
|
|
83
|
+
const text = await c.req.text();
|
|
84
|
+
let inputs = {};
|
|
85
|
+
if (text.trim()) {
|
|
86
|
+
inputs = JSON.parse(text);
|
|
87
|
+
if (typeof inputs !== 'object') {
|
|
88
|
+
throw new Error('Inputs must be an object');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (args.stream != null) {
|
|
92
|
+
const stream = await streamGraph({ project, inputs, graphId: args.graph, ...args });
|
|
93
|
+
return new Response(stream, {
|
|
94
|
+
headers: {
|
|
95
|
+
'Content-Type': 'text/event-stream',
|
|
96
|
+
'Cache-Control': 'no-cache',
|
|
97
|
+
Connection: 'keep-alive',
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
const outputs = await runGraph({ project, inputs, graphId: args.graph, ...args });
|
|
103
|
+
return c.json(outputs);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
if (args.allowSpecifyingGraphId) {
|
|
107
|
+
app.post('/:graphId', async (c) => {
|
|
108
|
+
const project = args.dev ? await loadProjectFromFile(projectFilePath) : initialProject;
|
|
109
|
+
const inputs = await c.req.json();
|
|
110
|
+
const graphId = c.req.param('graphId');
|
|
111
|
+
const outputs = await runGraph({ project, inputs, graphId, ...args });
|
|
112
|
+
return c.json(outputs);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
const server = serveHono({
|
|
116
|
+
port: args.port,
|
|
117
|
+
fetch: app.fetch,
|
|
118
|
+
});
|
|
119
|
+
let servedGraphName;
|
|
120
|
+
if (args.graph) {
|
|
121
|
+
const graph = Object.values(initialProject.graphs).find((g) => g.metadata.id === args.graph || g.metadata.name === args.graph);
|
|
122
|
+
servedGraphName = graph.metadata.name;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
const graph = Object.values(initialProject.graphs).find((g) => g.metadata.id === initialProject.metadata.mainGraphId);
|
|
126
|
+
servedGraphName = graph.metadata.name;
|
|
127
|
+
}
|
|
128
|
+
console.log(`${chalk.green(`Serving project file ${chalk.bold.white(projectFilePath)} on port ${chalk.bold.white(args.port)}.\nServing graph "${chalk.bold.white(servedGraphName)}".`)}`);
|
|
129
|
+
function shutdown() {
|
|
130
|
+
console.log('Shutting down...');
|
|
131
|
+
server.close((err) => {
|
|
132
|
+
if (err) {
|
|
133
|
+
console.error(err);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
process.exit(0);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
process.on('SIGINT', shutdown);
|
|
140
|
+
process.on('SIGTERM', shutdown);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
console.error(chalk.red(err));
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async function streamGraph({ project, inputs, graphId, openaiApiKey, openaiEndpoint, openaiOrganization, streamNode, }) {
|
|
148
|
+
const { run, processor, getSSEStream } = createProcessor(project, {
|
|
149
|
+
inputs,
|
|
150
|
+
graph: graphId,
|
|
151
|
+
openAiKey: openaiApiKey,
|
|
152
|
+
openAiEndpoint: openaiEndpoint,
|
|
153
|
+
openAiOrganization: openaiOrganization,
|
|
154
|
+
});
|
|
155
|
+
if (streamNode) {
|
|
156
|
+
const stream = getSingleNodeStream(processor, streamNode);
|
|
157
|
+
run().catch((err) => {
|
|
158
|
+
console.error(err);
|
|
159
|
+
});
|
|
160
|
+
return stream;
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
const stream = getSSEStream({
|
|
164
|
+
nodeStart: streamNode ? [streamNode] : true,
|
|
165
|
+
nodeFinish: streamNode ? [streamNode] : true,
|
|
166
|
+
partialOutputs: streamNode ? [streamNode] : true,
|
|
167
|
+
});
|
|
168
|
+
run().catch((err) => {
|
|
169
|
+
console.error(err);
|
|
170
|
+
});
|
|
171
|
+
return stream;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async function runGraph({ project, inputs, graphId, openaiApiKey, openaiEndpoint, openaiOrganization, exposeCost, }) {
|
|
175
|
+
const { run } = createProcessor(project, {
|
|
176
|
+
inputs,
|
|
177
|
+
graph: graphId,
|
|
178
|
+
openAiKey: openaiApiKey,
|
|
179
|
+
openAiEndpoint: openaiEndpoint,
|
|
180
|
+
openAiOrganization: openaiOrganization,
|
|
181
|
+
});
|
|
182
|
+
const outputs = await run();
|
|
183
|
+
if (!exposeCost) {
|
|
184
|
+
delete outputs.cost;
|
|
185
|
+
}
|
|
186
|
+
return outputs;
|
|
187
|
+
}
|
|
188
|
+
function throwIfNoMainGraph(project, graph, projectFilePath) {
|
|
189
|
+
if (!project.metadata.mainGraphId && !graph) {
|
|
190
|
+
const validGraphs = Object.values(project.graphs).map((graph) => [graph.metadata.id, graph.metadata.name]);
|
|
191
|
+
if (validGraphs.length === 0) {
|
|
192
|
+
throw new Error('No graphs found in the project file. Please edit the project file in Rivet and add a graph.');
|
|
193
|
+
}
|
|
194
|
+
const validGraphNames = validGraphs.map(([id, name]) => `• "${name}" (${id})`);
|
|
195
|
+
const firstExample = `rivet serve ${projectFilePath} --graph ${validGraphs[0][0]}`;
|
|
196
|
+
const secondExample = `rivet serve ${projectFilePath} --graph "${validGraphs[0][1]}"`;
|
|
197
|
+
throw new Error(`No graph name provided, and project does not specify a main graph. Valid graphs are: \n\n${validGraphNames.join('\n')}\n\n Use either the graph's name or its ID. For example, \n• \`${chalk.bold(firstExample)}\` or\n• \`${chalk.bold(secondExample)}\``);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function throwIfInvalidGraph(project, graph) {
|
|
201
|
+
if (project.metadata.mainGraphId && !graph) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const matchingGraph = Object.values(project.graphs).find((g) => g.metadata.id === graph || g.metadata.name === graph);
|
|
205
|
+
if (!matchingGraph) {
|
|
206
|
+
const validGraphsAndIds = Object.values(project.graphs).flatMap((graph) => [
|
|
207
|
+
graph.metadata.id,
|
|
208
|
+
graph.metadata.name,
|
|
209
|
+
]);
|
|
210
|
+
const suggestion = didYouMean(graph, validGraphsAndIds);
|
|
211
|
+
if (suggestion) {
|
|
212
|
+
throw new Error(`Graph "${graph}" not found in project file. Did you mean \`${chalk.bold(`--graph "${suggestion}"`)}\`?`);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
const validGraphsAndIds = Object.values(project.graphs)
|
|
216
|
+
.map((graph) => `• "${graph.metadata.name}" (${graph.metadata.id})`)
|
|
217
|
+
.join('\n');
|
|
218
|
+
throw new Error(`Graph "${graph}" not found in project file. Valid graphs are: \n${validGraphsAndIds}`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
async function getProjectFile(initialProjectFilePath) {
|
|
223
|
+
let projectFilePath = initialProjectFilePath ?? (await getProjectFilePathFromDirectory(process.cwd()));
|
|
224
|
+
await throwIfMissingFile(projectFilePath);
|
|
225
|
+
if ((await stat(projectFilePath)).isDirectory()) {
|
|
226
|
+
projectFilePath = await getProjectFilePathFromDirectory(projectFilePath);
|
|
227
|
+
}
|
|
228
|
+
return projectFilePath;
|
|
229
|
+
}
|
|
230
|
+
async function getProjectFilePathFromDirectory(directory) {
|
|
231
|
+
const files = await readdir(directory);
|
|
232
|
+
const projectFiles = files.filter((file) => extname(file) === '.rivet-project');
|
|
233
|
+
if (projectFiles.length === 0) {
|
|
234
|
+
throw new Error('No project file found in the current directory. Project files should end with .rivet-project.');
|
|
235
|
+
}
|
|
236
|
+
if (projectFiles.length > 1) {
|
|
237
|
+
throw new Error(`Multiple project files found in the current directory. Please specify which one to serve: \n${projectFiles.join('\n')}`);
|
|
238
|
+
}
|
|
239
|
+
return join(directory, projectFiles[0]);
|
|
240
|
+
}
|
|
241
|
+
async function throwIfMissingFile(filePath) {
|
|
242
|
+
try {
|
|
243
|
+
await stat(filePath);
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
if (err.code !== 'ENOENT') {
|
|
247
|
+
throw err;
|
|
248
|
+
}
|
|
249
|
+
if (isAbsolute(filePath)) {
|
|
250
|
+
const parentDir = filePath.split('/').slice(0, -1).join('/');
|
|
251
|
+
const possibleFiles = await readdir(parentDir);
|
|
252
|
+
const suggestion = didYouMean(filePath, possibleFiles);
|
|
253
|
+
if (suggestion) {
|
|
254
|
+
throw new Error(`Could not find project file "${filePath}". Did you mean "${suggestion}"?`);
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
throw new Error(`Could not find project file "${filePath}".`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
const possibleFiles = await readdir(process.cwd());
|
|
262
|
+
const suggestion = didYouMean(filePath, possibleFiles);
|
|
263
|
+
if (suggestion) {
|
|
264
|
+
throw new Error(`Could not find project file "${filePath}". Did you mean "${suggestion}"?`);
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
throw new Error(`Could not find project file "${filePath}".`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type * as yargs from 'yargs';
|
|
2
|
+
export declare function makeCommand<T>(y: yargs.Argv<T>): yargs.Argv<T & {
|
|
3
|
+
projectFile: string;
|
|
4
|
+
} & {
|
|
5
|
+
graphName: string | undefined;
|
|
6
|
+
} & {
|
|
7
|
+
"inputs-stdin": boolean;
|
|
8
|
+
} & {
|
|
9
|
+
"include-cost": boolean;
|
|
10
|
+
} & {
|
|
11
|
+
context: never[] | string[];
|
|
12
|
+
} & {
|
|
13
|
+
input: never[] | string[];
|
|
14
|
+
}>;
|
|
15
|
+
export declare function run(args: {
|
|
16
|
+
projectFile: string;
|
|
17
|
+
graphName: string | undefined;
|
|
18
|
+
inputsStdin: boolean;
|
|
19
|
+
includeCost: boolean;
|
|
20
|
+
context: string[];
|
|
21
|
+
input: string[];
|
|
22
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type * as yargs from 'yargs';
|
|
2
|
+
export declare function makeCommand<T>(y: yargs.Argv<T>): yargs.Argv<T & {
|
|
3
|
+
port: number;
|
|
4
|
+
} & {
|
|
5
|
+
dev: boolean;
|
|
6
|
+
} & {
|
|
7
|
+
graph: string | undefined;
|
|
8
|
+
} & {
|
|
9
|
+
"allow-specifying-graph-id": boolean;
|
|
10
|
+
} & {
|
|
11
|
+
"openai-api-key": string | undefined;
|
|
12
|
+
} & {
|
|
13
|
+
"openai-endpoint": string | undefined;
|
|
14
|
+
} & {
|
|
15
|
+
"openai-organization": string | undefined;
|
|
16
|
+
} & {
|
|
17
|
+
"expose-cost": boolean;
|
|
18
|
+
} & {
|
|
19
|
+
stream: string | undefined;
|
|
20
|
+
} & {
|
|
21
|
+
"stream-node": string | undefined;
|
|
22
|
+
} & {
|
|
23
|
+
projectFile: string | undefined;
|
|
24
|
+
}>;
|
|
25
|
+
export declare function serve(args: {
|
|
26
|
+
port: number;
|
|
27
|
+
projectFile: string | undefined;
|
|
28
|
+
dev: boolean;
|
|
29
|
+
graph: string | undefined;
|
|
30
|
+
allowSpecifyingGraphId: boolean;
|
|
31
|
+
openaiApiKey: string | undefined;
|
|
32
|
+
openaiEndpoint: string | undefined;
|
|
33
|
+
openaiOrganization: string | undefined;
|
|
34
|
+
exposeCost: boolean;
|
|
35
|
+
stream: string | undefined;
|
|
36
|
+
streamNode: string | undefined;
|
|
37
|
+
}): Promise<void>;
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@valerypopoff/rivet2-cli",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"types": "dist/types/cli.d.ts",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"rivet": "bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin",
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18.0.0"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/valerypopoff/rivet2.0.git"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@hono/node-server": "^1.13.8",
|
|
26
|
+
"@types/dotenv": "^8.2.3",
|
|
27
|
+
"@valerypopoff/rivet2-node": "^2.0.0",
|
|
28
|
+
"chalk": "^5.4.1",
|
|
29
|
+
"didyoumean2": "^7.0.4",
|
|
30
|
+
"dotenv": "^16.4.7",
|
|
31
|
+
"hono": "^4.7.0",
|
|
32
|
+
"yargs": "^17.7.2"
|
|
33
|
+
}
|
|
34
|
+
}
|