boosted-cli 0.1.2
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/LICENSE +21 -0
- package/README.md +58 -0
- package/bin/boosted-cli.mjs +8 -0
- package/npm/launcher.mjs +136 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 monokaijs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Boosted
|
|
2
|
+
|
|
3
|
+
Boosted is a local-first, multi-user coding workspace with a task board, task-specific Codex planning conversations, and separate general Codex chats. It ships one Vite + React frontend for both the browser and a Tauri desktop shell.
|
|
4
|
+
|
|
5
|
+
## Development
|
|
6
|
+
|
|
7
|
+
Prerequisites: Node 22+, pnpm 10+, Rust 1.85+, Git, and the Codex CLI.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm install
|
|
11
|
+
pnpm dev
|
|
12
|
+
cargo run -p boosted-server
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The web client defaults to `http://127.0.0.1:4782`. Set `VITE_BOOSTED_API_URL` when the service runs elsewhere. The server stores local state under the platform application-data directory, or under `BOOSTED_DATA_DIR` when set.
|
|
16
|
+
|
|
17
|
+
The first browser visit creates the administrator. The admin then creates member accounts. All authenticated users share projects, tasks, history, terminals, and host-level execution access; only the first user can manage accounts and the shared Codex connection.
|
|
18
|
+
|
|
19
|
+
> Boosted currently starts Codex with full host access, matching the selected product policy. Only expose the server to trusted users, and put remote access behind your own authenticated TLS proxy or tunnel.
|
|
20
|
+
|
|
21
|
+
## Headless server
|
|
22
|
+
|
|
23
|
+
The quickest way to start the headless server is through npm (Node.js 18+):
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npx boosted-cli
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Or install it globally and run `boosted-cli`. The npm launcher downloads and caches the native CLI for Linux x64, macOS Intel/Apple Silicon, or Windows x64. The CLI has the web app embedded, so it does not need a desktop environment or WebKit. The server host still needs Git and the Codex CLI.
|
|
30
|
+
|
|
31
|
+
No data-directory argument is required. Boosted stores its database, uploads, and managed worktrees in the platform application-data directory by default (`BOOSTED_DATA_DIR` remains available when a custom location is needed).
|
|
32
|
+
|
|
33
|
+
Open `http://<server>:4782` in a browser. The first launch listens publicly on `0.0.0.0:4782`. Administrators can change the port, disable browser UI serving, or allowlist remote IPv4/IPv6 addresses under **Settings → Global → Web interface**; saved changes apply after restarting Boosted. Localhost remains available when an allowlist is active.
|
|
34
|
+
|
|
35
|
+
Run `npx boosted-cli --help` for launch overrides. `--bind`, `--port`, `--disable-web-ui`, repeated `--allow-ip`, and `--public` override saved settings for that launch. `BOOSTED_BIND`, `BOOSTED_PORT`, `BOOSTED_DISABLE_WEB_UI`, `BOOSTED_ALLOWED_IPS`, `BOOSTED_DATA_DIR`, and `BOOSTED_WEB_DIR` provide environment equivalents; an external web directory overrides the embedded frontend.
|
|
36
|
+
|
|
37
|
+
Public access gives authenticated users host-level execution access. Use the IP allowlist or a firewall for trusted networks, and put internet-facing access behind an authenticated TLS proxy or tunnel.
|
|
38
|
+
|
|
39
|
+
To build and run the self-contained CLI from source:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pnpm build
|
|
43
|
+
cargo run --release -p boosted-server --features embedded-web -- serve
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
GitHub Releases also provide the standalone native CLI executables used by the npm launcher.
|
|
47
|
+
|
|
48
|
+
## Releases
|
|
49
|
+
|
|
50
|
+
Run the **Release Boosted** workflow from the repository's Actions tab and choose a `patch`, `minor`, or `major` version increment. The workflow builds standalone CLIs for Linux x64, Windows x64, and macOS Intel/Apple Silicon, plus Linux (`.deb` and `.AppImage`), Windows (`.exe` and `.msi`), and universal macOS (`.dmg`) installers. Once every build succeeds, it commits the synchronized version bump, creates the version tag, publishes a GitHub Release with SHA-256 checksums, and publishes `boosted-cli` to npm through Trusted Publishing.
|
|
51
|
+
|
|
52
|
+
Trusted Publishing requires an existing npm package. Bootstrap `boosted-cli` with one authenticated manual publish, then configure its npm package settings with GitHub organization/user `monokaijs`, repository `boosted`, and workflow filename `release.yml`. No npm token is needed for later releases.
|
|
53
|
+
|
|
54
|
+
Desktop builds check `monokaijs/boosted` GitHub Releases shortly after startup and every six hours. When a newer signed release is available, Boosted downloads it, verifies its updater signature, installs it, and relaunches. A manual **Check now** action and update progress are available under **Settings → Application**. Browser and headless-server sessions do not run the desktop updater.
|
|
55
|
+
|
|
56
|
+
Updater packages are signed with the Tauri key whose public half is embedded in `desktop/src-tauri/tauri.conf.json`. The release workflow requires its private half in the `TAURI_SIGNING_PRIVATE_KEY` repository secret; `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` is optional. Keep an offline backup of the private key: losing or replacing it prevents installed copies from trusting future updates. For a local release build using an unencrypted key, set `TAURI_SIGNING_PRIVATE_KEY` to the key’s path, export `TAURI_SIGNING_PRIVATE_KEY_PASSWORD=""`, then run `pnpm desktop:build`.
|
|
57
|
+
|
|
58
|
+
The release workflow requires a Developer ID certificate and Apple notarization credentials for macOS. Follow [the macOS signing guide](docs/macos-signing.md) before the first release. Local macOS builds fall back to an ad-hoc signature; Windows installers remain unsigned.
|
package/npm/launcher.mjs
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { chmod, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import { homedir, tmpdir } from "node:os";
|
|
5
|
+
import { dirname, join } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const packagePath = fileURLToPath(new URL("../package.json", import.meta.url));
|
|
9
|
+
const packageJson = JSON.parse(await readFile(packagePath, "utf8"));
|
|
10
|
+
|
|
11
|
+
export const version = packageJson.version;
|
|
12
|
+
|
|
13
|
+
export function releaseAsset(platform = process.platform, arch = process.arch) {
|
|
14
|
+
const targets = {
|
|
15
|
+
"darwin-arm64": `boosted-${version}-darwin-aarch64`,
|
|
16
|
+
"darwin-x64": `boosted-${version}-darwin-x86_64`,
|
|
17
|
+
"linux-x64": `boosted-${version}-linux-x86_64`,
|
|
18
|
+
"win32-x64": `boosted-${version}-windows-x86_64.exe`,
|
|
19
|
+
};
|
|
20
|
+
const key = `${platform}-${arch}`;
|
|
21
|
+
const asset = targets[key];
|
|
22
|
+
|
|
23
|
+
if (!asset) {
|
|
24
|
+
throw new Error(
|
|
25
|
+
`unsupported platform ${platform}/${arch}; supported platforms are macOS arm64/x64, Linux x64, and Windows x64`,
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return asset;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function cacheRoot(platform = process.platform, env = process.env) {
|
|
33
|
+
if (env.BOOSTED_CLI_CACHE_DIR) return env.BOOSTED_CLI_CACHE_DIR;
|
|
34
|
+
if (platform === "darwin") return join(homedir(), "Library", "Caches", "boosted-cli");
|
|
35
|
+
if (platform === "win32") {
|
|
36
|
+
return join(env.LOCALAPPDATA || tmpdir(), "boosted-cli", "Cache");
|
|
37
|
+
}
|
|
38
|
+
return join(env.XDG_CACHE_HOME || join(homedir(), ".cache"), "boosted-cli");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function releaseBaseUrl(env = process.env) {
|
|
42
|
+
return (
|
|
43
|
+
env.BOOSTED_CLI_DOWNLOAD_BASE_URL ||
|
|
44
|
+
`https://github.com/monokaijs/boosted/releases/download/v${version}`
|
|
45
|
+
).replace(/\/$/, "");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function download(url) {
|
|
49
|
+
const response = await fetch(url, {
|
|
50
|
+
headers: {
|
|
51
|
+
Accept: "application/octet-stream",
|
|
52
|
+
"User-Agent": `boosted-cli/${version}`,
|
|
53
|
+
},
|
|
54
|
+
redirect: "follow",
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
throw new Error(`download failed (${response.status} ${response.statusText}): ${url}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return Buffer.from(await response.arrayBuffer());
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function expectedChecksum(checksums, asset) {
|
|
65
|
+
for (const line of checksums.split(/\r?\n/)) {
|
|
66
|
+
const match = line.match(/^([a-fA-F0-9]{64})\s+\*?(.+)$/);
|
|
67
|
+
if (match?.[2] === asset) return match[1].toLowerCase();
|
|
68
|
+
}
|
|
69
|
+
throw new Error(`SHA256SUMS.txt does not contain ${asset}`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function installBinary({
|
|
73
|
+
platform = process.platform,
|
|
74
|
+
arch = process.arch,
|
|
75
|
+
env = process.env,
|
|
76
|
+
} = {}) {
|
|
77
|
+
const asset = releaseAsset(platform, arch);
|
|
78
|
+
const binary = join(
|
|
79
|
+
cacheRoot(platform, env),
|
|
80
|
+
version,
|
|
81
|
+
platform === "win32" ? "boosted-cli.exe" : "boosted-cli",
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
await chmod(binary, 0o755);
|
|
86
|
+
return binary;
|
|
87
|
+
} catch (error) {
|
|
88
|
+
if (error.code !== "ENOENT") throw error;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const baseUrl = releaseBaseUrl(env);
|
|
92
|
+
console.error(`boosted-cli: downloading Boosted ${version} for ${platform}/${arch}...`);
|
|
93
|
+
const [contents, checksumContents] = await Promise.all([
|
|
94
|
+
download(`${baseUrl}/${asset}`),
|
|
95
|
+
download(`${baseUrl}/SHA256SUMS.txt`).then((value) => value.toString("utf8")),
|
|
96
|
+
]);
|
|
97
|
+
const actual = createHash("sha256").update(contents).digest("hex");
|
|
98
|
+
const expected = expectedChecksum(checksumContents, asset);
|
|
99
|
+
|
|
100
|
+
if (actual !== expected) {
|
|
101
|
+
throw new Error(`checksum verification failed for ${asset}`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
await mkdir(dirname(binary), { recursive: true });
|
|
105
|
+
const temporary = `${binary}.${process.pid}.tmp`;
|
|
106
|
+
try {
|
|
107
|
+
await writeFile(temporary, contents, { mode: 0o755 });
|
|
108
|
+
await chmod(temporary, 0o755);
|
|
109
|
+
await rename(temporary, binary);
|
|
110
|
+
} finally {
|
|
111
|
+
await rm(temporary, { force: true });
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return binary;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export async function run({ argv = process.argv.slice(2), env = process.env } = {}) {
|
|
118
|
+
const binary = await installBinary({ env });
|
|
119
|
+
const child = spawn(binary, argv, {
|
|
120
|
+
env,
|
|
121
|
+
stdio: "inherit",
|
|
122
|
+
windowsHide: false,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
await new Promise((resolve, reject) => {
|
|
126
|
+
child.once("error", reject);
|
|
127
|
+
child.once("exit", (code, signal) => {
|
|
128
|
+
if (signal) {
|
|
129
|
+
process.kill(process.pid, signal);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
process.exitCode = code ?? 1;
|
|
133
|
+
resolve();
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "boosted-cli",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Run the Boosted local-first coding workspace from the command line",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/monokaijs/boosted.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/monokaijs/boosted#readme",
|
|
11
|
+
"bugs": "https://github.com/monokaijs/boosted/issues",
|
|
12
|
+
"type": "module",
|
|
13
|
+
"bin": {
|
|
14
|
+
"boosted-cli": "bin/boosted-cli.mjs"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"bin/boosted-cli.mjs",
|
|
18
|
+
"npm/launcher.mjs"
|
|
19
|
+
],
|
|
20
|
+
"engines": {
|
|
21
|
+
"node": ">=18"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"packageManager": "pnpm@10.34.5",
|
|
27
|
+
"scripts": {
|
|
28
|
+
"dev": "pnpm --filter @boosted/web dev",
|
|
29
|
+
"build": "pnpm --filter @boosted/web build",
|
|
30
|
+
"test": "pnpm --filter @boosted/web test",
|
|
31
|
+
"typecheck": "pnpm --filter @boosted/web typecheck",
|
|
32
|
+
"desktop": "pnpm --filter @boosted/desktop tauri dev",
|
|
33
|
+
"desktop:build": "pnpm --filter @boosted/desktop tauri build",
|
|
34
|
+
"server": "cargo run -p boosted-server",
|
|
35
|
+
"test:cli": "node --test test/npm-cli.test.mjs"
|
|
36
|
+
}
|
|
37
|
+
}
|