settlekit 0.1.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 ADDED
@@ -0,0 +1,43 @@
1
+ # SettleKit CLI
2
+
3
+ Install globally:
4
+
5
+ ```bash
6
+ npm install -g settlekit
7
+ settle login
8
+ ```
9
+
10
+ Or install in a project:
11
+
12
+ ```bash
13
+ npm install settlekit
14
+ npx settlekit login
15
+ ```
16
+
17
+ One-off usage also works without adding it to `package.json`:
18
+
19
+ ```bash
20
+ npx settlekit login
21
+ ```
22
+
23
+ `settle login` opens the SettleKit website, lets you authorize the CLI, and stores a local CLI config. After that:
24
+
25
+ ```bash
26
+ settle tool list
27
+ settle tool call web.search --input '{"q":"SettleKit","count":5}'
28
+ settle credits balance
29
+ ```
30
+
31
+ For staging or self-hosted deployments:
32
+
33
+ ```bash
34
+ SETTLE_PLATFORM_URL=https://app.example.com SETTLE_BASE_URL=https://api.example.com settle login
35
+ ```
36
+
37
+ The npm package bundles platform binaries and verifies the matching `.sha256` file during `postinstall`. If a bundled binary is unavailable, installation falls back to downloading the binary and checksum from GitHub Releases. Private release channels can override:
38
+
39
+ ```bash
40
+ SETTLEKIT_CLI_RELEASE_BASE=https://github.com/your-org/your-repo/releases/download \
41
+ SETTLEKIT_CLI_RELEASE_TAG=v0.1.0 \
42
+ npm install -g settlekit
43
+ ```
package/bin/settle.js ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawnSync } = require("node:child_process");
4
+ const fs = require("node:fs");
5
+ const path = require("node:path");
6
+
7
+ const binaryOverride = process.env.SETTLEKIT_CLI_BINARY;
8
+ const binaryName = process.platform === "win32" ? "settle.exe" : "settle";
9
+ const binaryPath = binaryOverride || path.join(__dirname, "..", "vendor", binaryName);
10
+
11
+ if (!fs.existsSync(binaryPath)) {
12
+ console.error("settle: CLI binary was not found.");
13
+ console.error("Run `npm rebuild -g settlekit` or reinstall with `npm install -g settlekit`.");
14
+ if (process.env.SETTLEKIT_CLI_RELEASE_BASE || process.env.SETTLEKIT_CLI_RELEASE_TAG) {
15
+ console.error("Check SETTLEKIT_CLI_RELEASE_BASE and SETTLEKIT_CLI_RELEASE_TAG.");
16
+ }
17
+ process.exit(1);
18
+ }
19
+
20
+ const result = spawnSync(binaryPath, process.argv.slice(2), {
21
+ stdio: "inherit",
22
+ env: process.env,
23
+ });
24
+
25
+ if (result.error) {
26
+ console.error(`settle: ${result.error.message}`);
27
+ process.exit(1);
28
+ }
29
+
30
+ process.exit(result.status ?? 0);
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "settlekit",
3
+ "version": "0.1.0",
4
+ "description": "SettleKit CLI",
5
+ "license": "UNLICENSED",
6
+ "homepage": "https://settlekit.io",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/CalLeeLQY/SettleKit.git",
10
+ "directory": "npm/settlekit"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/CalLeeLQY/SettleKit/issues"
14
+ },
15
+ "keywords": [
16
+ "settlekit",
17
+ "cli",
18
+ "agent",
19
+ "ai",
20
+ "tools"
21
+ ],
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "bin": {
26
+ "kit": "bin/settle.js",
27
+ "settle": "bin/settle.js",
28
+ "settlekit": "bin/settle.js"
29
+ },
30
+ "scripts": {
31
+ "prepack": "node scripts/stage-binaries.js",
32
+ "postpack": "node scripts/clean-staged-binaries.js",
33
+ "postinstall": "node scripts/install.js"
34
+ },
35
+ "files": [
36
+ "bin/",
37
+ "scripts/",
38
+ "vendor/",
39
+ "README.md"
40
+ ],
41
+ "config": {
42
+ "release_base": "https://github.com/CalLeeLQY/SettleKit/releases/download"
43
+ },
44
+ "engines": {
45
+ "node": ">=18"
46
+ },
47
+ "os": [
48
+ "darwin",
49
+ "linux",
50
+ "win32"
51
+ ],
52
+ "cpu": [
53
+ "x64",
54
+ "arm64"
55
+ ]
56
+ }
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("node:fs");
4
+ const path = require("node:path");
5
+
6
+ const vendorDir = path.resolve(__dirname, "..", "vendor");
7
+ const assets = [
8
+ "settle-darwin-arm64",
9
+ "settle-darwin-x64",
10
+ "settle-linux-arm64",
11
+ "settle-linux-x64",
12
+ "settle-win32-arm64.exe",
13
+ "settle-win32-x64.exe",
14
+ ];
15
+
16
+ for (const asset of assets) {
17
+ fs.rmSync(path.join(vendorDir, asset), { force: true });
18
+ fs.rmSync(path.join(vendorDir, `${asset}.sha256`), { force: true });
19
+ }
20
+
21
+ try {
22
+ if (fs.existsSync(vendorDir) && fs.readdirSync(vendorDir).length === 0) {
23
+ fs.rmdirSync(vendorDir);
24
+ }
25
+ } catch {
26
+ // Best-effort cleanup only.
27
+ }
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("node:fs");
4
+ const crypto = require("node:crypto");
5
+ const http = require("node:http");
6
+ const https = require("node:https");
7
+ const os = require("node:os");
8
+ const path = require("node:path");
9
+ const { fileURLToPath } = require("node:url");
10
+
11
+ const root = path.resolve(__dirname, "..");
12
+ const pkg = require(path.join(root, "package.json"));
13
+
14
+ if (process.env.SETTLEKIT_SKIP_BINARY_INSTALL === "1") {
15
+ console.log("settle: skipping binary install because SETTLEKIT_SKIP_BINARY_INSTALL=1");
16
+ process.exit(0);
17
+ }
18
+
19
+ const platform = platformName(process.platform);
20
+ const arch = archName(process.arch);
21
+ const binaryName = process.platform === "win32" ? "settle.exe" : "settle";
22
+ const assetName = process.platform === "win32" ? `settle-${platform}-${arch}.exe` : `settle-${platform}-${arch}`;
23
+ const vendorDir = path.join(root, "vendor");
24
+ const target = path.join(vendorDir, binaryName);
25
+ const bundledAsset = path.join(vendorDir, assetName);
26
+ const bundledChecksum = `${bundledAsset}.sha256`;
27
+ const tmp = path.join(os.tmpdir(), `settle-${process.pid}-${Date.now()}`);
28
+ const checksumTmp = `${tmp}.sha256`;
29
+ const releaseBase = stripTrailingSlash(
30
+ process.env.SETTLEKIT_CLI_RELEASE_BASE ||
31
+ process.env.npm_package_config_release_base ||
32
+ pkg.config?.release_base ||
33
+ "https://github.com/CalLeeLQY/SettleKit/releases/download",
34
+ );
35
+ const releaseTag = process.env.SETTLEKIT_CLI_RELEASE_TAG || `v${pkg.version}`;
36
+ const url = `${releaseBase}/${releaseTag}/${assetName}`;
37
+ const checksumURL = `${url}.sha256`;
38
+
39
+ fs.mkdirSync(vendorDir, { recursive: true });
40
+
41
+ if (fs.existsSync(bundledAsset)) {
42
+ try {
43
+ installFromLocalAsset(bundledAsset, bundledChecksum, target);
44
+ console.log(`settle: installed bundled ${assetName}`);
45
+ process.exit(0);
46
+ } catch (err) {
47
+ console.error(`settle: bundled ${assetName} failed verification`);
48
+ console.error(`settle: ${err.message}`);
49
+ process.exit(1);
50
+ }
51
+ }
52
+
53
+ download(url, tmp, 0, (err) => {
54
+ if (err) {
55
+ console.error(`settle: failed to download ${assetName}`);
56
+ console.error(`settle: ${err.message}`);
57
+ console.error(`settle: attempted ${url}`);
58
+ console.error("settle: set SETTLEKIT_CLI_RELEASE_BASE or SETTLEKIT_CLI_RELEASE_TAG for private/staging releases.");
59
+ process.exit(1);
60
+ }
61
+ download(checksumURL, checksumTmp, 0, (checksumErr) => {
62
+ if (checksumErr && process.env.SETTLEKIT_SKIP_CHECKSUM !== "1") {
63
+ fs.rmSync(tmp, { force: true });
64
+ fs.rmSync(checksumTmp, { force: true });
65
+ console.error(`settle: failed to download checksum for ${assetName}`);
66
+ console.error(`settle: ${checksumErr.message}`);
67
+ console.error(`settle: attempted ${checksumURL}`);
68
+ console.error("settle: set SETTLEKIT_SKIP_CHECKSUM=1 only for trusted private test releases.");
69
+ process.exit(1);
70
+ }
71
+ if (!checksumErr && process.env.SETTLEKIT_SKIP_CHECKSUM !== "1") {
72
+ const expected = parseChecksum(fs.readFileSync(checksumTmp, "utf8"));
73
+ const actual = sha256File(tmp);
74
+ if (!expected || expected !== actual) {
75
+ fs.rmSync(tmp, { force: true });
76
+ fs.rmSync(checksumTmp, { force: true });
77
+ console.error(`settle: checksum mismatch for ${assetName}`);
78
+ console.error(`settle: expected ${expected || "(missing checksum)"}`);
79
+ console.error(`settle: actual ${actual}`);
80
+ process.exit(1);
81
+ }
82
+ }
83
+ fs.copyFileSync(tmp, target);
84
+ fs.rmSync(tmp, { force: true });
85
+ fs.rmSync(checksumTmp, { force: true });
86
+ if (process.platform !== "win32") {
87
+ fs.chmodSync(target, 0o755);
88
+ }
89
+ console.log(`settle: installed ${assetName}`);
90
+ });
91
+ });
92
+
93
+ function installFromLocalAsset(source, checksumPath, destination) {
94
+ if (process.env.SETTLEKIT_SKIP_CHECKSUM !== "1") {
95
+ if (!fs.existsSync(checksumPath)) {
96
+ throw new Error(`missing checksum ${path.basename(checksumPath)}`);
97
+ }
98
+ const expected = parseChecksum(fs.readFileSync(checksumPath, "utf8"));
99
+ const actual = sha256File(source);
100
+ if (!expected || expected !== actual) {
101
+ throw new Error(`checksum mismatch: expected ${expected || "(missing checksum)"}, actual ${actual}`);
102
+ }
103
+ }
104
+ fs.copyFileSync(source, destination);
105
+ if (process.platform !== "win32") {
106
+ fs.chmodSync(destination, 0o755);
107
+ }
108
+ }
109
+
110
+ function parseChecksum(value) {
111
+ const match = String(value || "").match(/[a-fA-F0-9]{64}/);
112
+ return match ? match[0].toLowerCase() : "";
113
+ }
114
+
115
+ function sha256File(filePath) {
116
+ const hash = crypto.createHash("sha256");
117
+ const data = fs.readFileSync(filePath);
118
+ hash.update(data);
119
+ return hash.digest("hex");
120
+ }
121
+
122
+ function platformName(value) {
123
+ switch (value) {
124
+ case "darwin":
125
+ case "linux":
126
+ case "win32":
127
+ return value;
128
+ default:
129
+ throw new Error(`unsupported platform ${value}`);
130
+ }
131
+ }
132
+
133
+ function archName(value) {
134
+ switch (value) {
135
+ case "x64":
136
+ case "arm64":
137
+ return value;
138
+ default:
139
+ throw new Error(`unsupported architecture ${value}`);
140
+ }
141
+ }
142
+
143
+ function stripTrailingSlash(value) {
144
+ return String(value || "").replace(/\/+$/, "");
145
+ }
146
+
147
+ function download(rawURL, destination, redirectCount, done) {
148
+ if (redirectCount > 5) {
149
+ done(new Error("too many redirects"));
150
+ return;
151
+ }
152
+ let parsed;
153
+ try {
154
+ parsed = new URL(rawURL);
155
+ } catch (err) {
156
+ done(err);
157
+ return;
158
+ }
159
+ if (parsed.protocol === "file:") {
160
+ try {
161
+ fs.copyFileSync(fileURLToPath(parsed), destination);
162
+ done();
163
+ } catch (err) {
164
+ done(err);
165
+ }
166
+ return;
167
+ }
168
+ const client = parsed.protocol === "http:" ? http : https;
169
+ const request = client.get(rawURL, (response) => {
170
+ const status = response.statusCode || 0;
171
+ const location = response.headers.location;
172
+ if (status >= 300 && status < 400 && location) {
173
+ response.resume();
174
+ download(new URL(location, rawURL).toString(), destination, redirectCount + 1, done);
175
+ return;
176
+ }
177
+ if (status !== 200) {
178
+ response.resume();
179
+ done(new Error(`HTTP ${status}`));
180
+ return;
181
+ }
182
+ const file = fs.createWriteStream(destination, { mode: 0o755 });
183
+ response.pipe(file);
184
+ file.on("finish", () => file.close(done));
185
+ file.on("error", done);
186
+ });
187
+ request.on("error", done);
188
+ request.setTimeout(120000, () => request.destroy(new Error("download timed out")));
189
+ }
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("node:fs");
4
+ const path = require("node:path");
5
+
6
+ const root = path.resolve(__dirname, "..", "..", "..");
7
+ const pkgRoot = path.resolve(__dirname, "..");
8
+ const distDir = path.join(root, "dist");
9
+ const vendorDir = path.join(pkgRoot, "vendor");
10
+ const assets = [
11
+ "settle-darwin-arm64",
12
+ "settle-darwin-x64",
13
+ "settle-linux-arm64",
14
+ "settle-linux-x64",
15
+ "settle-win32-arm64.exe",
16
+ "settle-win32-x64.exe",
17
+ ];
18
+
19
+ if (process.env.SETTLEKIT_SKIP_VENDOR_STAGE === "1") {
20
+ console.log("settle: skipping bundled binary staging because SETTLEKIT_SKIP_VENDOR_STAGE=1");
21
+ process.exit(0);
22
+ }
23
+
24
+ if (!fs.existsSync(distDir)) {
25
+ console.warn("settle: dist/ was not found; npm package will rely on release download fallback");
26
+ process.exit(0);
27
+ }
28
+
29
+ fs.mkdirSync(vendorDir, { recursive: true });
30
+ cleanupVendor();
31
+
32
+ for (const asset of assets) {
33
+ const source = path.join(distDir, asset);
34
+ const checksum = `${source}.sha256`;
35
+ if (!fs.existsSync(source) || !fs.existsSync(checksum)) {
36
+ throw new Error(`missing release asset or checksum for ${asset}; run make cli-release first`);
37
+ }
38
+ fs.copyFileSync(source, path.join(vendorDir, asset));
39
+ fs.copyFileSync(checksum, path.join(vendorDir, `${asset}.sha256`));
40
+ }
41
+
42
+ console.log(`settle: staged ${assets.length} bundled CLI binaries`);
43
+
44
+ function cleanupVendor() {
45
+ for (const asset of assets) {
46
+ fs.rmSync(path.join(vendorDir, asset), { force: true });
47
+ fs.rmSync(path.join(vendorDir, `${asset}.sha256`), { force: true });
48
+ }
49
+ }
Binary file
@@ -0,0 +1 @@
1
+ 31e93db71c2ad07319f827a675e65caaa5193a7a94430016bc1f8ca2f08a1345
Binary file
@@ -0,0 +1 @@
1
+ 1532c4535ce91c58517731da64431b844651f57158a54de7a78f4d603f5fd127
Binary file
@@ -0,0 +1 @@
1
+ c2c5e1496f78fdd2a7ec0ecbea1b352dd73be617aacb3691f6345690cb6db443
Binary file
@@ -0,0 +1 @@
1
+ fdeb89c62e701963b8b87f8413bcc3f4b6efb885d5872e47719079d1ea892b97
Binary file
@@ -0,0 +1 @@
1
+ 6fc51dd2dadf7543dee4786d147a9ef2a34a6ff03f84be177ebd1776715e25de
Binary file
@@ -0,0 +1 @@
1
+ 98f51ba91d2ec9a7937ed7426c079145fddf730ff7bb912793b535171d657889