@asterai/cli 0.1.3 → 0.2.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/README.md +10 -10
- package/asterai-init-plugin/package.json +3 -1
- package/asterai-init-plugin/plugin.asterai.proto +22 -0
- package/asterai-init-plugin/plugin.ts +33 -5
- package/bin/dev.js +0 -0
- package/dist/commands/build.d.ts +11 -0
- package/dist/commands/build.js +117 -21
- package/dist/commands/codegen.d.ts +5 -0
- package/dist/commands/codegen.js +33 -69
- package/dist/commands/deploy.d.ts +1 -0
- package/dist/commands/deploy.js +57 -38
- package/dist/compile.d.ts +1 -1
- package/dist/compile.js +1 -4
- package/oclif.manifest.json +4 -4
- package/package.json +18 -14
- package/asterai-init-plugin/plugin.asterai.yaml +0 -9
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @asterai/cli
|
|
2
2
|
|
|
3
|
-
CLI for building and deploying
|
|
3
|
+
CLI for building and deploying asterai plugins
|
|
4
4
|
|
|
5
5
|
[](https://oclif.io)
|
|
6
6
|
[](https://npmjs.org/package/@asterai/cli)
|
|
@@ -20,7 +20,7 @@ $ npm install -g @asterai/cli
|
|
|
20
20
|
$ asterai COMMAND
|
|
21
21
|
running command...
|
|
22
22
|
$ asterai (--version)
|
|
23
|
-
@asterai/cli/0.
|
|
23
|
+
@asterai/cli/0.2.0 linux-x64 node-v20.12.2
|
|
24
24
|
$ asterai --help [COMMAND]
|
|
25
25
|
USAGE
|
|
26
26
|
$ asterai COMMAND
|
|
@@ -53,7 +53,7 @@ EXAMPLES
|
|
|
53
53
|
$ asterai auth
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
_See code: [src/commands/auth.ts](https://github.com/asterai-io/asterai-sdk/blob/v0.
|
|
56
|
+
_See code: [src/commands/auth.ts](https://github.com/asterai-io/asterai-sdk/blob/v0.2.0/src/commands/auth.ts)_
|
|
57
57
|
|
|
58
58
|
## `asterai build [INPUT]`
|
|
59
59
|
|
|
@@ -64,7 +64,7 @@ USAGE
|
|
|
64
64
|
$ asterai build [INPUT] [-m <value>]
|
|
65
65
|
|
|
66
66
|
FLAGS
|
|
67
|
-
-m, --manifest=<value> [default: plugin.asterai.
|
|
67
|
+
-m, --manifest=<value> [default: plugin.asterai.proto] manifest path
|
|
68
68
|
|
|
69
69
|
DESCRIPTION
|
|
70
70
|
compiles the plugin
|
|
@@ -73,7 +73,7 @@ EXAMPLES
|
|
|
73
73
|
$ asterai build
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
_See code: [src/commands/build.ts](https://github.com/asterai-io/asterai-sdk/blob/v0.
|
|
76
|
+
_See code: [src/commands/build.ts](https://github.com/asterai-io/asterai-sdk/blob/v0.2.0/src/commands/build.ts)_
|
|
77
77
|
|
|
78
78
|
## `asterai codegen`
|
|
79
79
|
|
|
@@ -84,7 +84,7 @@ USAGE
|
|
|
84
84
|
$ asterai codegen [-m <value>] [-o <value>]
|
|
85
85
|
|
|
86
86
|
FLAGS
|
|
87
|
-
-m, --manifest=<value> [default: plugin.asterai.
|
|
87
|
+
-m, --manifest=<value> [default: plugin.asterai.proto] manifest path
|
|
88
88
|
-o, --outputDir=<value> [default: generated] output directory
|
|
89
89
|
|
|
90
90
|
DESCRIPTION
|
|
@@ -94,7 +94,7 @@ EXAMPLES
|
|
|
94
94
|
$ asterai codegen
|
|
95
95
|
```
|
|
96
96
|
|
|
97
|
-
_See code: [src/commands/codegen.ts](https://github.com/asterai-io/asterai-sdk/blob/v0.
|
|
97
|
+
_See code: [src/commands/codegen.ts](https://github.com/asterai-io/asterai-sdk/blob/v0.2.0/src/commands/codegen.ts)_
|
|
98
98
|
|
|
99
99
|
## `asterai deploy [INPUT]`
|
|
100
100
|
|
|
@@ -107,7 +107,7 @@ USAGE
|
|
|
107
107
|
FLAGS
|
|
108
108
|
-a, --app=<value> (required) app ID to immediately configure this plugin with
|
|
109
109
|
-e, --endpoint=<value> [default: https://api.asterai.io/app/plugin]
|
|
110
|
-
-m, --manifest=<value> [default: plugin.asterai.
|
|
110
|
+
-m, --manifest=<value> [default: plugin.asterai.proto] manifest path
|
|
111
111
|
-s, --staging
|
|
112
112
|
|
|
113
113
|
DESCRIPTION
|
|
@@ -117,7 +117,7 @@ EXAMPLES
|
|
|
117
117
|
$ asterai deploy --app 66a46b12-b1a7-4b72-a64a-0e4fe21902b6
|
|
118
118
|
```
|
|
119
119
|
|
|
120
|
-
_See code: [src/commands/deploy.ts](https://github.com/asterai-io/asterai-sdk/blob/v0.
|
|
120
|
+
_See code: [src/commands/deploy.ts](https://github.com/asterai-io/asterai-sdk/blob/v0.2.0/src/commands/deploy.ts)_
|
|
121
121
|
|
|
122
122
|
## `asterai help [COMMAND]`
|
|
123
123
|
|
|
@@ -154,5 +154,5 @@ EXAMPLES
|
|
|
154
154
|
$ asterai init project-name
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
-
_See code: [src/commands/init.ts](https://github.com/asterai-io/asterai-sdk/blob/v0.
|
|
157
|
+
_See code: [src/commands/init.ts](https://github.com/asterai-io/asterai-sdk/blob/v0.2.0/src/commands/init.ts)_
|
|
158
158
|
<!-- commandsstop -->
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
import "node_modules/@asterai/sdk/protobuf/asterai.proto";
|
|
3
|
+
|
|
4
|
+
service Math {
|
|
5
|
+
rpc processQuery(PluginContext) returns (ProcessQueryOutput);
|
|
6
|
+
rpc add(BinaryOperationInput) returns (CalculationOutput);
|
|
7
|
+
rpc mul(BinaryOperationInput) returns (CalculationOutput);
|
|
8
|
+
rpc div(BinaryOperationInput) returns (CalculationOutput);
|
|
9
|
+
rpc pow(BinaryOperationInput) returns (CalculationOutput);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
message ProcessQueryOutput {}
|
|
13
|
+
|
|
14
|
+
message BinaryOperationInput {
|
|
15
|
+
PluginContext context = 1;
|
|
16
|
+
double a = 2;
|
|
17
|
+
double b = 3;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
message CalculationOutput {
|
|
21
|
+
string system_message = 1;
|
|
22
|
+
}
|
|
@@ -1,7 +1,35 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { BinaryOperationInput } from "./generated/BinaryOperationInput";
|
|
2
|
+
import { CalculationOutput } from "./generated/CalculationOutput";
|
|
3
|
+
import { PluginContext } from "./generated/PluginContext";
|
|
4
|
+
import { ProcessQueryOutput } from "./generated/ProcessQueryOutput";
|
|
5
|
+
import { Log } from "@asterai/sdk";
|
|
3
6
|
|
|
4
|
-
export function
|
|
5
|
-
|
|
6
|
-
return
|
|
7
|
+
export function processQuery(input: PluginContext): ProcessQueryOutput {
|
|
8
|
+
Log.info(`math plugin received a query: ${input.query.content}`);
|
|
9
|
+
// This doesn't return any data, but protobuf requires functions
|
|
10
|
+
// to always have one input and one output exactly to ensure
|
|
11
|
+
// backward compatibility.
|
|
12
|
+
return new ProcessQueryOutput();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function add(input: BinaryOperationInput): CalculationOutput {
|
|
16
|
+
const result = input.a + input.b;
|
|
17
|
+
// CalculationOutput returns a system message.
|
|
18
|
+
// The `system_message` field is sent to the LLM.
|
|
19
|
+
return new CalculationOutput(`the result is ${result}`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function mul(input: BinaryOperationInput): CalculationOutput {
|
|
23
|
+
const result = input.a * input.b;
|
|
24
|
+
return new CalculationOutput(`the result is ${result}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function div(input: BinaryOperationInput): CalculationOutput {
|
|
28
|
+
const result = input.a / input.b;
|
|
29
|
+
return new CalculationOutput(`the result is ${result}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function pow(input: BinaryOperationInput): CalculationOutput {
|
|
33
|
+
const result = input.a ** input.b;
|
|
34
|
+
return new CalculationOutput(`the result is ${result}`);
|
|
7
35
|
}
|
package/bin/dev.js
CHANGED
|
File without changes
|
package/dist/commands/build.d.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import { Command } from "@oclif/core";
|
|
2
|
+
export type BuildArgs = {
|
|
3
|
+
input: string;
|
|
4
|
+
};
|
|
5
|
+
export type BuildFlags = {
|
|
6
|
+
manifest: string;
|
|
7
|
+
};
|
|
8
|
+
export type BuildOutput = {
|
|
9
|
+
outputFile: string;
|
|
10
|
+
manifestPath: string;
|
|
11
|
+
};
|
|
2
12
|
export default class Build extends Command {
|
|
3
13
|
static args: {
|
|
4
14
|
input: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
|
|
@@ -10,3 +20,4 @@ export default class Build extends Command {
|
|
|
10
20
|
};
|
|
11
21
|
run(): Promise<void>;
|
|
12
22
|
}
|
|
23
|
+
export declare const build: (args: BuildArgs, flags: BuildFlags) => Promise<BuildOutput>;
|
package/dist/commands/build.js
CHANGED
|
@@ -2,6 +2,9 @@ import { Args, Command, Flags } from "@oclif/core";
|
|
|
2
2
|
import path from "path";
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import { compile } from "../compile.js";
|
|
5
|
+
import Mustache from "mustache";
|
|
6
|
+
import protobuf from "protobufjs";
|
|
7
|
+
import { mergeProtoImports } from "./deploy.js";
|
|
5
8
|
export default class Build extends Command {
|
|
6
9
|
static args = {
|
|
7
10
|
input: Args.string({
|
|
@@ -14,30 +17,123 @@ export default class Build extends Command {
|
|
|
14
17
|
manifest: Flags.string({
|
|
15
18
|
char: "m",
|
|
16
19
|
description: "manifest path",
|
|
17
|
-
default: "plugin.asterai.
|
|
20
|
+
default: "plugin.asterai.proto",
|
|
18
21
|
}),
|
|
19
22
|
};
|
|
20
23
|
async run() {
|
|
21
24
|
const { args, flags } = await this.parse(Build);
|
|
22
|
-
|
|
23
|
-
const inputFile = path.resolve(args.input);
|
|
24
|
-
if (!fs.existsSync(inputFile)) {
|
|
25
|
-
throw new Error(`input file not found (${args.input})`);
|
|
26
|
-
}
|
|
27
|
-
const inputFileName = path.parse(inputFile).name;
|
|
28
|
-
const baseDir = path.dirname(manifestPath);
|
|
29
|
-
const outDir = path.join(baseDir, "build");
|
|
30
|
-
const outputFile = path.join(outDir, `${inputFileName}.wasm`);
|
|
31
|
-
const libsDir = path.join(baseDir, "node_modules");
|
|
32
|
-
if (!fs.existsSync(libsDir)) {
|
|
33
|
-
throw new Error("no node_modules found in the plugin directory");
|
|
34
|
-
}
|
|
35
|
-
const options = {
|
|
36
|
-
inputFile,
|
|
37
|
-
baseDir,
|
|
38
|
-
outputFile,
|
|
39
|
-
libs: libsDir,
|
|
40
|
-
};
|
|
41
|
-
await compile(options);
|
|
25
|
+
await build(args, flags);
|
|
42
26
|
}
|
|
43
27
|
}
|
|
28
|
+
export const build = async (args, flags) => {
|
|
29
|
+
const manifestPath = path.resolve(flags.manifest);
|
|
30
|
+
const inputFile = path.resolve(args.input);
|
|
31
|
+
if (!fs.existsSync(inputFile)) {
|
|
32
|
+
throw new Error(`input file not found (${args.input})`);
|
|
33
|
+
}
|
|
34
|
+
const inputFileName = path.parse(inputFile).name;
|
|
35
|
+
const baseDir = path.dirname(manifestPath);
|
|
36
|
+
const outDir = path.join(baseDir, "build");
|
|
37
|
+
const outputFile = path.join(outDir, `${inputFileName}.wasm`);
|
|
38
|
+
const libsDir = path.join(baseDir, "node_modules");
|
|
39
|
+
if (!fs.existsSync(libsDir)) {
|
|
40
|
+
throw new Error("no node_modules found in the plugin directory");
|
|
41
|
+
}
|
|
42
|
+
const proto = fs.readFileSync(manifestPath, { encoding: "utf8" });
|
|
43
|
+
const functionDescriptors = getPluginFunctionDescriptors(proto, manifestPath);
|
|
44
|
+
const inputFileContent = fs.readFileSync(inputFile, { encoding: "utf8" });
|
|
45
|
+
assertPluginCodeHasAllFunctionsFromManifest(inputFileContent, functionDescriptors);
|
|
46
|
+
const entryPointCode = generateEntryPointCode(functionDescriptors);
|
|
47
|
+
const mergedPluginCode = mergeInputPluginCodeWithEntrypoint(inputFileContent, entryPointCode);
|
|
48
|
+
const mergedTempFilePath = writeMergedPluginCodeTempFile(mergedPluginCode, path.parse(inputFile).dir, inputFileName);
|
|
49
|
+
const globalFile = path.join(libsDir, "@asterai/sdk/global.ts");
|
|
50
|
+
const options = {
|
|
51
|
+
inputFiles: [mergedTempFilePath, globalFile],
|
|
52
|
+
baseDir,
|
|
53
|
+
outputFile,
|
|
54
|
+
libs: libsDir,
|
|
55
|
+
};
|
|
56
|
+
try {
|
|
57
|
+
await compile(options);
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
fs.unlinkSync(mergedTempFilePath);
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
manifestPath,
|
|
64
|
+
outputFile,
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
const getPluginFunctionDescriptors = (proto, protoPath) => {
|
|
68
|
+
const protoMerged = mergeProtoImports(proto, protoPath, false, false);
|
|
69
|
+
const result = protobuf.parse(protoMerged);
|
|
70
|
+
const namespace = result.root.resolveAll();
|
|
71
|
+
const objects = namespace.nestedArray;
|
|
72
|
+
const serviceObject = objects.find(o => o.methods !== undefined);
|
|
73
|
+
if (!serviceObject) {
|
|
74
|
+
throw new Error("no service found in plugin manifest");
|
|
75
|
+
}
|
|
76
|
+
const service = serviceObject;
|
|
77
|
+
return service.methodsArray.map(m => ({
|
|
78
|
+
functionName: m.name,
|
|
79
|
+
inputType: m.requestType,
|
|
80
|
+
outputType: m.responseType,
|
|
81
|
+
}));
|
|
82
|
+
};
|
|
83
|
+
const generateEntryPointCode = (functionDescriptors) => {
|
|
84
|
+
const importsCode = `
|
|
85
|
+
import { Protobuf } from "@asterai/as-proto/assembly";
|
|
86
|
+
import { readBufferFromPtr, writeBufferToPr } from "@asterai/sdk/buffer";
|
|
87
|
+
`;
|
|
88
|
+
let code = "\n// generated plugin entry points\n\n";
|
|
89
|
+
for (const functionDescriptor of functionDescriptors) {
|
|
90
|
+
const template = `
|
|
91
|
+
export function {{func}}_entry_point(ptr: u32): u32 {
|
|
92
|
+
const inputBuffer = readBufferFromPtr(ptr);
|
|
93
|
+
const input = Protobuf.decode<{{inpt}}>(
|
|
94
|
+
inputBuffer,
|
|
95
|
+
{{inpt}}.decode,
|
|
96
|
+
);
|
|
97
|
+
const output = {{func}}(input);
|
|
98
|
+
const outputBuffer = Protobuf.encode<{{outp}}>(
|
|
99
|
+
output,
|
|
100
|
+
{{outp}}.encode,
|
|
101
|
+
);
|
|
102
|
+
return writeBufferToPr(outputBuffer);
|
|
103
|
+
}
|
|
104
|
+
`;
|
|
105
|
+
const view = {
|
|
106
|
+
func: functionDescriptor.functionName,
|
|
107
|
+
inpt: functionDescriptor.inputType,
|
|
108
|
+
outp: functionDescriptor.outputType,
|
|
109
|
+
};
|
|
110
|
+
const functionEntryPoint = Mustache.render(template, view);
|
|
111
|
+
code = `${code}\n${functionEntryPoint}`;
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
importsCode,
|
|
115
|
+
entryPointsCode: code,
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
const mergeInputPluginCodeWithEntrypoint = (pluginCode, entryPoint) => `${entryPoint.importsCode}\n${pluginCode}\n${entryPoint.entryPointsCode}`;
|
|
119
|
+
const writeMergedPluginCodeTempFile = (source, inputFileDir, inputFileName) => {
|
|
120
|
+
const tempFileName = `.entrypoint.${inputFileName}.ts`;
|
|
121
|
+
const tempFilePath = path.join(inputFileDir, tempFileName);
|
|
122
|
+
fs.writeFileSync(tempFilePath, source, { encoding: "utf8" });
|
|
123
|
+
return tempFilePath;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Throw an error if the plugin WASM source is missing a function from
|
|
127
|
+
* the manifest.
|
|
128
|
+
* The only purpose of this function is to let the user know about
|
|
129
|
+
* the issue in a direct way.
|
|
130
|
+
*/
|
|
131
|
+
const assertPluginCodeHasAllFunctionsFromManifest = (source, functionDescriptors) => {
|
|
132
|
+
for (const functionDescriptor of functionDescriptors) {
|
|
133
|
+
const includesFunction = source.includes(`function ${functionDescriptor.functionName}`);
|
|
134
|
+
if (!includesFunction) {
|
|
135
|
+
throw new Error(`function "${functionDescriptor.functionName}" was defined in plugin ` +
|
|
136
|
+
"manifest (.proto file) but is missing from plugin code");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { Command } from "@oclif/core";
|
|
2
|
+
export type CodegenFlags = {
|
|
3
|
+
manifest: string;
|
|
4
|
+
outputDir: string;
|
|
5
|
+
};
|
|
2
6
|
export default class Codegen extends Command {
|
|
3
7
|
static args: {};
|
|
4
8
|
static description: string;
|
|
@@ -9,3 +13,4 @@ export default class Codegen extends Command {
|
|
|
9
13
|
};
|
|
10
14
|
run(): Promise<void>;
|
|
11
15
|
}
|
|
16
|
+
export declare const codegen: (flags: CodegenFlags) => void;
|
package/dist/commands/codegen.js
CHANGED
|
@@ -1,38 +1,8 @@
|
|
|
1
1
|
import { Command, Flags } from "@oclif/core";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import z from "zod";
|
|
4
|
-
import YAML from "yaml";
|
|
5
3
|
import fs from "fs";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"u8",
|
|
9
|
-
"i16",
|
|
10
|
-
"u16",
|
|
11
|
-
"i32",
|
|
12
|
-
"u32",
|
|
13
|
-
"i64",
|
|
14
|
-
"u64",
|
|
15
|
-
"isize",
|
|
16
|
-
"usize",
|
|
17
|
-
"f32",
|
|
18
|
-
"f64",
|
|
19
|
-
"bool",
|
|
20
|
-
"string",
|
|
21
|
-
];
|
|
22
|
-
const ManifestFunctionArgumentSchema = z.object({
|
|
23
|
-
name: z.string(),
|
|
24
|
-
description: z.string(),
|
|
25
|
-
type: z.enum(ASC_TYPES),
|
|
26
|
-
});
|
|
27
|
-
const ManifestFunctionSchema = z.object({
|
|
28
|
-
name: z.string(),
|
|
29
|
-
description: z.string(),
|
|
30
|
-
arguments: z.array(ManifestFunctionArgumentSchema).optional(),
|
|
31
|
-
});
|
|
32
|
-
const ManifestSchema = z.object({
|
|
33
|
-
name: z.string(),
|
|
34
|
-
functions: z.array(ManifestFunctionSchema).optional(),
|
|
35
|
-
});
|
|
4
|
+
import { execSync } from "node:child_process";
|
|
5
|
+
const AS_PROTO_GEN_PATH = "./node_modules/@asterai/sdk/node_modules/.bin/as-proto-gen";
|
|
36
6
|
export default class Codegen extends Command {
|
|
37
7
|
static args = {};
|
|
38
8
|
static description = "Generate code from the plugin manifest";
|
|
@@ -41,7 +11,7 @@ export default class Codegen extends Command {
|
|
|
41
11
|
manifest: Flags.string({
|
|
42
12
|
char: "m",
|
|
43
13
|
description: "manifest path",
|
|
44
|
-
default: "plugin.asterai.
|
|
14
|
+
default: "plugin.asterai.proto",
|
|
45
15
|
}),
|
|
46
16
|
outputDir: Flags.string({
|
|
47
17
|
char: "o",
|
|
@@ -51,42 +21,36 @@ export default class Codegen extends Command {
|
|
|
51
21
|
};
|
|
52
22
|
async run() {
|
|
53
23
|
const { flags } = await this.parse(Codegen);
|
|
54
|
-
|
|
55
|
-
const baseDir = path.dirname(manifestPath);
|
|
56
|
-
const outDir = path.join(baseDir, flags.outputDir);
|
|
57
|
-
const manifest = ManifestSchema.parse(YAML.parse(fs.readFileSync(manifestPath, "utf8")));
|
|
58
|
-
if (!manifest.functions) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
if (!fs.existsSync(outDir)) {
|
|
62
|
-
fs.mkdirSync(outDir, { recursive: true });
|
|
63
|
-
}
|
|
64
|
-
for (const func of manifest.functions) {
|
|
65
|
-
const className = `${capitaliseFirstLetter(func.name)}Args`;
|
|
66
|
-
const fileName = `${className}.ts`;
|
|
67
|
-
const filePath = path.join(outDir, fileName);
|
|
68
|
-
const stream = fs.createWriteStream(filePath);
|
|
69
|
-
writeFunctionFile(className, func.arguments ?? [], stream);
|
|
70
|
-
}
|
|
24
|
+
codegen(flags);
|
|
71
25
|
}
|
|
72
26
|
}
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
27
|
+
export const codegen = (flags) => {
|
|
28
|
+
const manifestPath = path.resolve(flags.manifest);
|
|
29
|
+
const baseDir = path.dirname(manifestPath);
|
|
30
|
+
const outDir = path.join(baseDir, flags.outputDir);
|
|
31
|
+
if (!fs.existsSync(outDir)) {
|
|
32
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
deleteOldGeneratedFiles(outDir);
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
execSync("protoc " +
|
|
39
|
+
`--plugin=protoc-gen-as=${AS_PROTO_GEN_PATH} ` +
|
|
40
|
+
`--as_out=./${flags.outputDir} ./${flags.manifest}`);
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
console.error("Failed to generate protobuf types:", e);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const deleteOldGeneratedFiles = (outDir) => {
|
|
47
|
+
const oldFiles = fs.readdirSync(outDir);
|
|
48
|
+
for (const oldFile of oldFiles) {
|
|
49
|
+
const file = path.parse(oldFile);
|
|
50
|
+
if (file.ext !== ".ts") {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const deletePath = path.join(outDir, oldFile);
|
|
54
|
+
fs.unlinkSync(deletePath);
|
|
55
|
+
}
|
|
81
56
|
};
|
|
82
|
-
const renderArgGetterString = (arg) => `
|
|
83
|
-
public get ${arg.name}(): ${arg.type} {
|
|
84
|
-
${arg.type === "string"
|
|
85
|
-
? `return this.mustGet("${arg.name}")`
|
|
86
|
-
: `
|
|
87
|
-
const value = this.mustGet("${arg.name}");
|
|
88
|
-
return parseTypeFromString<${arg.type}>(value, "${arg.type}");
|
|
89
|
-
`.trim()}
|
|
90
|
-
}
|
|
91
|
-
`;
|
|
92
|
-
const capitaliseFirstLetter = (string) => string.charAt(0).toUpperCase() + string.slice(1);
|
package/dist/commands/deploy.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Args, Command, Flags } from "@oclif/core";
|
|
2
|
-
import path from "path";
|
|
3
2
|
import fs from "fs";
|
|
4
|
-
import
|
|
3
|
+
import path from "path";
|
|
5
4
|
import FormData from "form-data";
|
|
6
5
|
import axios from "axios";
|
|
7
6
|
import { getConfigValue } from "../config.js";
|
|
7
|
+
import { build } from "./build.js";
|
|
8
8
|
const PRODUCTION_ENDPOINT = "https://api.asterai.io/app/plugin";
|
|
9
9
|
const STAGING_ENDPOINT = "https://staging.api.asterai.io/app/plugin";
|
|
10
10
|
export default class Deploy extends Command {
|
|
@@ -26,7 +26,7 @@ export default class Deploy extends Command {
|
|
|
26
26
|
manifest: Flags.string({
|
|
27
27
|
char: "m",
|
|
28
28
|
description: "manifest path",
|
|
29
|
-
default: "plugin.asterai.
|
|
29
|
+
default: "plugin.asterai.proto",
|
|
30
30
|
}),
|
|
31
31
|
endpoint: Flags.string({
|
|
32
32
|
char: "e",
|
|
@@ -38,44 +38,63 @@ export default class Deploy extends Command {
|
|
|
38
38
|
};
|
|
39
39
|
async run() {
|
|
40
40
|
const { args, flags } = await this.parse(Deploy);
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
const output = await build(args, flags);
|
|
42
|
+
await deploy(output, flags);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const deploy = async (args, flags) => {
|
|
46
|
+
const form = new FormData();
|
|
47
|
+
form.append("app_id", flags.app);
|
|
48
|
+
form.append("module", fs.readFileSync(args.outputFile));
|
|
49
|
+
const manifestString = fs.readFileSync(args.manifestPath, {
|
|
50
|
+
encoding: "utf8",
|
|
51
|
+
});
|
|
52
|
+
const mergedManifestString = mergeProtoImports(manifestString, args.manifestPath);
|
|
53
|
+
form.append("manifest", mergedManifestString);
|
|
54
|
+
const url = flags.staging ? STAGING_ENDPOINT : flags.endpoint;
|
|
55
|
+
await axios({
|
|
56
|
+
url,
|
|
57
|
+
method: "put",
|
|
58
|
+
data: form,
|
|
59
|
+
headers: {
|
|
60
|
+
Authorization: getConfigValue("key"),
|
|
61
|
+
...form.getHeaders(),
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
.then(() => console.log("done"))
|
|
65
|
+
.catch(logRequestError);
|
|
66
|
+
};
|
|
67
|
+
export const mergeProtoImports = (proto, protoPath, excludeSdk = true, excludeSyntaxDefinition = true, n = 0) => {
|
|
68
|
+
let mergedManifestString = "";
|
|
69
|
+
const lines = proto.split("\n");
|
|
70
|
+
for (let line of lines) {
|
|
71
|
+
line = line.trim();
|
|
72
|
+
const isSyntaxLine = line.startsWith("syntax");
|
|
73
|
+
if (isSyntaxLine && (excludeSyntaxDefinition || n > 1)) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const isImportLine = line.startsWith("import");
|
|
77
|
+
if (!isImportLine) {
|
|
78
|
+
mergedManifestString = `${mergedManifestString}\n${line}`;
|
|
79
|
+
continue;
|
|
45
80
|
}
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
if (
|
|
52
|
-
|
|
81
|
+
const importLine = line.replaceAll("'", '"');
|
|
82
|
+
const pathStart = importLine.indexOf('"') + 1;
|
|
83
|
+
const pathEnd = importLine.lastIndexOf('"');
|
|
84
|
+
const pathRelative = importLine.substring(pathStart, pathEnd);
|
|
85
|
+
const isSdkImport = pathRelative.startsWith("node_modules/@asterai/sdk");
|
|
86
|
+
if (isSdkImport && excludeSdk) {
|
|
87
|
+
// Asterai protobuf definitions should not be uploaded
|
|
88
|
+
// as part of the plugin manifest.
|
|
89
|
+
continue;
|
|
53
90
|
}
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
libs: libsDir,
|
|
59
|
-
};
|
|
60
|
-
await compile(options);
|
|
61
|
-
const form = new FormData();
|
|
62
|
-
form.append("app_id", flags.app);
|
|
63
|
-
form.append("module", fs.readFileSync(outputFile));
|
|
64
|
-
form.append("manifest", fs.readFileSync(manifestPath));
|
|
65
|
-
const url = flags.staging ? STAGING_ENDPOINT : flags.endpoint;
|
|
66
|
-
await axios({
|
|
67
|
-
url,
|
|
68
|
-
method: "put",
|
|
69
|
-
data: form,
|
|
70
|
-
headers: {
|
|
71
|
-
Authorization: getConfigValue("key"),
|
|
72
|
-
...form.getHeaders(),
|
|
73
|
-
},
|
|
74
|
-
})
|
|
75
|
-
.then(() => console.log("done"))
|
|
76
|
-
.catch(logRequestError);
|
|
91
|
+
const pathAbsolute = path.join(path.dirname(protoPath), pathRelative);
|
|
92
|
+
const importProto = fs.readFileSync(pathAbsolute, { encoding: "utf8" });
|
|
93
|
+
const importProtoMerged = mergeProtoImports(importProto, pathAbsolute, excludeSdk, excludeSyntaxDefinition, n + 1);
|
|
94
|
+
mergedManifestString = `${mergedManifestString}\n${importProtoMerged}`;
|
|
77
95
|
}
|
|
78
|
-
|
|
96
|
+
return mergedManifestString.trim();
|
|
97
|
+
};
|
|
79
98
|
const logRequestError = (e) => {
|
|
80
99
|
const info = e.response?.data ?? e;
|
|
81
100
|
console.log("request error:", info);
|
package/dist/compile.d.ts
CHANGED
package/dist/compile.js
CHANGED
|
@@ -4,14 +4,11 @@ const COMPILER_OPTIONS = {
|
|
|
4
4
|
stderr: process.stderr,
|
|
5
5
|
};
|
|
6
6
|
export const compile = async (options) => {
|
|
7
|
-
// TODO also include a file here to remove the necessity of including
|
|
8
|
-
// export * from "@asterai/sdk";
|
|
9
|
-
// in each plugin.
|
|
10
7
|
const args = [
|
|
11
8
|
"--exportRuntime",
|
|
12
9
|
"--runtime",
|
|
13
10
|
"stub",
|
|
14
|
-
options.
|
|
11
|
+
...options.inputFiles,
|
|
15
12
|
"--baseDir",
|
|
16
13
|
options.baseDir,
|
|
17
14
|
"--lib",
|
package/oclif.manifest.json
CHANGED
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"char": "m",
|
|
46
46
|
"description": "manifest path",
|
|
47
47
|
"name": "manifest",
|
|
48
|
-
"default": "plugin.asterai.
|
|
48
|
+
"default": "plugin.asterai.proto",
|
|
49
49
|
"hasDynamicHelp": false,
|
|
50
50
|
"multiple": false,
|
|
51
51
|
"type": "option"
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"char": "m",
|
|
79
79
|
"description": "manifest path",
|
|
80
80
|
"name": "manifest",
|
|
81
|
-
"default": "plugin.asterai.
|
|
81
|
+
"default": "plugin.asterai.proto",
|
|
82
82
|
"hasDynamicHelp": false,
|
|
83
83
|
"multiple": false,
|
|
84
84
|
"type": "option"
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
"char": "m",
|
|
135
135
|
"description": "manifest path",
|
|
136
136
|
"name": "manifest",
|
|
137
|
-
"default": "plugin.asterai.
|
|
137
|
+
"default": "plugin.asterai.proto",
|
|
138
138
|
"hasDynamicHelp": false,
|
|
139
139
|
"multiple": false,
|
|
140
140
|
"type": "option"
|
|
@@ -198,5 +198,5 @@
|
|
|
198
198
|
]
|
|
199
199
|
}
|
|
200
200
|
},
|
|
201
|
-
"version": "0.
|
|
201
|
+
"version": "0.2.0"
|
|
202
202
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asterai/cli",
|
|
3
|
-
"description": "CLI for building and deploying
|
|
4
|
-
"version": "0.
|
|
3
|
+
"description": "CLI for building and deploying asterai plugins",
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"author": "asterai <support@asterai.io>",
|
|
6
6
|
"repository": "asterai-io/asterai-sdk",
|
|
7
7
|
"homepage": "https://github.com/asterai-io/asterai-sdk",
|
|
@@ -13,6 +13,18 @@
|
|
|
13
13
|
"license": "UNLICENSED",
|
|
14
14
|
"main": "dist/index.js",
|
|
15
15
|
"type": "module",
|
|
16
|
+
"scripts": {
|
|
17
|
+
"prepare": "cd .. && husky cli/.husky",
|
|
18
|
+
"build": "shx rm -rf dist && tsc -b",
|
|
19
|
+
"lint": "eslint . --ext .ts",
|
|
20
|
+
"postpack": "shx rm -f oclif.manifest.json",
|
|
21
|
+
"posttest": "pnpm run lint",
|
|
22
|
+
"prepack": "oclif manifest && oclif readme",
|
|
23
|
+
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
|
|
24
|
+
"version": "oclif readme && git add README.md",
|
|
25
|
+
"format": "prettier --write .",
|
|
26
|
+
"format-staged": "pretty-quick --staged"
|
|
27
|
+
},
|
|
16
28
|
"bin": {
|
|
17
29
|
"asterai": "./bin/run.js"
|
|
18
30
|
},
|
|
@@ -44,14 +56,15 @@
|
|
|
44
56
|
"assemblyscript": "^0.27.27",
|
|
45
57
|
"axios": "^1.7.2",
|
|
46
58
|
"form-data": "^4.0.0",
|
|
47
|
-
"
|
|
48
|
-
"
|
|
59
|
+
"mustache": "^4.2.0",
|
|
60
|
+
"protobufjs": "^7.4.0"
|
|
49
61
|
},
|
|
50
62
|
"devDependencies": {
|
|
51
63
|
"@oclif/prettier-config": "^0.2.1",
|
|
52
64
|
"@oclif/test": "^4",
|
|
53
65
|
"@types/chai": "^4",
|
|
54
66
|
"@types/mocha": "^10",
|
|
67
|
+
"@types/mustache": "^4.2.5",
|
|
55
68
|
"@types/node": "^18",
|
|
56
69
|
"chai": "^4",
|
|
57
70
|
"eslint": "^8",
|
|
@@ -66,14 +79,5 @@
|
|
|
66
79
|
"shx": "^0.3.3",
|
|
67
80
|
"ts-node": "^10",
|
|
68
81
|
"typescript": "^5"
|
|
69
|
-
},
|
|
70
|
-
"scripts": {
|
|
71
|
-
"build": "shx rm -rf dist && tsc -b",
|
|
72
|
-
"lint": "eslint . --ext .ts",
|
|
73
|
-
"posttest": "pnpm run lint",
|
|
74
|
-
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
|
|
75
|
-
"version": "oclif readme && git add README.md",
|
|
76
|
-
"format": "prettier --write .",
|
|
77
|
-
"format-staged": "pretty-quick --staged"
|
|
78
82
|
}
|
|
79
|
-
}
|
|
83
|
+
}
|