settlemesh 0.1.34
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 +178 -0
- package/bin/settle.js +80 -0
- package/package.json +58 -0
- package/scripts/clean-staged-binaries.js +27 -0
- package/scripts/install.js +189 -0
- package/scripts/stage-binaries.js +49 -0
- package/vendor/settle-darwin-arm64 +0 -0
- package/vendor/settle-darwin-arm64.sha256 +1 -0
- package/vendor/settle-darwin-x64 +0 -0
- package/vendor/settle-darwin-x64.sha256 +1 -0
- package/vendor/settle-linux-arm64 +0 -0
- package/vendor/settle-linux-arm64.sha256 +1 -0
- package/vendor/settle-linux-x64 +0 -0
- package/vendor/settle-linux-x64.sha256 +1 -0
- package/vendor/settle-win32-arm64.exe +0 -0
- package/vendor/settle-win32-arm64.exe.sha256 +1 -0
- package/vendor/settle-win32-x64.exe +0 -0
- package/vendor/settle-win32-x64.exe.sha256 +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# SettleMesh CLI
|
|
2
|
+
|
|
3
|
+
SettleMesh is a CLI-first tool platform for developers, scripts, and AI agents. The npm package and primary command are both `settlemesh`.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
For AI agents, clean terminals, and project-specific deploys, prefer a project-local latest install. This avoids stale global binaries:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install settlemesh@latest --prefer-online
|
|
11
|
+
./node_modules/.bin/settlemesh doctor --require-latest
|
|
12
|
+
./node_modules/.bin/settlemesh recipes
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Global install is also supported for interactive use:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g settlemesh
|
|
19
|
+
settlemesh doctor
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The package exposes compatibility aliases:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
settlemesh --version
|
|
26
|
+
settle --version
|
|
27
|
+
settlekit --version
|
|
28
|
+
kit --version
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Project-local install also works:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install settlemesh@latest --prefer-online
|
|
35
|
+
./node_modules/.bin/settlemesh help
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Login
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
settlemesh login
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
For CI, scripts, and hosted agents:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
export SETTLE_API_KEY="sk_..."
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Use `SETTLE_BASE_URL=http://localhost:8080` for local development, and `SETTLE_REQUEST_TIMEOUT=90s` for slow provider calls.
|
|
51
|
+
|
|
52
|
+
## Use Tools
|
|
53
|
+
|
|
54
|
+
Always use discovery before calling tools:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
settlemesh help --json
|
|
58
|
+
settlemesh recipes
|
|
59
|
+
settlemesh tool list --json
|
|
60
|
+
settlemesh tool show web.search --json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
For a no-context agent, start with the built-in golden paths:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install settlemesh@latest --prefer-online
|
|
67
|
+
./node_modules/.bin/settlemesh doctor --require-latest
|
|
68
|
+
./node_modules/.bin/settlemesh recipes
|
|
69
|
+
./node_modules/.bin/settlemesh search "build app with login database api command"
|
|
70
|
+
./node_modules/.bin/settlemesh services show app-project-backends --json
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`settlemesh recipes` covers the shortest flows for full-stack app deploys, App API/CLI commands, browser bridge URLs, hosted agents, and local worker offers.
|
|
74
|
+
|
|
75
|
+
Call a tool with JSON input:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
settlemesh tool call web.search \
|
|
79
|
+
--input '{"q":"SettleMesh","count":5}' \
|
|
80
|
+
--json
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Generate an image task:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
settlemesh tool call image.gpt-image-2 \
|
|
87
|
+
--input '{"prompt":"A clean product photo of a ceramic tea cup","size":"1:1"}' \
|
|
88
|
+
--json
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Poll async media:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
settlemesh tool events image_... --json
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Upload a local image for image-to-image:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
settlemesh files upload ./input.png --json
|
|
101
|
+
settlemesh tool call image.gpt-image-2 \
|
|
102
|
+
--input '{"prompt":"Turn this into a clean product photo","size":"1:1"}' \
|
|
103
|
+
--image-file ./input.png \
|
|
104
|
+
--json
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Credits
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
settlemesh credits balance --json
|
|
111
|
+
settlemesh credits ledger --json
|
|
112
|
+
settlemesh credits topup --credits 100 --json
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Hosted Agents
|
|
116
|
+
|
|
117
|
+
Create from a built-in template and make it callable by other accounts:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
settlemesh agents templates --json
|
|
121
|
+
settlemesh agents create \
|
|
122
|
+
--name research-helper \
|
|
123
|
+
--template hermes \
|
|
124
|
+
--public \
|
|
125
|
+
--max-budget 50 \
|
|
126
|
+
--allowed-capabilities web.search,web.scrape,llm.chat \
|
|
127
|
+
--json
|
|
128
|
+
settlemesh agents invoke agent_... --input '{"prompt":"Find three primary sources."}' --json
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
You can share the returned `agent_id`; other users can call public agents directly by id with `settlemesh agents invoke` or `settlemesh tool call agent.invoke`.
|
|
132
|
+
|
|
133
|
+
## Managed Backends
|
|
134
|
+
|
|
135
|
+
Create a SettleMesh project with database + app auth:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
settlemesh projects create --name demo --db sqlite --auth email_password,magic_link
|
|
139
|
+
settlemesh db query proj_... --sql "select 1"
|
|
140
|
+
settlemesh db migrate proj_... --file schema.sql
|
|
141
|
+
settlemesh db connection proj_...
|
|
142
|
+
settlemesh auth users proj_...
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`settlemesh db connection` is redacted by default. Add `--reveal` only in a trusted terminal. Database SQL endpoints accept a developer key or the one-time project server key returned by `projects create`; browser/public project keys are only for app auth.
|
|
146
|
+
|
|
147
|
+
## Full-stack Apps, App APIs, and CLI Commands
|
|
148
|
+
|
|
149
|
+
Deploy a local app project with SettleMesh auth, database, runtime API keys, and optional payment bindings:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
./node_modules/.bin/settlemesh deploy ./my-next-app --name my-next-app --full-stack --wait --json
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Expose selected routes from that app as APIs and CLI commands:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
settlemesh apps api publish app_... --file app-api.json --json
|
|
159
|
+
settlemesh apps api call app_... summarize --input '{"topic":"shipping"}' --json
|
|
160
|
+
settlemesh apps commands publish app_... --file app-commands.json --json
|
|
161
|
+
settlemesh run app:app_....summarize --input '{"topic":"shipping"}' --open --json
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
When a command has a web binding, `--open` can return a short-lived URL that opens the app in the browser using the caller's Settle login, without a second manual login.
|
|
165
|
+
|
|
166
|
+
## Local Worker Offers
|
|
167
|
+
|
|
168
|
+
Share a local OpenAI-compatible endpoint as a callable service:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
settlemesh search "lend local compute worker offer"
|
|
172
|
+
settlemesh worker start --name local-model --public --model local/model --endpoint http://localhost:11434/v1/chat/completions --credits-per-second 0.05
|
|
173
|
+
settlemesh worker-offers list --json
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Public Tool Surface
|
|
177
|
+
|
|
178
|
+
The public CLI surface includes discovery, tools, full-stack app deployment, App APIs/commands, hosted agents, local worker offers, credits, files, and managed project/database/auth operations. Provider-specific operations may still be gated on a given deployment. Inspect each tool's `availability`, `policy`, and `input_schema` before side-effecting or costly calls.
|
package/bin/settle.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
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 pkg = require(path.join(__dirname, "..", "package.json"));
|
|
8
|
+
const binaryOverride = process.env.SETTLEKIT_CLI_BINARY;
|
|
9
|
+
const binaryName = process.platform === "win32" ? "settle.exe" : "settle";
|
|
10
|
+
const binaryPath = binaryOverride || path.join(__dirname, "..", "vendor", binaryName);
|
|
11
|
+
const commandName = path.basename(process.argv[1] || "settlemesh").replace(/\.cmd$/i, "");
|
|
12
|
+
|
|
13
|
+
if (!fs.existsSync(binaryPath)) {
|
|
14
|
+
console.error(`${commandName}: CLI binary was not found.`);
|
|
15
|
+
console.error("Run `npm rebuild -g settlemesh` or reinstall with `npm install -g settlemesh`.");
|
|
16
|
+
if (process.env.SETTLEKIT_CLI_RELEASE_BASE || process.env.SETTLEKIT_CLI_RELEASE_TAG) {
|
|
17
|
+
console.error("Check SETTLEKIT_CLI_RELEASE_BASE and SETTLEKIT_CLI_RELEASE_TAG.");
|
|
18
|
+
}
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
maybeWarnForStalePackage();
|
|
23
|
+
|
|
24
|
+
const env = {
|
|
25
|
+
...process.env,
|
|
26
|
+
SETTLEKIT_NPM_PACKAGE_VERSION: process.env.SETTLEKIT_NPM_PACKAGE_VERSION || pkg.version,
|
|
27
|
+
SETTLEKIT_NPM_PACKAGE_ROOT: process.env.SETTLEKIT_NPM_PACKAGE_ROOT || path.join(__dirname, ".."),
|
|
28
|
+
SETTLE_CLI_NAME: process.env.SETTLE_CLI_NAME || commandName,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const result = spawnSync(binaryPath, process.argv.slice(2), {
|
|
32
|
+
stdio: "inherit",
|
|
33
|
+
env,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (result.error) {
|
|
37
|
+
console.error(`${commandName}: ${result.error.message}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
process.exit(result.status ?? 0);
|
|
42
|
+
|
|
43
|
+
function maybeWarnForStalePackage() {
|
|
44
|
+
if (process.env.SETTLEKIT_SKIP_VERSION_CHECK === "1") {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const command = process.argv[2] || "";
|
|
48
|
+
const shouldCheck = new Set(["deploy", "recipes", "quickstart", "doctor", "version", "--version", "-v"]);
|
|
49
|
+
if (!shouldCheck.has(command)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
53
|
+
const result = spawnSync(npm, ["view", pkg.name || "settlemesh", "version", "--silent"], {
|
|
54
|
+
encoding: "utf8",
|
|
55
|
+
timeout: 2500,
|
|
56
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
57
|
+
});
|
|
58
|
+
if (result.error || result.status !== 0) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const latest = String(result.stdout || "").trim().split(/\s+/)[0];
|
|
62
|
+
if (!latest || compareVersions(pkg.version, latest) >= 0) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
console.error(`${commandName}: warning: npm package ${pkg.name}@${pkg.version} is older than latest ${latest}.`);
|
|
66
|
+
console.error(`${commandName}: for agent/bootstrap flows, run \`npm install settlemesh@latest --prefer-online\` and use \`./node_modules/.bin/settlemesh\`.`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function compareVersions(left, right) {
|
|
70
|
+
const a = String(left || "").split(".").map((part) => parseInt(part, 10) || 0);
|
|
71
|
+
const b = String(right || "").split(".").map((part) => parseInt(part, 10) || 0);
|
|
72
|
+
const n = Math.max(a.length, b.length);
|
|
73
|
+
for (let i = 0; i < n; i++) {
|
|
74
|
+
const diff = (a[i] || 0) - (b[i] || 0);
|
|
75
|
+
if (diff !== 0) {
|
|
76
|
+
return diff;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "settlemesh",
|
|
3
|
+
"version": "0.1.34",
|
|
4
|
+
"description": "SettleMesh CLI for services, models, apps, agents, workers, and credits",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"homepage": "https://settlemesh.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
|
+
"settlemesh",
|
|
17
|
+
"settlekit",
|
|
18
|
+
"cli",
|
|
19
|
+
"agent",
|
|
20
|
+
"ai",
|
|
21
|
+
"tools"
|
|
22
|
+
],
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"bin": {
|
|
27
|
+
"kit": "bin/settle.js",
|
|
28
|
+
"settle": "bin/settle.js",
|
|
29
|
+
"settlemesh": "bin/settle.js",
|
|
30
|
+
"settlekit": "bin/settle.js"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"prepack": "node scripts/stage-binaries.js",
|
|
34
|
+
"postpack": "node scripts/clean-staged-binaries.js",
|
|
35
|
+
"postinstall": "node scripts/install.js"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"bin/",
|
|
39
|
+
"scripts/",
|
|
40
|
+
"vendor/",
|
|
41
|
+
"README.md"
|
|
42
|
+
],
|
|
43
|
+
"config": {
|
|
44
|
+
"release_base": "https://github.com/CalLeeLQY/SettleKit/releases/download"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=18"
|
|
48
|
+
},
|
|
49
|
+
"os": [
|
|
50
|
+
"darwin",
|
|
51
|
+
"linux",
|
|
52
|
+
"win32"
|
|
53
|
+
],
|
|
54
|
+
"cpu": [
|
|
55
|
+
"x64",
|
|
56
|
+
"arm64"
|
|
57
|
+
]
|
|
58
|
+
}
|
|
@@ -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("settlemesh: 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(`settlemesh: installed bundled ${assetName}`);
|
|
45
|
+
process.exit(0);
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.error(`settlemesh: bundled ${assetName} failed verification`);
|
|
48
|
+
console.error(`settlemesh: ${err.message}`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
download(url, tmp, 0, (err) => {
|
|
54
|
+
if (err) {
|
|
55
|
+
console.error(`settlemesh: failed to download ${assetName}`);
|
|
56
|
+
console.error(`settlemesh: ${err.message}`);
|
|
57
|
+
console.error(`settlemesh: attempted ${url}`);
|
|
58
|
+
console.error("settlemesh: 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(`settlemesh: failed to download checksum for ${assetName}`);
|
|
66
|
+
console.error(`settlemesh: ${checksumErr.message}`);
|
|
67
|
+
console.error(`settlemesh: attempted ${checksumURL}`);
|
|
68
|
+
console.error("settlemesh: 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(`settlemesh: checksum mismatch for ${assetName}`);
|
|
78
|
+
console.error(`settlemesh: expected ${expected || "(missing checksum)"}`);
|
|
79
|
+
console.error(`settlemesh: 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(`settlemesh: 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("settlemesh: skipping bundled binary staging because SETTLEKIT_SKIP_VENDOR_STAGE=1");
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (!fs.existsSync(distDir)) {
|
|
25
|
+
console.warn("settlemesh: 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(`settlemesh: 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
|
+
1033476dad68da250fc04a53b6326d6ff4a8fa7a784c037087e12b1e7fd17736
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
c2485074a305314022001f47539836c0c9683fea74752ef945dec74a8553bbfe
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
6983bdd99ed0b9dd12cecff5e514a3b56d83489f5ce5635944254063680f4311
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1284edd5a9d437970f0b60c7d05c3a76e8091061668d7daea7dc7ebb1da35dc5
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
4d31f80b34a44dcff12f42b0b153c740c0d41082f5b8bc54fa083837f9e17e86
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
de63eaaf0c9edde24ab4607ab167a7733ee43e6f9940cb1fbbfdb516ddd2aede
|