@napisani/scute 0.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Nick
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,327 @@
1
+ # scute - AI Shell Assistant
2
+
3
+ ## Purpose / Goal
4
+
5
+ `scute` is a CLI companion for your shell. It adds fast, context-aware command generation, suggestion, and explanation directly in your terminal workflow. The goal is to reduce friction when crafting commands by:
6
+
7
+ - Generating commands from natural language prompts
8
+ - Suggesting completions for partially typed commands
9
+ - Explaining commands without disrupting your prompt
10
+ - Integrating through lightweight keybindings and shell hooks
11
+
12
+ The name comes from the scute, the protective shell plate on a turtle, and the tool itself is meant to assist with shell commands.
13
+ Scute is built as a single native binary (via Bun) so it can be distributed and updated easily.
14
+
15
+ ## Installation
16
+
17
+ Supported platforms: macOS and Linux (x86_64 only for now).
18
+
19
+ ### A. Install via curl (install.sh)
20
+
21
+ Convenience installer (requires `curl` and `tar`):
22
+
23
+ ```sh
24
+ curl -fsSL https://raw.githubusercontent.com/napisani/scute/main/scripts/install.sh | bash
25
+ ```
26
+
27
+ By default it installs into `/usr/local/bin` and pulls the latest release. Pass `vX.Y.Z` and a custom directory to override.
28
+
29
+ ### B. Homebrew
30
+
31
+ ```sh
32
+ brew tap napisani/scute https://github.com/napisani/scute
33
+ brew install scute
34
+ ```
35
+
36
+ ### C. npm / npx
37
+
38
+ Install globally:
39
+
40
+ ```sh
41
+ npm install -g @napisani/scute
42
+ ```
43
+
44
+ Or run once with:
45
+
46
+ ```sh
47
+ npx @napisani/scute --help
48
+ ```
49
+
50
+ > The npm package runs a Bun-based `postinstall` script to download the matching release binary, so Bun must be available on your `PATH`.
51
+
52
+ ### D. Nix
53
+
54
+ Add the repo as an input and use it in your Home Manager flake:
55
+
56
+ ```nix
57
+ inputs.scute.url = "github:napisani/scute";
58
+
59
+ outputs = { self, nixpkgs, scute, ... }: {
60
+ homeConfigurations.me = nixpkgs.lib.homeManagerConfiguration {
61
+ # ...
62
+ packages = [ scute.packages.${pkgs.system}.default ];
63
+ };
64
+ };
65
+ ```
66
+
67
+ > The repository ships an intentionally minimal `flake.nix`. Run `nix flake lock --update-input scute` inside your own workspace to pin exact revisions.
68
+
69
+ ### E. Prebuilt binaries (manual)
70
+
71
+ Every Git tag publishes `x86_64` macOS and Linux archives on the [GitHub Releases](https://github.com/napisani/scute/releases) page. Download the archive for your platform, unpack it, and move the `scute` binary onto your `PATH`:
72
+
73
+ ```sh
74
+ curl -L -o scute.tar.gz "https://github.com/napisani/scute/releases/download/vX.Y.Z/scute-vX.Y.Z-macos-x86_64.tar.gz"
75
+ tar -xzf scute.tar.gz
76
+ sudo mv scute /usr/local/bin/
77
+ ```
78
+
79
+ Verify downloads with the checksums shipped alongside each release:
80
+
81
+ ```sh
82
+ curl -LO https://github.com/napisani/scute/releases/download/vX.Y.Z/checksums.txt
83
+ grep scute-vX.Y.Z-macos-x86_64.tar.gz checksums.txt | shasum -a 256 -c -
84
+ ```
85
+
86
+ ### F. Install from source
87
+
88
+ ```sh
89
+ git clone https://github.com/napisani/scute.git
90
+ cd scute
91
+ bun install --frozen-lockfile
92
+ bun run build:bin
93
+ sudo mv dist/scute /usr/local/bin/
94
+ ```
95
+
96
+ If you prefer Make targets:
97
+
98
+ ```sh
99
+ make build
100
+ sudo mv dist/scute /usr/local/bin/
101
+ ```
102
+
103
+ ## Configuration
104
+
105
+ Scute reads configuration from `~/.config/scute/config.yaml` by default. You can override it per invocation with `--config <path>`.
106
+
107
+ ### Precedence
108
+
109
+ 1. `--config <path>` (explicit CLI override)
110
+ 2. Environment variables (provider keys, defaults)
111
+ 3. Config file defaults (schema defaults)
112
+
113
+ Notes:
114
+ - `dotenv/config` is loaded at startup, so values in `.env` will be respected.
115
+ - Provider env vars (e.g., `OPENAI_API_KEY`) merge into `providers` and override matching entries.
116
+
117
+ ### Minimal config example
118
+
119
+ ```yaml
120
+ # ~/.config/scute/config.yaml
121
+
122
+ # Use a compact view for the token editor
123
+ viewMode: horizontal
124
+
125
+ # Define at least one provider for prompts
126
+ providers:
127
+ - name: openai
128
+ apiKey: ${OPENAI_API_KEY}
129
+
130
+ # Optional: adjust shell keybindings (universal syntax)
131
+ shellKeybindings:
132
+ explain: "Ctrl+E"
133
+ build: "Ctrl+G"
134
+ suggest: "Ctrl+Shift+E"
135
+ ```
136
+
137
+ ### Fully configured example
138
+
139
+ ```yaml
140
+ # ~/.config/scute/config.yaml
141
+
142
+ # Layout for the interactive token editor
143
+ viewMode: horizontal # horizontal -> annotated view, vertical -> list view
144
+
145
+ # Clipboard command for output channel "clipboard"
146
+ clipboardCommand: "pbcopy"
147
+
148
+ # Providers used by prompts (env vars override these)
149
+ providers:
150
+ - name: openai
151
+ apiKey: ${OPENAI_API_KEY}
152
+ - name: anthropic
153
+ apiKey: ${ANTHROPIC_API_KEY}
154
+ - name: gemini
155
+ apiKey: ${GEMINI_API_KEY}
156
+ - name: ollama
157
+ baseUrl: ${OLLAMA_BASE_URL}
158
+
159
+ # Keybindings for the interactive token editor UI
160
+ keybindings:
161
+ up: ["up"]
162
+ down: ["down"]
163
+ left: ["left", "h"]
164
+ right: ["right", "l"]
165
+ wordForward: ["w"]
166
+ wordBackward: ["b"]
167
+ lineStart: ["0", "^"]
168
+ lineEnd: ["$"]
169
+ firstToken: ["g"]
170
+ lastToken: ["G"]
171
+ appendLine: ["A"]
172
+ explain: ["e"]
173
+ toggleView: ["m"]
174
+ insert: ["i"]
175
+ append: ["a"]
176
+ change: ["c"]
177
+ exitInsert: ["escape"]
178
+ save: ["return"]
179
+
180
+ # Shell keybindings in universal syntax (rendered by scute init)
181
+ shellKeybindings:
182
+ explain: "Ctrl+E"
183
+ build: "Ctrl+G"
184
+ suggest: "Ctrl+Shift+E"
185
+ generate: [] # disable if you do not want a binding
186
+
187
+ # Theme colors (catppuccin defaults shown)
188
+ theme:
189
+ tokenColors:
190
+ command: "#A6E3A1"
191
+ option: "#FAB387"
192
+ argument: "#89B4FA"
193
+ assignment: "#CBA6F7"
194
+ pipe: "#94E2D5"
195
+ controlOperator: "#F38BA8"
196
+ redirect: "#CDD6F4"
197
+ unknown: "#6C7086"
198
+ tokenDescription: "#CDD6F4"
199
+ markerColor: "#CDD6F4"
200
+
201
+ # Prompt behavior per command
202
+ prompts:
203
+ explain:
204
+ provider: openai
205
+ model: gpt-4
206
+ temperature: 0.7
207
+ maxTokens: 128000
208
+ userPrompt: ""
209
+ systemPromptOverride: ""
210
+ suggest:
211
+ provider: openai
212
+ model: gpt-4
213
+ temperature: 0.7
214
+ maxTokens: 128000
215
+ generate:
216
+ provider: openai
217
+ model: gpt-4
218
+ temperature: 0.7
219
+ maxTokens: 128000
220
+ describeTokens:
221
+ provider: openai
222
+ model: gpt-4
223
+ temperature: 0.7
224
+ maxTokens: 128000
225
+ ```
226
+
227
+ ### Environment variables
228
+
229
+ Provider credentials and defaults:
230
+
231
+ - `OPENAI_API_KEY`
232
+ - `ANTHROPIC_API_KEY`
233
+ - `GEMINI_API_KEY`
234
+ - `OLLAMA_BASE_URL`
235
+ - `SCUTE_DEFAULT_PROVIDER`
236
+ - `SCUTE_DEFAULT_MODEL`
237
+
238
+ Runtime behavior:
239
+
240
+ - `SCUTE_DEBUG` (set to `1` or `true` for verbose logging)
241
+ - `SCUTE_SHELL` (override detected shell name)
242
+ - `SHELL` (standard shell env var)
243
+ - `READLINE_LINE` (readline current line, when present)
244
+
245
+ ## Shell Integration
246
+
247
+ `scute` integrates with your shell via a script that needs to be loaded by your shell's configuration file (e.g., `.bashrc`).
248
+
249
+ ### For Bash
250
+
251
+ Add the following line to the end of your `~/.bashrc` file:
252
+
253
+ ```sh
254
+ eval "$(scute init bash)"
255
+ ```
256
+
257
+ After adding the line, restart your terminal or run `source ~/.bashrc` to apply the changes.
258
+
259
+ ### For Nix/home-manager Users
260
+
261
+ If you use `home-manager` to manage your dotfiles, you cannot edit `.bashrc` directly. Instead, add the following to your `home.nix` configuration:
262
+
263
+ ```nix
264
+ programs.bash = {
265
+ enable = true;
266
+ bashrcExtra = ''
267
+ eval "$(scute init bash)"
268
+ '';
269
+ };
270
+ ```
271
+
272
+ Then, run `home-manager switch` to apply the configuration.
273
+
274
+ ## Debug Logging
275
+
276
+ Set `SCUTE_DEBUG=1` to enable verbose logs. When enabled, `scute` writes detailed traces to `/tmp/scute.log`:
277
+
278
+ ```sh
279
+ export SCUTE_DEBUG=1
280
+ tail -f /tmp/scute.log
281
+ ```
282
+
283
+ ### Inspect Resolved Configuration
284
+
285
+ Use the `config-debug` subcommand to print the fully resolved configuration (including environment overrides). This is useful when troubleshooting provider settings or custom config files:
286
+
287
+ ```sh
288
+ scute --config configs/ollama-config.yml config-debug
289
+ ```
290
+
291
+ The command prints a JSON payload containing the merged configuration and relevant environment variables.
292
+
293
+ ## Testing
294
+
295
+ Test files use the `.test.ts` suffix. Evaluation tests use `.eval.test.ts` and live in the `evals/` directory.
296
+
297
+ ```sh
298
+ # Run standard unit tests
299
+ bun run test
300
+
301
+ # Run evaluation tests
302
+ bun run evals
303
+
304
+ # Or via Make targets
305
+ make test
306
+ ```
307
+
308
+ ## Usage
309
+
310
+ Once installed and configured, you can use the following keyboard shortcuts in your terminal:
311
+
312
+ - **`Ctrl + G`**: **Suggest Completion**. Takes the current command you are typing, sends it to the AI for completion, and replaces the line with the AI's suggestion.
313
+ - **`Ctrl + P`**: **Suggest from Prompt**. Replaces your current line with a command generated by the AI based on a prompt. (Note: The current implementation is a stub).
314
+ - **`Ctrl + E`**: **Explain Command**. Reads the command on the current line and displays a helpful, non-interfering explanation on the line below your prompt.
315
+
316
+ ## Release Process (Maintainers)
317
+
318
+ 1. Update `package.json` version.
319
+ 2. Ensure your working tree is clean and Bun is installed.
320
+ 3. Run `make release`.
321
+ - Runs lint and tests, builds the binary, tags `vX.Y.Z`, pushes the tag, and publishes to npm.
322
+ 4. GitHub Actions builds macOS/Linux archives and uploads them to the release.
323
+ 5. Refresh Homebrew checksums:
324
+
325
+ ```sh
326
+ make update-brew VERSION=vX.Y.Z
327
+ ```
package/dist/scute ADDED
Binary file
package/package.json ADDED
@@ -0,0 +1,87 @@
1
+ {
2
+ "name": "@napisani/scute",
3
+ "version": "0.0.1",
4
+ "description": "AI-powered shell assistant",
5
+ "module": "index.ts",
6
+ "type": "module",
7
+ "keywords": [
8
+ "shell",
9
+ "ai",
10
+ "explain",
11
+ "bash",
12
+ "zsh",
13
+ "suggestion",
14
+ "tui"
15
+ ],
16
+ "homepage": "https://github.com/napisani/scute",
17
+ "bugs": {
18
+ "url": "https://github.com/napisani/scute/issues"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/napisani/scute.git"
23
+ },
24
+ "license": "MIT",
25
+ "author": "Nick Pisani",
26
+ "main": "index.js",
27
+ "bin": {
28
+ "scute": "dist/scute"
29
+ },
30
+ "directories": {
31
+ "test": "tests"
32
+ },
33
+ "files": [
34
+ "dist/",
35
+ "scripts/",
36
+ "README.md",
37
+ "LICENSE"
38
+ ],
39
+ "scripts": {
40
+ "build": "bun run build:bin",
41
+ "build:bin": "bun build ./src/index.ts --compile --outfile dist/scute",
42
+ "clean": "rm -rf dist",
43
+ "lint": "bunx tsc --noEmit",
44
+ "test": "bun test tests/",
45
+ "coverage": "bun test tests/ --coverage",
46
+ "evals": "bun test evals --pattern \\\"\\.eval\\.test\\.ts$\\\"",
47
+ "prepublishOnly": "bun run clean && bun install --frozen-lockfile && bun run lint && bun run test",
48
+ "postinstall": "bun scripts/postinstall.ts"
49
+ },
50
+ "dependencies": {
51
+ "@opentui/core": "^0.1.75",
52
+ "@opentui/react": "^0.1.75",
53
+ "@tanstack/ai": "^0.2.2",
54
+ "@tanstack/ai-anthropic": "^0.2.0",
55
+ "@tanstack/ai-gemini": "^0.3.2",
56
+ "@tanstack/ai-ollama": "^0.3.0",
57
+ "@tanstack/ai-openai": "^0.2.1",
58
+ "chalk": "^5.6.2",
59
+ "commander": "^14.0.2",
60
+ "dotenv": "^17.2.3",
61
+ "js-yaml": "^4.1.1",
62
+ "react": "^19.2.4",
63
+ "shell-quote": "^1.8.3"
64
+ },
65
+ "devDependencies": {
66
+ "@biomejs/biome": "2.3.12",
67
+ "@testing-library/react": "^16.3.2",
68
+ "@types/bun": "latest",
69
+ "@types/js-yaml": "^4.0.9",
70
+ "@types/jsdom": "^27.0.0",
71
+ "@types/node": "^25.0.10",
72
+ "@types/react": "^19.2.9",
73
+ "@types/shell-quote": "^1.7.5",
74
+ "happy-dom": "^20.5.0",
75
+ "jsdom": "^28.0.0"
76
+ },
77
+ "peerDependencies": {
78
+ "typescript": "^5"
79
+ },
80
+ "engines": {
81
+ "node": ">=18"
82
+ },
83
+ "os": [
84
+ "darwin",
85
+ "linux"
86
+ ]
87
+ }
@@ -0,0 +1,73 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ REPO="napisani/scute"
5
+
6
+ if ! command -v curl >/dev/null 2>&1; then
7
+ echo "curl is required" >&2
8
+ exit 1
9
+ fi
10
+
11
+ case "$VERSION" in
12
+ v*) ;;
13
+ *) VERSION="v$VERSION" ;;
14
+ esac
15
+
16
+ if ! command -v tar >/dev/null 2>&1; then
17
+ echo "tar is required" >&2
18
+ exit 1
19
+ fi
20
+
21
+ if [ "${1:-}" = "--help" ]; then
22
+ cat <<EOF
23
+ Usage: install.sh [version] [install-dir]
24
+
25
+ version Git tag to install (default: latest release)
26
+ install-dir Directory to place the scute binary (default: /usr/local/bin)
27
+ EOF
28
+ exit 0
29
+ fi
30
+
31
+ VERSION="${1:-latest}"
32
+ INSTALL_DIR="${2:-/usr/local/bin}"
33
+
34
+ if [ "$VERSION" = "latest" ]; then
35
+ VERSION=$(curl -fsSL https://api.github.com/repos/${REPO}/releases/latest | sed -n 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' | head -n1)
36
+ if [ -z "$VERSION" ]; then
37
+ echo "Unable to determine latest release tag" >&2
38
+ exit 1
39
+ fi
40
+ fi
41
+
42
+ ARCH=$(uname -m)
43
+ OS=$(uname -s)
44
+
45
+ case "$OS" in
46
+ Linux) PLATFORM="linux" ;;
47
+ Darwin) PLATFORM="macos" ;;
48
+ *)
49
+ echo "Unsupported OS: $OS" >&2
50
+ exit 1
51
+ ;;
52
+ esac
53
+
54
+ if [ "$ARCH" != "x86_64" ]; then
55
+ echo "Currently only x86_64 binaries are published." >&2
56
+ exit 1
57
+ fi
58
+
59
+ TARBALL="scute-${VERSION}-${PLATFORM}-${ARCH}.tar.gz"
60
+ URL="https://github.com/${REPO}/releases/download/${VERSION}/${TARBALL}"
61
+
62
+ TMP_DIR=$(mktemp -d)
63
+ trap 'rm -rf "$TMP_DIR"' EXIT
64
+
65
+ echo "Downloading ${URL}"
66
+ curl -fsSL "$URL" -o "$TMP_DIR/$TARBALL"
67
+
68
+ tar -xzf "$TMP_DIR/$TARBALL" -C "$TMP_DIR"
69
+
70
+ mkdir -p "$INSTALL_DIR"
71
+ install -m 755 "$TMP_DIR/scute" "$INSTALL_DIR/scute"
72
+
73
+ echo "scute installed to $INSTALL_DIR/scute"
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { access, chmod, mkdir, rm } from "node:fs/promises";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+
7
+ async function buildFromSource(distDir: string, binaryPath: string) {
8
+ console.warn(
9
+ `[scute] No prebuilt binary available for ${process.platform}/${process.arch}. Building from source...`,
10
+ );
11
+ await mkdir(distDir, { recursive: true });
12
+ const build = Bun.spawn(["bun", "run", "build:bin"], {
13
+ stdout: "inherit",
14
+ stderr: "inherit",
15
+ });
16
+ const exitCode = await build.exited;
17
+ if (exitCode !== 0) {
18
+ build.kill();
19
+ throw new Error("Failed to build binary from source.");
20
+ }
21
+ try {
22
+ await access(binaryPath);
23
+ } catch {
24
+ throw new Error(
25
+ "Build completed but the scute binary was not created at dist/scute.",
26
+ );
27
+ }
28
+ await chmod(binaryPath, 0o755);
29
+ }
30
+
31
+ async function main() {
32
+ const version = Bun.env.npm_package_version;
33
+ if (!version || version === "0.0.0-development") {
34
+ console.warn("[scute] Skipping postinstall: unknown package version.");
35
+ return;
36
+ }
37
+
38
+ const platform = process.platform;
39
+ if (platform !== "darwin" && platform !== "linux") {
40
+ throw new Error(
41
+ `Unsupported platform '${platform}'. scute distributes binaries for macOS and Linux only.`,
42
+ );
43
+ }
44
+
45
+ // Ensure tar is available
46
+ const tarCheck = Bun.spawn(["tar", "--version"], {
47
+ stdout: "ignore",
48
+ stderr: "ignore",
49
+ });
50
+ if ((await tarCheck.exited) !== 0) {
51
+ tarCheck.kill();
52
+ throw new Error(
53
+ "`tar` is required to install scute. Please ensure it is available on PATH.",
54
+ );
55
+ }
56
+
57
+ const archMap: Record<string, string> = {
58
+ x64: "x86_64",
59
+ };
60
+ const distDir = join(import.meta.dir, "..", "dist");
61
+ await mkdir(distDir, { recursive: true });
62
+
63
+ const binaryPath = join(distDir, "scute");
64
+ try {
65
+ await access(binaryPath);
66
+ return; // Already present (e.g. local install)
67
+ } catch {
68
+ // continue
69
+ }
70
+
71
+ const detected = archMap[process.arch] ?? null;
72
+ if (!detected) {
73
+ await buildFromSource(distDir, binaryPath);
74
+ return;
75
+ }
76
+
77
+ const osName = platform === "darwin" ? "macos" : "linux";
78
+ const tag = version.startsWith("v") ? version : `v${version}`;
79
+ const tarball = `scute-${tag}-${osName}-${detected}.tar.gz`;
80
+ const url = `https://github.com/napisani/scute/releases/download/${tag}/${tarball}`;
81
+
82
+ console.log(`[scute] Downloading ${url}`);
83
+ const response = await fetch(url);
84
+ if (!response.ok) {
85
+ if (response.status === 404) {
86
+ await buildFromSource(distDir, binaryPath);
87
+ return;
88
+ }
89
+ throw new Error(
90
+ `[scute] Failed to download binary from ${url} (${response.status} ${response.statusText})`,
91
+ );
92
+ }
93
+
94
+ const tmpFile = join(tmpdir(), `${tarball}.${process.pid}.tmp`);
95
+ const buffer = await response.arrayBuffer();
96
+ await Bun.write(tmpFile, buffer);
97
+
98
+ const extract = Bun.spawn(["tar", "-xzf", tmpFile, "-C", distDir]);
99
+ const exitCode = await extract.exited;
100
+ if (exitCode !== 0) {
101
+ extract.kill();
102
+ throw new Error("[scute] Failed to extract downloaded archive.");
103
+ }
104
+
105
+ await chmod(binaryPath, 0o755);
106
+ await rm(tmpFile, { force: true });
107
+ }
108
+
109
+ await main().catch((error) => {
110
+ console.error(`[scute] Postinstall error: ${error.message}`);
111
+ process.exit(1);
112
+ });
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -euo pipefail
4
+
5
+ if [ $# -ne 1 ]; then
6
+ echo "Usage: $0 <version>" >&2
7
+ exit 1
8
+ fi
9
+
10
+ VERSION="$1"
11
+ case "$VERSION" in
12
+ v*) TAG="$VERSION" ;;
13
+ *) TAG="v$VERSION" ;;
14
+ esac
15
+
16
+ if ! command -v curl >/dev/null 2>&1; then
17
+ echo "curl is required" >&2
18
+ exit 1
19
+ fi
20
+
21
+ if ! command -v sha256sum >/dev/null 2>&1; then
22
+ if command -v shasum >/dev/null 2>&1; then
23
+ sha256sum() { shasum -a 256 "$@"; }
24
+ else
25
+ echo "sha256sum or shasum is required" >&2
26
+ exit 1
27
+ fi
28
+ fi
29
+
30
+ REPO="napisani/scute"
31
+
32
+ download_and_sha() {
33
+ local platform="$1"
34
+ local arch="x86_64"
35
+ local url="https://github.com/${REPO}/releases/download/${TAG}/scute-${TAG}-${platform}-${arch}.tar.gz"
36
+ local tmp
37
+ tmp=$(mktemp)
38
+ curl -fsSL "$url" -o "$tmp"
39
+ local sum
40
+ sum=$(sha256sum "$tmp" | awk '{print $1}')
41
+ rm -f "$tmp"
42
+ echo "$sum"
43
+ }
44
+
45
+ MAC_SHA=$(download_and_sha macos)
46
+ LINUX_SHA=$(download_and_sha linux)
47
+
48
+ FORMULA="Formula/scute.rb"
49
+
50
+ perl -0pi -e 's/version "[^"]+"/version "'"${TAG#v}"'"/' "$FORMULA"
51
+ perl -0pi -e 's/(on_macos do\n\s+url ".*"\n\s+sha256 ")[^"]+("/\1'"$MAC_SHA"'\2/' "$FORMULA"
52
+ perl -0pi -e 's/(on_linux do\n\s+url ".*"\n\s+sha256 ")[^"]+("/\1'"$LINUX_SHA"'\2/' "$FORMULA"
53
+
54
+ echo "Updated $FORMULA with version ${TAG#v}"