@onkernel/cli 0.0.2 → 0.1.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/README.md +103 -6
- package/install.js +6 -0
- package/lib.js +175 -0
- package/package.json +97 -43
- package/run-kernel.js +6 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -150
package/README.md
CHANGED
|
@@ -1,15 +1,112 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Kernel CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A command-line tool for deploying and invoking Kernel applications.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
4
6
|
|
|
5
7
|
```bash
|
|
6
|
-
|
|
8
|
+
brew tap onkernel/homebrew-tap
|
|
9
|
+
brew install kernel
|
|
7
10
|
```
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
## Development Prerequisites
|
|
13
|
+
|
|
14
|
+
Install the following tools:
|
|
15
|
+
|
|
16
|
+
- Go 1.22+ ( https://go.dev/doc/install )
|
|
17
|
+
- [Goreleaser](https://goreleaser.com/install/)
|
|
18
|
+
- [chglog](https://github.com/goreleaser/chglog)
|
|
19
|
+
|
|
20
|
+
Compile the CLI:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
make build # compiles the binary to ./bin/kernel
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Run the CLI:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
./bin/kernel --help
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Development workflow
|
|
33
|
+
|
|
34
|
+
Useful make targets:
|
|
35
|
+
|
|
36
|
+
- `make build` – compile the project to `./bin/kernel`
|
|
37
|
+
- `make test` – execute unit tests
|
|
38
|
+
- `make lint` – run the linter (requires `golangci-lint`)
|
|
39
|
+
- `make changelog` – generate/update the `CHANGELOG.md` file using **chglog**
|
|
40
|
+
- `make release` – create a release using **goreleaser** (builds archives, homebrew formula, etc. See below)
|
|
41
|
+
|
|
42
|
+
### Releasing a new version
|
|
43
|
+
|
|
44
|
+
Prerequisites:
|
|
45
|
+
|
|
46
|
+
- Make sure you have `goreleaser` _pro_ installed via `brew install goreleaser/tap/goreleaser-pro`. You will need a license key (in 1pw), and then `export GORELEASER_KEY=<the key>`.
|
|
47
|
+
|
|
48
|
+
- Grab the NPM token for our org (in 1pw) and run `npm config set '//registry.npmjs.org/:_authToken'=<the token>`
|
|
49
|
+
|
|
50
|
+
- export a `GITHUB_TOKEN` with repo and write:packages permissions: https://github.com/settings/tokens/new?scopes=repo,write:packages.
|
|
51
|
+
|
|
52
|
+
- Make sure you are logged in to the prod AWS account with `aws sso login --sso-session=kernel` + `export AWS_PROFILE=kernel-prod`. This is necessary to publish releases to S3.
|
|
53
|
+
|
|
54
|
+
On main, run:
|
|
10
55
|
|
|
11
56
|
```bash
|
|
12
|
-
|
|
57
|
+
make release-dry-run
|
|
13
58
|
```
|
|
14
59
|
|
|
15
|
-
This
|
|
60
|
+
This will check that everything is working, but not actually release anything.
|
|
61
|
+
You should see one error about there not being a git tag, and that's fine.
|
|
62
|
+
|
|
63
|
+
To actually release, run:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
export VERSION=0.1.1
|
|
67
|
+
git tag -a cli/v$VERSION -m "Bugfixes"
|
|
68
|
+
git push origin cli/v$VERSION
|
|
69
|
+
make release
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Environment variables
|
|
73
|
+
|
|
74
|
+
The CLI requires a Kernel API key to interact with the platform:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
export KERNEL_API_KEY=your_api_key
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Releasing a new version
|
|
81
|
+
|
|
82
|
+
1. Update the changelog:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
make changelog
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
2. Tag the release (e.g. `v1.0.0`) and push the tag:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
git tag cli/v0.1.0
|
|
92
|
+
git push origin cli/v0.1.0
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
3. Run `make release` – **goreleaser** will:
|
|
96
|
+
|
|
97
|
+
- Build binaries for macOS (arm64/amd64), Linux and Windows
|
|
98
|
+
- Create a GitHub release upload archives
|
|
99
|
+
- Publish/commit the Homebrew formula to the `onkernel/homebrew-tap` repository
|
|
100
|
+
|
|
101
|
+
## Directory structure
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
packages/cli
|
|
105
|
+
├── cmd/ # cobra commands (root, deploy, invoke, …)
|
|
106
|
+
│ └── kernel/
|
|
107
|
+
│ └── main.go
|
|
108
|
+
├── pkg/ # reusable helpers (zip util, etc.)
|
|
109
|
+
├── .goreleaser.yaml
|
|
110
|
+
├── Makefile
|
|
111
|
+
└── README.md
|
|
112
|
+
```
|
package/install.js
ADDED
package/lib.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// This file was generated by GoReleaser. DO NOT EDIT.
|
|
2
|
+
const { archives } = require("./package.json");
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const crypto = require("crypto");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const JSZip = require("jszip");
|
|
7
|
+
const tar = require("tar");
|
|
8
|
+
const axios = require("axios");
|
|
9
|
+
const { spawnSync } = require("child_process");
|
|
10
|
+
|
|
11
|
+
const getArchive = () => {
|
|
12
|
+
let target = `${process.platform}-${process.arch}`;
|
|
13
|
+
const archive = archives[target];
|
|
14
|
+
if (!archive) {
|
|
15
|
+
throw new Error(`No archive available for ${target}`);
|
|
16
|
+
}
|
|
17
|
+
return archive;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const binDir = path.join(__dirname, "bin");
|
|
21
|
+
|
|
22
|
+
async function extractTar(tarPath, binaries, dir) {
|
|
23
|
+
try {
|
|
24
|
+
await tar.x({
|
|
25
|
+
file: tarPath,
|
|
26
|
+
cwd: dir,
|
|
27
|
+
filter: (path) => binaries.includes(path),
|
|
28
|
+
});
|
|
29
|
+
console.log(`Successfully extracted binaries to "${dir}"`);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
throw new Error(`Extraction failed: ${err.message}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function extractZip(zipPath, binaries, dir) {
|
|
36
|
+
try {
|
|
37
|
+
const zipData = fs.readFileSync(zipPath);
|
|
38
|
+
const zip = await JSZip.loadAsync(zipData);
|
|
39
|
+
for (const binary of binaries) {
|
|
40
|
+
if (!zip.files[binary]) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`Error: ${binary} does not exist in ${zipPath}`,
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const content = await zip.files[binary].async("nodebuffer");
|
|
47
|
+
if (!fs.existsSync(dir)) {
|
|
48
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
const file = path.join(dir, binary);
|
|
51
|
+
fs.writeFileSync(file, content);
|
|
52
|
+
fs.chmodSync(file, "755");
|
|
53
|
+
console.log(`Successfully extracted "${binary}" to "${dir}"`);
|
|
54
|
+
}
|
|
55
|
+
} catch (err) {
|
|
56
|
+
throw new Error(`Extraction failed: ${err.message}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const run = async (bin) => {
|
|
61
|
+
await install();
|
|
62
|
+
if (process.platform === "win32") {
|
|
63
|
+
bin += ".exe";
|
|
64
|
+
}
|
|
65
|
+
const [, , ...args] = process.argv;
|
|
66
|
+
let result = spawnSync(path.join(binDir, bin), args, {
|
|
67
|
+
cwd: process.cwd(),
|
|
68
|
+
stdio: "inherit",
|
|
69
|
+
});
|
|
70
|
+
if (result.error) {
|
|
71
|
+
console.error(result.error);
|
|
72
|
+
}
|
|
73
|
+
return result.status;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const install = async () => {
|
|
77
|
+
try {
|
|
78
|
+
let archive = getArchive();
|
|
79
|
+
if (await exists(archive)) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
let tmp = fs.mkdtempSync("archive-");
|
|
83
|
+
let archivePath = path.join(tmp, archive.name);
|
|
84
|
+
await download(archive.url, archivePath);
|
|
85
|
+
verify(archivePath, archive.checksum);
|
|
86
|
+
|
|
87
|
+
if (!fs.existsSync(binDir)) {
|
|
88
|
+
fs.mkdirSync(binDir);
|
|
89
|
+
}
|
|
90
|
+
switch (archive.format) {
|
|
91
|
+
case "binary":
|
|
92
|
+
const bin = path.join(binDir, archive.bins[0]);
|
|
93
|
+
fs.copyFileSync(archivePath, bin);
|
|
94
|
+
fs.chmodSync(bin, 0o755);
|
|
95
|
+
return;
|
|
96
|
+
case "zip":
|
|
97
|
+
return extractZip(archivePath, archive.bins, binDir);
|
|
98
|
+
case "tar":
|
|
99
|
+
case "tar.gz":
|
|
100
|
+
case "tgz":
|
|
101
|
+
return extractTar(archivePath, archive.bins, binDir);
|
|
102
|
+
case "tar.zst":
|
|
103
|
+
case "tzst":
|
|
104
|
+
case "tar.xz":
|
|
105
|
+
case "txz":
|
|
106
|
+
default:
|
|
107
|
+
throw new Error(`unsupported format: ${archive.format}`);
|
|
108
|
+
}
|
|
109
|
+
} catch (err) {
|
|
110
|
+
throw new Error(`Installation failed: ${err.message}`);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const verify = (filename, checksum) => {
|
|
115
|
+
if (checksum.algorithm == "" || checksum.digest == "") {
|
|
116
|
+
console.warn("Warning: No checksum provided for verification");
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
let digest = crypto
|
|
120
|
+
.createHash(checksum.algorithm)
|
|
121
|
+
.update(fs.readFileSync(filename))
|
|
122
|
+
.digest("hex");
|
|
123
|
+
if (digest != checksum.digest) {
|
|
124
|
+
throw new Error(
|
|
125
|
+
`${filename}: ${checksum.algorithm} does not match, expected ${checksum.digest}, got ${digest}`,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const download = async (url, filename) => {
|
|
131
|
+
try {
|
|
132
|
+
console.log(`Downloading ${url} to ${filename}...`);
|
|
133
|
+
const dir = path.dirname(filename);
|
|
134
|
+
if (!fs.existsSync(dir)) {
|
|
135
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const response = await axios({
|
|
139
|
+
method: "GET",
|
|
140
|
+
url: url,
|
|
141
|
+
responseType: "stream",
|
|
142
|
+
timeout: 300000, // 5min
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const writer = fs.createWriteStream(filename);
|
|
146
|
+
response.data.pipe(writer);
|
|
147
|
+
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
writer.on("finish", () => {
|
|
150
|
+
console.log(`Download complete: ${filename}`);
|
|
151
|
+
resolve(dir);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
writer.on("error", (err) => {
|
|
155
|
+
console.error(`Error writing file: ${err.message}`);
|
|
156
|
+
reject(err);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
} catch (err) {
|
|
160
|
+
throw new Error(`Download failed: ${err.message}`);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
function exists(archive) {
|
|
165
|
+
if (!fs.existsSync(binDir)) {
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
return archive.bins.every((bin) => fs.existsSync(path.join(binDir, bin)));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
module.exports = {
|
|
172
|
+
install,
|
|
173
|
+
run,
|
|
174
|
+
getArchive,
|
|
175
|
+
};
|
package/package.json
CHANGED
|
@@ -1,54 +1,108 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onkernel/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Kernel
|
|
5
|
-
"type": "module",
|
|
6
|
-
"module": "index.ts",
|
|
7
|
-
"main": "dist/index.js",
|
|
8
|
-
"types": "dist/index.d.ts",
|
|
9
|
-
"bin": {
|
|
10
|
-
"kernel": "./dist/index.js"
|
|
11
|
-
},
|
|
12
|
-
"files": [
|
|
13
|
-
"dist"
|
|
14
|
-
],
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "CLI for Kernel",
|
|
15
5
|
"scripts": {
|
|
16
|
-
"
|
|
6
|
+
"postinstall": "node install.js",
|
|
7
|
+
"run": "node run-kernel.js"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://onkernel-public.s3.us-east-1.amazonaws.com/"
|
|
17
12
|
},
|
|
18
13
|
"keywords": [
|
|
19
14
|
"kernel",
|
|
20
15
|
"cli",
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"agent",
|
|
25
|
-
"agents",
|
|
26
|
-
"dev",
|
|
27
|
-
"development",
|
|
28
|
-
"deploy",
|
|
29
|
-
"deployment",
|
|
30
|
-
"build",
|
|
31
|
-
"workflow",
|
|
32
|
-
"typescript",
|
|
33
|
-
"command-line",
|
|
34
|
-
"devtools"
|
|
16
|
+
"browsers",
|
|
17
|
+
"automation",
|
|
18
|
+
"ai"
|
|
35
19
|
],
|
|
36
|
-
"author": "",
|
|
20
|
+
"author": "Rafael Garcia \u003craf@onkernel.com\u003e",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/onkernel/kernel/issues"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://docs.onkernel.com",
|
|
26
|
+
"bin": {
|
|
27
|
+
"kernel": "run-kernel.js"
|
|
28
|
+
},
|
|
37
29
|
"dependencies": {
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"archiver": "^7.0.1",
|
|
42
|
-
"chalk": "^5.4.1",
|
|
43
|
-
"commander": "^13.1.0",
|
|
44
|
-
"fs-extra": "^11.3.0",
|
|
45
|
-
"ignore-walk": "^7.0.0",
|
|
46
|
-
"tmp": "^0.2.3",
|
|
47
|
-
"type-fest": "^4.40.1"
|
|
30
|
+
"axios": "^1.8.2",
|
|
31
|
+
"jszip": "^3.10.1",
|
|
32
|
+
"tar": "^7.4.3"
|
|
48
33
|
},
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
34
|
+
"archives": {
|
|
35
|
+
"darwin-arm64": {
|
|
36
|
+
"name": "kernel_0.1.3_darwin_arm64.tar.gz",
|
|
37
|
+
"url": "https://github.com/onkernel/kernel/releases/download/cli%2Fv0.1.3/kernel_0.1.3_darwin_arm64.tar.gz",
|
|
38
|
+
"bins": [
|
|
39
|
+
"kernel"
|
|
40
|
+
],
|
|
41
|
+
"format": "tar.gz",
|
|
42
|
+
"checksum": {
|
|
43
|
+
"algorithm": "sha256",
|
|
44
|
+
"digest": "d703b23c7e536c43dbc18b32eb0f87d61b0586bf4bbabb509cee0c7899bfc29e"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"darwin-x64": {
|
|
48
|
+
"name": "kernel_0.1.3_darwin_amd64.tar.gz",
|
|
49
|
+
"url": "https://github.com/onkernel/kernel/releases/download/cli%2Fv0.1.3/kernel_0.1.3_darwin_amd64.tar.gz",
|
|
50
|
+
"bins": [
|
|
51
|
+
"kernel"
|
|
52
|
+
],
|
|
53
|
+
"format": "tar.gz",
|
|
54
|
+
"checksum": {
|
|
55
|
+
"algorithm": "sha256",
|
|
56
|
+
"digest": "0af126117f591cedbfcd60dae8ff4a12dd2c3dcbb12e54594059d448d351a906"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"linux-arm64": {
|
|
60
|
+
"name": "kernel_0.1.3_linux_arm64.tar.gz",
|
|
61
|
+
"url": "https://github.com/onkernel/kernel/releases/download/cli%2Fv0.1.3/kernel_0.1.3_linux_arm64.tar.gz",
|
|
62
|
+
"bins": [
|
|
63
|
+
"kernel"
|
|
64
|
+
],
|
|
65
|
+
"format": "tar.gz",
|
|
66
|
+
"checksum": {
|
|
67
|
+
"algorithm": "sha256",
|
|
68
|
+
"digest": "8b50e00fd9f98ef3333081c916f392d3646b1ab214858daf6d0faa08e1223c03"
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"linux-x64": {
|
|
72
|
+
"name": "kernel_0.1.3_linux_amd64.tar.gz",
|
|
73
|
+
"url": "https://github.com/onkernel/kernel/releases/download/cli%2Fv0.1.3/kernel_0.1.3_linux_amd64.tar.gz",
|
|
74
|
+
"bins": [
|
|
75
|
+
"kernel"
|
|
76
|
+
],
|
|
77
|
+
"format": "tar.gz",
|
|
78
|
+
"checksum": {
|
|
79
|
+
"algorithm": "sha256",
|
|
80
|
+
"digest": "a23d3c552729de53d7321ecccc73d8108c1c7af850a917f4976ba81a59368b06"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"win32-arm64": {
|
|
84
|
+
"name": "kernel_0.1.3_windows_arm64.tar.gz",
|
|
85
|
+
"url": "https://github.com/onkernel/kernel/releases/download/cli%2Fv0.1.3/kernel_0.1.3_windows_arm64.tar.gz",
|
|
86
|
+
"bins": [
|
|
87
|
+
"kernel.exe"
|
|
88
|
+
],
|
|
89
|
+
"format": "tar.gz",
|
|
90
|
+
"checksum": {
|
|
91
|
+
"algorithm": "sha256",
|
|
92
|
+
"digest": "1ab255f78eae35d0e2a368ca04c99695933e7eacd19208ab53f4f1dbfa3323dd"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"win32-x64": {
|
|
96
|
+
"name": "kernel_0.1.3_windows_amd64.tar.gz",
|
|
97
|
+
"url": "https://github.com/onkernel/kernel/releases/download/cli%2Fv0.1.3/kernel_0.1.3_windows_amd64.tar.gz",
|
|
98
|
+
"bins": [
|
|
99
|
+
"kernel.exe"
|
|
100
|
+
],
|
|
101
|
+
"format": "tar.gz",
|
|
102
|
+
"checksum": {
|
|
103
|
+
"algorithm": "sha256",
|
|
104
|
+
"digest": "298beb9c14eacb53567debb23ea52e54f2098e1dd676f58c127e77a66869d78c"
|
|
105
|
+
}
|
|
106
|
+
}
|
|
53
107
|
}
|
|
54
|
-
}
|
|
108
|
+
}
|
package/run-kernel.js
ADDED
package/dist/index.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
package/dist/index.js
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
import { Kernel } from '@onkernel/sdk';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import { Command } from 'commander';
|
|
5
|
-
import fs, { createReadStream } from 'fs';
|
|
6
|
-
import path2 from 'path';
|
|
7
|
-
import * as tmp from 'tmp';
|
|
8
|
-
import archiver from 'archiver';
|
|
9
|
-
import fsExtra from 'fs-extra';
|
|
10
|
-
import walk from 'ignore-walk';
|
|
11
|
-
|
|
12
|
-
function getPackageVersion() {
|
|
13
|
-
const pkgJsonPath = path2.join(__dirname, "..", "..", "..", "package.json");
|
|
14
|
-
const content = fsExtra.readJSONSync(pkgJsonPath);
|
|
15
|
-
if (!content.version) {
|
|
16
|
-
throw new Error("package.json does not contain a version");
|
|
17
|
-
}
|
|
18
|
-
return content.version;
|
|
19
|
-
}
|
|
20
|
-
async function zipDirectory(inputDir, outputZip) {
|
|
21
|
-
const entries = await walk({
|
|
22
|
-
path: inputDir,
|
|
23
|
-
ignoreFiles: [".gitignore", ".dockerignore"],
|
|
24
|
-
includeEmpty: true,
|
|
25
|
-
follow: false
|
|
26
|
-
});
|
|
27
|
-
const output = fs.createWriteStream(outputZip);
|
|
28
|
-
const archive = archiver("zip", { zlib: { level: 9 } });
|
|
29
|
-
const finalizePromise = new Promise((resolve, reject) => {
|
|
30
|
-
output.on("close", resolve);
|
|
31
|
-
archive.on("error", reject);
|
|
32
|
-
});
|
|
33
|
-
archive.pipe(output);
|
|
34
|
-
for (const entry of entries) {
|
|
35
|
-
const fullPath = path2.join(inputDir, entry);
|
|
36
|
-
const stat = fs.statSync(fullPath);
|
|
37
|
-
const archivePath = entry.split(path2.sep).join("/");
|
|
38
|
-
if (stat.isFile()) {
|
|
39
|
-
archive.file(fullPath, { name: archivePath });
|
|
40
|
-
} else if (stat.isDirectory()) {
|
|
41
|
-
archive.append("", { name: archivePath.endsWith("/") ? archivePath : archivePath + "/" });
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
await archive.finalize();
|
|
45
|
-
await finalizePromise;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// index.ts
|
|
49
|
-
var program = new Command();
|
|
50
|
-
if (process.argv.length === 3 && ["-v", "--version"].includes(process.argv[2])) {
|
|
51
|
-
console.log(getPackageVersion());
|
|
52
|
-
process.exit(0);
|
|
53
|
-
}
|
|
54
|
-
program.name("kernel").description("CLI for Kernel deployment and invocation");
|
|
55
|
-
program.command("deploy").description("Deploy a Kernel application").argument("<entrypoint>", "Path to entrypoint file (TypeScript or Python)").option("--version <version>", "Specify a version for the app (default: latest)").option("--force", "Allow overwrite of an existing version with the same name").action(async (entrypoint, options) => {
|
|
56
|
-
let { version: versionArg, force } = options;
|
|
57
|
-
if (!versionArg) {
|
|
58
|
-
versionArg = "latest";
|
|
59
|
-
if (force && force !== "true") {
|
|
60
|
-
console.error("Error: --force must be used when version is latest");
|
|
61
|
-
process.exit(1);
|
|
62
|
-
} else if (!force) {
|
|
63
|
-
force = "true";
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
const resolvedEntrypoint = path2.resolve(entrypoint);
|
|
67
|
-
if (!fs.existsSync(resolvedEntrypoint)) {
|
|
68
|
-
console.error(`Error: Entrypoint ${resolvedEntrypoint} doesn't exist`);
|
|
69
|
-
process.exit(1);
|
|
70
|
-
}
|
|
71
|
-
const sourceDir = path2.dirname(resolvedEntrypoint);
|
|
72
|
-
if (!process.env["KERNEL_API_KEY"]) {
|
|
73
|
-
console.error("Error: KERNEL_API_KEY environment variable is not set");
|
|
74
|
-
console.error("Please set your Kernel API key using: export KERNEL_API_KEY=your_api_key");
|
|
75
|
-
process.exit(1);
|
|
76
|
-
}
|
|
77
|
-
const client = new Kernel();
|
|
78
|
-
console.log(chalk.green(`Compressing files...`));
|
|
79
|
-
const tmpZipFile = tmp.fileSync({ postfix: ".zip" });
|
|
80
|
-
try {
|
|
81
|
-
await zipDirectory(path2.join(sourceDir), tmpZipFile.name);
|
|
82
|
-
console.log(chalk.green(`Deploying app (version: ${versionArg})...`));
|
|
83
|
-
const response = await client.apps.deploy(
|
|
84
|
-
{
|
|
85
|
-
file: createReadStream(tmpZipFile.name),
|
|
86
|
-
version: versionArg,
|
|
87
|
-
force,
|
|
88
|
-
entrypointRelPath: path2.relative(sourceDir, resolvedEntrypoint)
|
|
89
|
-
},
|
|
90
|
-
{ maxRetries: 0 }
|
|
91
|
-
);
|
|
92
|
-
if (!response.success) {
|
|
93
|
-
console.error("Error deploying to Kernel:", response.message);
|
|
94
|
-
process.exit(1);
|
|
95
|
-
}
|
|
96
|
-
for (const app of response.apps) {
|
|
97
|
-
console.log(
|
|
98
|
-
chalk.green(
|
|
99
|
-
`App "${app.name}" successfully deployed to Kernel with action${app.actions.length > 1 ? "s" : ""}: ${app.actions.map((a) => a.name).join(", ")}`
|
|
100
|
-
)
|
|
101
|
-
);
|
|
102
|
-
console.log(
|
|
103
|
-
`You can invoke it with: kernel invoke${versionArg !== "latest" ? ` --version ${versionArg}` : ""} ${quoteIfNeeded(app.name)} ${quoteIfNeeded(app.actions[0].name)} '{ ... JSON payload ... }'`
|
|
104
|
-
);
|
|
105
|
-
}
|
|
106
|
-
} catch (error) {
|
|
107
|
-
console.error("Error deploying to Kernel:", error);
|
|
108
|
-
process.exit(1);
|
|
109
|
-
} finally {
|
|
110
|
-
tmpZipFile.removeCallback();
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
function quoteIfNeeded(str) {
|
|
114
|
-
if (str.includes(" ")) {
|
|
115
|
-
return `"${str}"`;
|
|
116
|
-
}
|
|
117
|
-
return str;
|
|
118
|
-
}
|
|
119
|
-
program.command("invoke").description("Invoke a deployed Kernel application").option("--version <version>", "Specify a version of the app to invoke").argument("<app_name>", "Name of the application to invoke").argument("<action_name>", "Name of the action to invoke").argument("<payload>", "JSON payload to send to the application").action(async (appName, actionName, payload, options) => {
|
|
120
|
-
let parsedPayload;
|
|
121
|
-
try {
|
|
122
|
-
parsedPayload = JSON.parse(payload);
|
|
123
|
-
} catch (error) {
|
|
124
|
-
console.error("Error: Invalid JSON payload");
|
|
125
|
-
process.exit(1);
|
|
126
|
-
}
|
|
127
|
-
if (!process.env["KERNEL_API_KEY"]) {
|
|
128
|
-
console.error("Error: KERNEL_API_KEY environment variable is not set");
|
|
129
|
-
console.error("Please set your Kernel API key using: export KERNEL_API_KEY=your_api_key");
|
|
130
|
-
process.exit(1);
|
|
131
|
-
}
|
|
132
|
-
const client = new Kernel();
|
|
133
|
-
console.log(`Invoking "${appName}" with action "${actionName}" and payload:`);
|
|
134
|
-
console.log(JSON.stringify(parsedPayload, null, 2));
|
|
135
|
-
try {
|
|
136
|
-
const response = await client.apps.invoke({
|
|
137
|
-
appName,
|
|
138
|
-
actionName,
|
|
139
|
-
payload,
|
|
140
|
-
...options.version && { version: options.version }
|
|
141
|
-
});
|
|
142
|
-
console.log("Result:");
|
|
143
|
-
console.log(JSON.stringify(JSON.parse(response.output || "{}"), null, 2));
|
|
144
|
-
} catch (error) {
|
|
145
|
-
console.error("Error invoking application:", error);
|
|
146
|
-
process.exit(1);
|
|
147
|
-
}
|
|
148
|
-
return;
|
|
149
|
-
});
|
|
150
|
-
program.parse();
|