@asterai/cli 0.1.3 → 0.2.1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @asterai/cli
2
2
 
3
- CLI for building and deploying AsterAI plugins
3
+ CLI for building and deploying asterai plugins
4
4
 
5
5
  [![oclif](https://img.shields.io/badge/cli-oclif-brightgreen.svg)](https://oclif.io)
6
6
  [![Version](https://img.shields.io/npm/v/@asterai/cli.svg)](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.1.3 linux-x64 node-v20.12.2
23
+ @asterai/cli/0.2.1 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.1.3/src/commands/auth.ts)_
56
+ _See code: [src/commands/auth.ts](https://github.com/asterai-io/asterai-sdk/blob/v0.2.1/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.yaml] manifest path
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.1.3/src/commands/build.ts)_
76
+ _See code: [src/commands/build.ts](https://github.com/asterai-io/asterai-sdk/blob/v0.2.1/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.yaml] manifest path
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.1.3/src/commands/codegen.ts)_
97
+ _See code: [src/commands/codegen.ts](https://github.com/asterai-io/asterai-sdk/blob/v0.2.1/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.yaml] manifest path
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.1.3/src/commands/deploy.ts)_
120
+ _See code: [src/commands/deploy.ts](https://github.com/asterai-io/asterai-sdk/blob/v0.2.1/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.1.3/src/commands/init.ts)_
157
+ _See code: [src/commands/init.ts](https://github.com/asterai-io/asterai-sdk/blob/v0.2.1/src/commands/init.ts)_
158
158
  <!-- commandsstop -->
@@ -12,7 +12,9 @@
12
12
  },
13
13
  "type": "module",
14
14
  "devDependencies": {
15
- "@asterai/sdk": "0.1.3"
15
+ "@asterai/cli": "latest",
16
+ "@asterai/sdk": "latest",
17
+ "@asterai/as-proto": "latest"
16
18
  },
17
19
  "peerDependencies": {
18
20
  "assemblyscript": "0.27.27"
@@ -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 { OrderBurgerArgs } from "./generated/OrderBurgerArgs";
2
- export * from "@asterai/sdk/exports";
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 orderBurger(args: OrderBurgerArgs): string {
5
- // TODO: make http call to burger API.
6
- return `burger delivered to ${args.address}`;
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
@@ -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>;
@@ -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.yaml",
20
+ default: "plugin.asterai.proto",
18
21
  }),
19
22
  };
20
23
  async run() {
21
24
  const { args, flags } = await this.parse(Build);
22
- const manifestPath = path.resolve(flags.manifest);
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;
@@ -1,38 +1,9 @@
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
- const ASC_TYPES = [
7
- "i8",
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
+ // Relative path from the CLI root directory.
6
+ const AS_PROTO_GEN_PATH = "node_modules/.bin/as-proto-gen";
36
7
  export default class Codegen extends Command {
37
8
  static args = {};
38
9
  static description = "Generate code from the plugin manifest";
@@ -41,7 +12,7 @@ export default class Codegen extends Command {
41
12
  manifest: Flags.string({
42
13
  char: "m",
43
14
  description: "manifest path",
44
- default: "plugin.asterai.yaml",
15
+ default: "plugin.asterai.proto",
45
16
  }),
46
17
  outputDir: Flags.string({
47
18
  char: "o",
@@ -51,42 +22,42 @@ export default class Codegen extends Command {
51
22
  };
52
23
  async run() {
53
24
  const { flags } = await this.parse(Codegen);
54
- const manifestPath = path.resolve(flags.manifest);
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
- }
25
+ codegen(flags);
71
26
  }
72
27
  }
73
- const writeFunctionFile = (className, args, stream) => {
74
- stream.write(`\
75
- import {parseTypeFromString, TypedMap} from "@asterai/sdk/collections";
76
-
77
- export class ${className} extends TypedMap<string, string> {
78
- ${args.map(renderArgGetterString).join("")}
79
- }
80
- `);
28
+ export const codegen = (flags) => {
29
+ const manifestPath = path.resolve(flags.manifest);
30
+ const baseDir = path.dirname(manifestPath);
31
+ const outDir = path.join(baseDir, flags.outputDir);
32
+ if (!fs.existsSync(outDir)) {
33
+ fs.mkdirSync(outDir, { recursive: true });
34
+ }
35
+ else {
36
+ deleteOldGeneratedFiles(outDir);
37
+ }
38
+ const cliRootDir = getCliRootDir();
39
+ const absoluteAsProtoGenPath = path.join(cliRootDir, AS_PROTO_GEN_PATH);
40
+ try {
41
+ execSync("protoc " +
42
+ `--plugin=protoc-gen-as=${absoluteAsProtoGenPath} ` +
43
+ `--as_out=./${flags.outputDir} ./${flags.manifest}`);
44
+ }
45
+ catch (e) {
46
+ console.error("Failed to generate protobuf types:", e);
47
+ }
48
+ };
49
+ const deleteOldGeneratedFiles = (outDir) => {
50
+ const oldFiles = fs.readdirSync(outDir);
51
+ for (const oldFile of oldFiles) {
52
+ const file = path.parse(oldFile);
53
+ if (file.ext !== ".ts") {
54
+ continue;
55
+ }
56
+ const deletePath = path.join(outDir, oldFile);
57
+ fs.unlinkSync(deletePath);
58
+ }
59
+ };
60
+ const getCliRootDir = () => {
61
+ const fullCliBinPath = path.parse(process.argv[1]).dir;
62
+ return path.join(fullCliBinPath, "../");
81
63
  };
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);
@@ -13,3 +13,4 @@ export default class Deploy extends Command {
13
13
  };
14
14
  run(): Promise<void>;
15
15
  }
16
+ export declare const mergeProtoImports: (proto: string, protoPath: string, excludeSdk?: boolean, excludeSyntaxDefinition?: boolean, n?: number) => string;
@@ -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 { compile } from "../compile.js";
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.yaml",
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 manifestPath = path.resolve(flags.manifest);
42
- const inputFile = path.resolve(args.input);
43
- if (!fs.existsSync(inputFile)) {
44
- throw new Error(`input file not found (${args.input})`);
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 inputFileName = path.parse(inputFile).name;
47
- const baseDir = path.dirname(manifestPath);
48
- const outDir = path.join(baseDir, "build");
49
- const outputFile = path.join(outDir, `${inputFileName}.wasm`);
50
- const libsDir = path.join(baseDir, "node_modules");
51
- if (!fs.existsSync(libsDir)) {
52
- throw new Error("no node_modules found in the plugin directory");
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 options = {
55
- inputFile,
56
- baseDir,
57
- outputFile,
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
@@ -1,5 +1,5 @@
1
1
  export type CompileOptions = {
2
- inputFile: string;
2
+ inputFiles: string[];
3
3
  baseDir: string;
4
4
  libs: string;
5
5
  outputFile: string;
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.inputFile,
11
+ ...options.inputFiles,
15
12
  "--baseDir",
16
13
  options.baseDir,
17
14
  "--lib",
@@ -45,7 +45,7 @@
45
45
  "char": "m",
46
46
  "description": "manifest path",
47
47
  "name": "manifest",
48
- "default": "plugin.asterai.yaml",
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.yaml",
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.yaml",
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.1.3"
201
+ "version": "0.2.1"
202
202
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@asterai/cli",
3
- "description": "CLI for building and deploying AsterAI plugins",
4
- "version": "0.1.3",
3
+ "description": "CLI for building and deploying asterai plugins",
4
+ "version": "0.2.1",
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
  },
@@ -38,20 +50,22 @@
38
50
  },
39
51
  "types": "dist/index.d.ts",
40
52
  "dependencies": {
53
+ "@asterai/as-proto-gen": "^1.4.1",
41
54
  "@oclif/core": "^3",
42
55
  "@oclif/plugin-help": "^6",
43
56
  "@oclif/plugin-plugins": "^5",
44
57
  "assemblyscript": "^0.27.27",
45
58
  "axios": "^1.7.2",
46
59
  "form-data": "^4.0.0",
47
- "yaml": "^2.4.5",
48
- "zod": "^3.23.8"
60
+ "mustache": "^4.2.0",
61
+ "protobufjs": "^7.4.0"
49
62
  },
50
63
  "devDependencies": {
51
64
  "@oclif/prettier-config": "^0.2.1",
52
65
  "@oclif/test": "^4",
53
66
  "@types/chai": "^4",
54
67
  "@types/mocha": "^10",
68
+ "@types/mustache": "^4.2.5",
55
69
  "@types/node": "^18",
56
70
  "chai": "^4",
57
71
  "eslint": "^8",
@@ -66,14 +80,5 @@
66
80
  "shx": "^0.3.3",
67
81
  "ts-node": "^10",
68
82
  "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
83
  }
79
- }
84
+ }
@@ -1,9 +0,0 @@
1
- name: plugin
2
- functions:
3
- - name: orderBurger
4
- description: >-
5
- orders a burger to be delivered to the specified address
6
- arguments:
7
- - name: address
8
- type: string
9
- description: the address to deliver the burger to