Compare commits
10
Commits
main
...
secure-main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5dd271588 | ||
|
|
32663a7b18 | ||
|
|
f6ee715478 | ||
|
|
907613f657 | ||
|
|
fd65bf1b17 | ||
|
|
766d0cb479 | ||
|
|
4a201858e9 | ||
|
|
1d4cf88f8b | ||
|
|
56bc5a79e7 | ||
|
|
a6cf45b883 |
@@ -0,0 +1,26 @@
|
||||
name: Upstream Sync
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '@hourly' # Every hour (Gitea shorthand)
|
||||
workflow_dispatch: # Manual trigger
|
||||
|
||||
jobs:
|
||||
sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: main
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Sync Upstream
|
||||
run: |
|
||||
git config user.email "omar@git.qomar.pw"
|
||||
git config user.name "Gitea Action"
|
||||
git remote add upstream https://github.com/0Chencc/clawgod.git
|
||||
git fetch upstream main
|
||||
git checkout main
|
||||
git reset --hard upstream/main
|
||||
git push origin main --force
|
||||
@@ -1,54 +0,0 @@
|
||||
name: Cache Cleanup Weekly
|
||||
|
||||
# compat-daily.yml writes a fresh `~/.npm` cache entry on every successful
|
||||
# run (key includes ${{ github.run_id }}, which is unique per run) and reads
|
||||
# previous entries via restore-keys. GitHub's automatic 7-day cache expiry
|
||||
# only kicks in for entries that haven't been *accessed* — the restore-keys
|
||||
# match counts as access, so daily-tested entries never expire on their
|
||||
# own. Without housekeeping, cache entries accumulate until we hit the
|
||||
# 10 GB per-repo limit and GitHub starts evicting LRU, which sometimes
|
||||
# kicks the entries we actually wanted to keep.
|
||||
#
|
||||
# Run weekly: list every cache, delete it. Next compat-daily run repopulates
|
||||
# `~/.npm` from a fresh npm-registry fetch (one extra ~80 MB download per
|
||||
# week, trivial cost).
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 4 * * 0' # Sunday 04:00 UTC
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
actions: write # required for `gh cache delete`
|
||||
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
|
||||
jobs:
|
||||
purge:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Delete all repo caches
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
REPO: ${{ github.repository }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# gh cache list paginates; --limit 200 handles up to 200 entries
|
||||
# in a single call (we'd never expect that many anyway).
|
||||
ids=$(gh cache list --repo "$REPO" --limit 200 --json id --jq '.[].id')
|
||||
if [[ -z "$ids" ]]; then
|
||||
echo "No caches to delete."
|
||||
exit 0
|
||||
fi
|
||||
count=$(printf '%s\n' "$ids" | grep -c . || true)
|
||||
echo "Deleting $count cache entries…"
|
||||
while IFS= read -r id; do
|
||||
[[ -z "$id" ]] && continue
|
||||
gh cache delete "$id" --repo "$REPO" \
|
||||
&& echo " ✓ $id" \
|
||||
|| echo " ✗ $id (already gone or transient error)"
|
||||
done <<< "$ids"
|
||||
echo "Done. Next compat-daily run will repopulate ~/.npm fresh."
|
||||
@@ -1,212 +0,0 @@
|
||||
name: Compat Daily
|
||||
|
||||
# Runs install.sh end-to-end on every supported platform against the current
|
||||
# latest Claude Code from npm. Catches the kind of regression we hit when
|
||||
# Anthropic bumps the embedded Bun runtime ahead of Bun's stable release.
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '17 7 * * *' # ~07:17 UTC daily
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- install.sh
|
||||
- .github/workflows/compat-daily.yml
|
||||
pull_request:
|
||||
paths:
|
||||
- install.sh
|
||||
- .github/workflows/compat-daily.yml
|
||||
|
||||
permissions:
|
||||
contents: write # write needed to push the version-badge JSON to `badges` branch
|
||||
issues: write
|
||||
|
||||
# Opt every JS-based action (e.g. actions/checkout, actions/cache,
|
||||
# actions/github-script) onto Node 24, ahead of GitHub forcing it on
|
||||
# 2026-06-02. Silences the deprecation warning and keeps us aligned
|
||||
# with the Node version we use to run patch.mjs / extract-natives.mjs.
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
|
||||
jobs:
|
||||
smoke:
|
||||
# Single Linux runner — a Linux failure almost always means cross-platform
|
||||
# breakage upstream. macOS / Windows runners are 10x / 2x more expensive
|
||||
# than Linux on shared-tier accounting, so we don't burn them on a daily
|
||||
# signal.
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Node.js 24
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24
|
||||
|
||||
- name: Set up Bun (canary)
|
||||
# Anthropic ships claude-code with bleeding-edge Bun (e.g. 1.3.14
|
||||
# before it leaves the canary channel). Stable Bun panics with
|
||||
# "Expected CommonJS module to have a function wrapper" when loading
|
||||
# cli.original.cjs extracted from a newer-Bun-built native binary.
|
||||
# setup-bun caches the canary binary by commit hash — same canary
|
||||
# build is restored from cache, new build re-downloads.
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: canary
|
||||
|
||||
- name: Cache ~/.npm (claude-code-<plat> tarball)
|
||||
# install.sh runs `npm pack @anthropic-ai/claude-code-linux-x64@latest`,
|
||||
# which lands the ~80 MB tarball in ~/.npm/_cacache. Reusing the cache
|
||||
# lets npm short-circuit the download when @latest hasn't bumped since
|
||||
# the last run; it still re-validates registry metadata, so we never
|
||||
# serve a stale binary on a real upgrade day.
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: npm-claude-${{ runner.os }}-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
npm-claude-${{ runner.os }}-
|
||||
|
||||
- name: Install ripgrep
|
||||
shell: bash
|
||||
run: |
|
||||
sudo apt-get update -qq && sudo apt-get install -y ripgrep
|
||||
rg --version | head -1
|
||||
|
||||
- name: Add ~/.local/bin to PATH (clawgod launcher install target)
|
||||
shell: bash
|
||||
run: echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Print runtime versions
|
||||
shell: bash
|
||||
run: |
|
||||
bun --version
|
||||
node --version
|
||||
uname -a
|
||||
|
||||
- name: Run install.sh (npm-fallback path)
|
||||
# No official Claude binary pre-installed → install.sh exercises
|
||||
# its npm-registry fallback to fetch @anthropic-ai/claude-code-<plat>.
|
||||
# Capture output so the patch-result line can be asserted on; we
|
||||
# don't trust `patch.mjs --verify` because some patches have no
|
||||
# post-state sentinel (they use a regex-stale heuristic that
|
||||
# false-positives once the source survives a partial replacement).
|
||||
shell: bash
|
||||
run: |
|
||||
set -o pipefail
|
||||
bash install.sh 2>&1 | tee /tmp/install.log
|
||||
|
||||
- name: Verify install artifacts
|
||||
shell: bash
|
||||
run: |
|
||||
ls -la "$HOME/.clawgod/" || true
|
||||
for f in cli.cjs cli.original.cjs patch.mjs extract-natives.mjs post-process.mjs .source-version; do
|
||||
test -e "$HOME/.clawgod/$f" || { echo "::error::missing ~/.clawgod/$f"; exit 1; }
|
||||
done
|
||||
echo "Source: $(cat "$HOME/.clawgod/.source-version")"
|
||||
|
||||
- name: Assert all patches applied (parse install log)
|
||||
# patch.mjs prints "Result: A applied, S skipped, F failed".
|
||||
# F must be 0 — otherwise upstream has shifted enough that one of
|
||||
# our regex patches no longer matches and a feature is silently broken.
|
||||
shell: bash
|
||||
run: |
|
||||
line=$(grep -E 'Result: [0-9]+ applied, [0-9]+ skipped, [0-9]+ failed' /tmp/install.log | tail -1 || true)
|
||||
echo "Patch summary: ${line:-<not found>}"
|
||||
[[ -n "$line" ]] || { echo "::error::patch.mjs result line missing from install.sh output"; exit 1; }
|
||||
failed=$(echo "$line" | sed -E 's/.*skipped, ([0-9]+) failed.*/\1/')
|
||||
[[ "$failed" -eq 0 ]] || { echo "::error::patch.mjs reported $failed failed patches"; exit 1; }
|
||||
|
||||
- name: Smoke test — claude --version
|
||||
# Exercises the wrapper path:
|
||||
# launcher → bun cli.cjs → require('./cli.original.cjs')
|
||||
# The Bun CJS-wrapper panic surfaces here, not at install time.
|
||||
shell: bash
|
||||
run: |
|
||||
set +e
|
||||
out=$(claude --version 2>&1)
|
||||
rc=$?
|
||||
set -e
|
||||
echo "$out"
|
||||
if echo "$out" | grep -q "Expected CommonJS module to have a function wrapper"; then
|
||||
echo "::error::Bun CJS-wrapper panic — local Bun lags the embedded Bun"
|
||||
exit 1
|
||||
fi
|
||||
[[ $rc -eq 0 ]] || { echo "::error::claude --version exited $rc"; exit 1; }
|
||||
|
||||
- name: Publish supported-Claude-version badge
|
||||
# Write the version we just verified end-to-end to a JSON file on the
|
||||
# `badges` branch (force-pushed; that branch holds nothing else and is
|
||||
# never read as source). README links to it via shields.io endpoint.
|
||||
# PRs from forks can't push, so skip them.
|
||||
if: success() && github.event_name != 'pull_request'
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
version=$(cat "$HOME/.clawgod/.source-version")
|
||||
[[ -n "$version" ]] || { echo "::error::source-version missing"; exit 1; }
|
||||
tmp=$(mktemp -d)
|
||||
cd "$tmp"
|
||||
cat > claude-version.json <<EOF
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"label": "Claude tested",
|
||||
"message": "$version",
|
||||
"color": "brightgreen"
|
||||
}
|
||||
EOF
|
||||
git init -q -b badges
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config user.name "github-actions[bot]"
|
||||
git add claude-version.json
|
||||
git commit -q -m "compat-daily: claude $version verified"
|
||||
git push -fq "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" HEAD:badges
|
||||
echo "Published badge: claude $version"
|
||||
|
||||
- name: Open / update issue on scheduled failure
|
||||
if: failure() && github.event_name == 'schedule'
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const stamp = path.join(process.env.HOME, '.clawgod', '.source-version');
|
||||
const claudeVersion = fs.existsSync(stamp)
|
||||
? fs.readFileSync(stamp, 'utf8').trim()
|
||||
: 'unknown';
|
||||
const title = `compat-daily: broke (claude ${claudeVersion})`;
|
||||
const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
|
||||
const { data: open } = await github.rest.issues.listForRepo({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
state: 'open',
|
||||
labels: 'compat-broken',
|
||||
per_page: 100,
|
||||
});
|
||||
const dup = open.find(i => i.title === title);
|
||||
if (dup) {
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: dup.number,
|
||||
body: `Re-failed ${new Date().toISOString().slice(0,10)} — ${runUrl}`,
|
||||
});
|
||||
} else {
|
||||
await github.rest.issues.create({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
title,
|
||||
labels: ['compat-broken', 'bug'],
|
||||
body: [
|
||||
`Daily compatibility run failed on \`ubuntu-latest\`.`,
|
||||
``,
|
||||
`- Claude binary: \`${claudeVersion}\``,
|
||||
`- Run: ${runUrl}`,
|
||||
``,
|
||||
`Auto-opened by \`.github/workflows/compat-daily.yml\`.`,
|
||||
].join('\n'),
|
||||
});
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
# Project policy: never run JS-based actions on Node 20 — they're already
|
||||
# deprecated and forced off after 2026-06-02. Pin every action that runs
|
||||
# JS (actions/checkout etc.) to Node 24 across all our workflows.
|
||||
env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Resolve versions
|
||||
id: versions
|
||||
run: |
|
||||
tag="${GITHUB_REF_NAME}"
|
||||
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
|
||||
prev=$(git tag --sort=-version:refname | grep -v "^${tag}$" | head -n1)
|
||||
echo "prev=${prev}" >> "$GITHUB_OUTPUT"
|
||||
if [ -n "$prev" ]; then
|
||||
echo "range=${prev}..${tag}" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "range=${tag}" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Build release notes
|
||||
id: notes
|
||||
run: |
|
||||
tag="${{ steps.versions.outputs.tag }}"
|
||||
prev="${{ steps.versions.outputs.prev }}"
|
||||
range="${{ steps.versions.outputs.range }}"
|
||||
{
|
||||
echo "## Changes"
|
||||
echo
|
||||
if [ -n "$prev" ]; then
|
||||
git log --pretty='- %s (%h)' "$range"
|
||||
else
|
||||
git log --pretty='- %s (%h)' "$tag"
|
||||
fi
|
||||
echo
|
||||
echo "## Install"
|
||||
echo
|
||||
echo '**macOS / Linux:**'
|
||||
echo '```bash'
|
||||
echo "curl -fsSL https://github.com/${{ github.repository }}/releases/latest/download/install.sh | bash"
|
||||
echo '```'
|
||||
echo
|
||||
echo '**Windows (PowerShell):**'
|
||||
echo '```powershell'
|
||||
echo "irm https://github.com/${{ github.repository }}/releases/latest/download/install.ps1 | iex"
|
||||
echo '```'
|
||||
if [ -n "$prev" ]; then
|
||||
echo
|
||||
echo "**Full changelog:** https://github.com/${{ github.repository }}/compare/${prev}...${tag}"
|
||||
fi
|
||||
} > release-notes.md
|
||||
|
||||
- name: Create GitHub release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
tag="${{ steps.versions.outputs.tag }}"
|
||||
if gh release view "$tag" >/dev/null 2>&1; then
|
||||
# Release already exists (e.g. created manually with curated notes).
|
||||
# Refresh assets only — don't touch notes/title.
|
||||
gh release upload "$tag" install.sh install.ps1 --clobber
|
||||
else
|
||||
gh release create "$tag" install.sh install.ps1 \
|
||||
--title "ClawGod $tag" \
|
||||
--notes-file release-notes.md
|
||||
fi
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
[English](README.md) | [中文](README_ZH.md) | [日本語](README_JP.md)
|
||||
|
||||
[](https://github.com/0Chencc/clawgod/releases/latest)
|
||||
[](https://github.com/0Chencc/clawgod/releases/latest)
|
||||
[](https://github.com/0Chencc/clawgod/releases)
|
||||
[](https://github.com/0Chencc/clawgod/actions/workflows/compat-daily.yml)
|
||||
[](https://github.com/0Chencc/clawgod/actions/workflows/compat-daily.yml)
|
||||
[](https://git.qomar.pw/omar/clawgod/releases/latest)
|
||||
[](https://git.qomar.pw/omar/clawgod/releases/latest)
|
||||
[](https://git.qomar.pw/omar/clawgod/releases)
|
||||
[](https://git.qomar.pw/omar/clawgod/actions/workflows/compat-daily.yml)
|
||||
[](https://git.qomar.pw/omar/clawgod/actions/workflows/compat-daily.yml)
|
||||
|
||||
> God mode for [Claude Code](https://docs.anthropic.com/en/docs/claude-code).
|
||||
|
||||
@@ -27,12 +27,12 @@ Install these **before** running the ClawGod installer:
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash
|
||||
curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash
|
||||
```
|
||||
|
||||
**Windows (PowerShell):**
|
||||
```powershell
|
||||
irm https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1 | iex
|
||||
irm https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1 | iex
|
||||
```
|
||||
|
||||
Green logo = patched. Orange logo = original.
|
||||
@@ -125,12 +125,12 @@ If you'd rather invoke the installer directly (same effect, both paths fetch the
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash
|
||||
curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```powershell
|
||||
irm https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1 | iex
|
||||
irm https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1 | iex
|
||||
```
|
||||
|
||||
If you'd rather drop ClawGod and use Anthropic's original `claude update` (which manages its own paths and would overwrite our launcher), uninstall first:
|
||||
@@ -143,13 +143,13 @@ bash ~/.clawgod/install.sh --uninstall
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash -s -- --uninstall
|
||||
curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash -s -- --uninstall
|
||||
hash -r # refresh shell cache
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```powershell
|
||||
irm https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1 -OutFile install.ps1; .\install.ps1 -Uninstall
|
||||
irm https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1 -OutFile install.ps1; .\install.ps1 -Uninstall
|
||||
```
|
||||
|
||||
Uninstall restores `claude.orig → claude` and removes the `clawgod` alias.
|
||||
|
||||
+11
-11
@@ -2,11 +2,11 @@
|
||||
|
||||
[English](README.md) | [中文](README_ZH.md) | [日本語](README_JP.md)
|
||||
|
||||
[](https://github.com/0Chencc/clawgod/releases/latest)
|
||||
[](https://github.com/0Chencc/clawgod/releases/latest)
|
||||
[](https://github.com/0Chencc/clawgod/releases)
|
||||
[](https://github.com/0Chencc/clawgod/actions/workflows/compat-daily.yml)
|
||||
[](https://github.com/0Chencc/clawgod/actions/workflows/compat-daily.yml)
|
||||
[](https://git.qomar.pw/omar/clawgod/releases/latest)
|
||||
[](https://git.qomar.pw/omar/clawgod/releases/latest)
|
||||
[](https://git.qomar.pw/omar/clawgod/releases)
|
||||
[](https://git.qomar.pw/omar/clawgod/actions/workflows/compat-daily.yml)
|
||||
[](https://git.qomar.pw/omar/clawgod/actions/workflows/compat-daily.yml)
|
||||
|
||||
> [Claude Code](https://docs.anthropic.com/en/docs/claude-code) ゴッドモード。
|
||||
|
||||
@@ -27,12 +27,12 @@ ClawGod インストーラ実行**前**に揃えておくもの:
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash
|
||||
curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash
|
||||
```
|
||||
|
||||
**Windows (PowerShell):**
|
||||
```powershell
|
||||
irm https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1 | iex
|
||||
irm https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1 | iex
|
||||
```
|
||||
|
||||
緑のロゴ = パッチ適用済み。オレンジのロゴ = オリジナル。
|
||||
@@ -125,12 +125,12 @@ claude.orig # オリジナル未修正版(自動バックアップ)
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash
|
||||
curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```powershell
|
||||
irm https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1 | iex
|
||||
irm https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1 | iex
|
||||
```
|
||||
|
||||
ClawGod を外して Anthropic 本来の `claude update`(独自に管理されたパスへ書き込み、私たちの launcher を上書きします)を使いたい場合は、先にアンインストールしてください:
|
||||
@@ -143,13 +143,13 @@ bash ~/.clawgod/install.sh --uninstall
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash -s -- --uninstall
|
||||
curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash -s -- --uninstall
|
||||
hash -r # シェルキャッシュをリフレッシュ
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```powershell
|
||||
irm https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1 -OutFile install.ps1; .\install.ps1 -Uninstall
|
||||
irm https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1 -OutFile install.ps1; .\install.ps1 -Uninstall
|
||||
```
|
||||
|
||||
アンインストールは `claude.orig` を `claude` に戻し、`clawgod` エイリアスを削除します。
|
||||
|
||||
+11
-11
@@ -2,11 +2,11 @@
|
||||
|
||||
[English](README.md) | [中文](README_ZH.md) | [日本語](README_JP.md)
|
||||
|
||||
[](https://github.com/0Chencc/clawgod/releases/latest)
|
||||
[](https://github.com/0Chencc/clawgod/releases/latest)
|
||||
[](https://github.com/0Chencc/clawgod/releases)
|
||||
[](https://github.com/0Chencc/clawgod/actions/workflows/compat-daily.yml)
|
||||
[](https://github.com/0Chencc/clawgod/actions/workflows/compat-daily.yml)
|
||||
[](https://git.qomar.pw/omar/clawgod/releases/latest)
|
||||
[](https://git.qomar.pw/omar/clawgod/releases/latest)
|
||||
[](https://git.qomar.pw/omar/clawgod/releases)
|
||||
[](https://git.qomar.pw/omar/clawgod/actions/workflows/compat-daily.yml)
|
||||
[](https://git.qomar.pw/omar/clawgod/actions/workflows/compat-daily.yml)
|
||||
|
||||
> [Claude Code](https://docs.anthropic.com/en/docs/claude-code) 上帝模式。
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash
|
||||
curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash
|
||||
```
|
||||
|
||||
**Windows (PowerShell):**
|
||||
```powershell
|
||||
irm https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1 | iex
|
||||
irm https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1 | iex
|
||||
```
|
||||
|
||||
绿色 Logo = 已 Patch。橙色 Logo = 原版。
|
||||
@@ -125,12 +125,12 @@ claude.orig # 原版未修改版本(自动备份)
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash
|
||||
curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```powershell
|
||||
irm https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1 | iex
|
||||
irm https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1 | iex
|
||||
```
|
||||
|
||||
如果你想脱离 ClawGod、使用 Anthropic 原本的 `claude update`(它会写到自己管的目录、并把我们的 launcher 替换掉),请先卸载:
|
||||
@@ -143,13 +143,13 @@ bash ~/.clawgod/install.sh --uninstall
|
||||
|
||||
**macOS / Linux:**
|
||||
```bash
|
||||
curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash -s -- --uninstall
|
||||
curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash -s -- --uninstall
|
||||
hash -r # 刷新 shell 缓存
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```powershell
|
||||
irm https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1 -OutFile install.ps1; .\install.ps1 -Uninstall
|
||||
irm https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1 -OutFile install.ps1; .\install.ps1 -Uninstall
|
||||
```
|
||||
|
||||
卸载会把 `claude.orig` 还原成 `claude`,并移除 `clawgod` 别名。
|
||||
|
||||
@@ -26,13 +26,13 @@
|
||||
### macOS / Linux
|
||||
|
||||
```bash
|
||||
curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash
|
||||
curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash
|
||||
```
|
||||
|
||||
### Windows (PowerShell)
|
||||
|
||||
```powershell
|
||||
irm https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1 | iex
|
||||
irm https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1 | iex
|
||||
```
|
||||
|
||||
### 验证
|
||||
@@ -161,7 +161,7 @@ CTF 场景的 Guard 策略应该偏宽松:
|
||||
exit
|
||||
|
||||
# 卸载 ClawGod(如果需要)
|
||||
curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash -s -- --uninstall
|
||||
curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash -s -- --uninstall
|
||||
|
||||
# 移除 CTF rules
|
||||
rm ~/.claude/rules/ctf-context.md
|
||||
|
||||
@@ -35,7 +35,7 @@ ClawGod 解决客户端层。Session Rules 解决模型层。Guard 重建可控
|
||||
|
||||
### 最小配置(5 分钟)
|
||||
|
||||
1. 安装 [ClawGod](https://github.com/0Chencc/clawgod) — 解除客户端层限制
|
||||
1. 安装 [ClawGod](https://git.qomar.pw/omar/clawgod) — 解除客户端层限制
|
||||
2. 复制 `01-session-rules/security-research-context.md` 到 `~/.claude/rules/`
|
||||
3. 完成。两层限制同时解除。
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
| 组件 | 提供者 | 解决的问题 |
|
||||
|------|--------|-----------|
|
||||
| ClawGod | [GitHub](https://github.com/0Chencc/clawgod) | 客户端运行时限制(Layer 0) |
|
||||
| ClawGod | [GitHub](https://git.qomar.pw/omar/clawgod) | 客户端运行时限制(Layer 0) |
|
||||
| Session Rules | 本文档 `01-session-rules/` | 模型层身份与场景声明(Layer 1) |
|
||||
| Scene Router | 本文档 `02-scene-router/` | 动态场景识别(Layer 2) |
|
||||
| Guard + Policy | 本文档 `03-guard-policy/` | 工具调用策略(Layer 3) |
|
||||
|
||||
+12
-12
@@ -24,7 +24,7 @@
|
||||
<nav class="topbar-links">
|
||||
<a href="#patches">Patches</a>
|
||||
<a href="#how">How it works</a>
|
||||
<a href="https://github.com/0Chencc/clawgod" target="_blank" rel="noopener">GitHub</a>
|
||||
<a href="https://git.qomar.pw/omar/clawgod" target="_blank" rel="noopener">GitHub</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
@@ -52,12 +52,12 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M9.294 6.776 14.357 1h-1.2L8.756 6.013 5.235 1H1.171l5.31 7.531L1.171 15h1.2l4.642-5.296L10.762 15h4.064L9.294 6.776Zm-1.643 1.872-.539-.755L2.804 1.91h1.844l3.452 4.847.539.755 4.49 6.301h-1.844L7.65 8.648Z"/></svg>
|
||||
<span>@0chencc</span>
|
||||
</a>
|
||||
<a class="hero-link stars" href="https://github.com/0Chencc/clawgod/stargazers" target="_blank" rel="noopener">
|
||||
<a class="hero-link stars" href="https://git.qomar.pw/omar/clawgod/stargazers" target="_blank" rel="noopener">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z"/></svg>
|
||||
<span class="stat-num loading" id="stat-stars">—</span>
|
||||
<span>stars</span>
|
||||
</a>
|
||||
<a class="hero-link downloads" href="https://github.com/0Chencc/clawgod/releases" target="_blank" rel="noopener">
|
||||
<a class="hero-link downloads" href="https://git.qomar.pw/omar/clawgod/releases" target="_blank" rel="noopener">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14H2.75Z"/><path d="M7.25 7.689V2a.75.75 0 0 1 1.5 0v5.689l1.97-1.969a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 6.78a.75.75 0 0 1 1.06-1.06l1.97 1.969Z"/></svg>
|
||||
<span class="stat-num loading" id="stat-downloads">—</span>
|
||||
<span>downloads</span>
|
||||
@@ -73,15 +73,15 @@
|
||||
</div>
|
||||
<div class="install-panel active" id="panel-unix" role="tabpanel">
|
||||
<div class="code-block">
|
||||
<button class="copy-btn" data-copy="curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash">Copy</button>
|
||||
<pre><span class="prompt">$ </span><span class="tok tok-cmd">curl</span> <span class="tok tok-flag">-fsSL</span> <span class="tok tok-url">https://github.com/0Chencc/clawgod/releases/latest/download/install.sh</span> <span class="tok tok-op">|</span> <span class="tok tok-cmd">bash</span></pre>
|
||||
<button class="copy-btn" data-copy="curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash">Copy</button>
|
||||
<pre><span class="prompt">$ </span><span class="tok tok-cmd">curl</span> <span class="tok tok-flag">-fsSL</span> <span class="tok tok-url">https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh</span> <span class="tok tok-op">|</span> <span class="tok tok-cmd">bash</span></pre>
|
||||
</div>
|
||||
<div class="install-note">Idempotent — safe to re-run. Bun, Node ≥ 18, ripgrep required.</div>
|
||||
</div>
|
||||
<div class="install-panel" id="panel-win" role="tabpanel">
|
||||
<div class="code-block">
|
||||
<button class="copy-btn" data-copy="irm https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1 | iex">Copy</button>
|
||||
<pre><span class="prompt">> </span><span class="tok tok-cmd">irm</span> <span class="tok tok-url">https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1</span> <span class="tok tok-op">|</span> <span class="tok tok-cmd">iex</span></pre>
|
||||
<button class="copy-btn" data-copy="irm https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1 | iex">Copy</button>
|
||||
<pre><span class="prompt">> </span><span class="tok tok-cmd">irm</span> <span class="tok tok-url">https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1</span> <span class="tok tok-op">|</span> <span class="tok tok-cmd">iex</span></pre>
|
||||
</div>
|
||||
<div class="install-note">Idempotent — safe to re-run. Bun via <a href="https://bun.sh/install" target="_blank" rel="noopener">bun.sh</a> recommended.</div>
|
||||
</div>
|
||||
@@ -179,8 +179,8 @@
|
||||
<!-- ─── CTA ───────────────────────────────────────────────── -->
|
||||
<section class="cta">
|
||||
<div class="cta-row">
|
||||
<a class="btn primary" href="https://github.com/0Chencc/clawgod#install">Get started</a>
|
||||
<a class="btn" href="https://github.com/0Chencc/clawgod" target="_blank" rel="noopener">
|
||||
<a class="btn primary" href="https://git.qomar.pw/omar/clawgod#install">Get started</a>
|
||||
<a class="btn" href="https://git.qomar.pw/omar/clawgod" target="_blank" rel="noopener">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
|
||||
Source on GitHub
|
||||
</a>
|
||||
@@ -206,9 +206,9 @@
|
||||
</a>
|
||||
</span>
|
||||
<span class="footer-cell footer-links">
|
||||
<a href="https://github.com/0Chencc/clawgod/releases">Releases</a> ·
|
||||
<a href="https://github.com/0Chencc/clawgod/issues">Issues</a> ·
|
||||
<a href="https://github.com/0Chencc/clawgod/actions/workflows/compat-daily.yml">CI</a>
|
||||
<a href="https://git.qomar.pw/omar/clawgod/releases">Releases</a> ·
|
||||
<a href="https://git.qomar.pw/omar/clawgod/issues">Issues</a> ·
|
||||
<a href="https://git.qomar.pw/omar/clawgod/actions/workflows/compat-daily.yml">CI</a>
|
||||
</span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
+81
-80
@@ -22,10 +22,10 @@ $ErrorActionPreference = "Stop"
|
||||
$ClawDir = Join-Path $env:USERPROFILE ".clawgod"
|
||||
$BinDir = Join-Path $env:USERPROFILE ".local\bin"
|
||||
|
||||
# ─── Colors ───────────────────────────────────────────
|
||||
# --- Colors -------------------------------------------
|
||||
|
||||
function Write-OK($msg) { Write-Host " ✓ $msg" -ForegroundColor Green }
|
||||
function Write-Err($msg) { Write-Host " ✗ $msg" -ForegroundColor Red }
|
||||
function Write-OK($msg) { Write-Host " [OK] $msg" -ForegroundColor Green }
|
||||
function Write-Err($msg) { Write-Host " [X] $msg" -ForegroundColor Red }
|
||||
function Write-Warn($msg) { Write-Host " ! $msg" -ForegroundColor Yellow }
|
||||
function Write-Dim($msg) { Write-Host " $msg" -ForegroundColor DarkGray }
|
||||
|
||||
@@ -34,7 +34,7 @@ Write-Host " ClawGod Installer" -ForegroundColor White -NoNewline
|
||||
Write-Host " (Windows)" -ForegroundColor DarkGray
|
||||
Write-Host ""
|
||||
|
||||
# ─── Uninstall ────────────────────────────────────────
|
||||
# --- Uninstall ----------------------------------------
|
||||
|
||||
if ($Uninstall) {
|
||||
# Restore original claude
|
||||
@@ -69,7 +69,7 @@ if ($Uninstall) {
|
||||
exit 0
|
||||
}
|
||||
|
||||
# ─── Prerequisites ────────────────────────────────────
|
||||
# --- Prerequisites ------------------------------------
|
||||
|
||||
try { $null = Get-Command node -ErrorAction Stop }
|
||||
catch {
|
||||
@@ -83,7 +83,7 @@ if ($nodeVer -lt 18) {
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ─── Ensure Bun (runtime that executes the patched cli.js) ────────────
|
||||
# --- Ensure Bun (runtime that executes the patched cli.js) ------------
|
||||
|
||||
$BunBin = $null
|
||||
try { $BunBin = (Get-Command bun -ErrorAction Stop).Source } catch {}
|
||||
@@ -103,9 +103,9 @@ if (-not $BunBin) {
|
||||
}
|
||||
}
|
||||
|
||||
# Resolve bun.ps1 → bun.exe. When Bun is installed via `npm install -g bun`,
|
||||
# Resolve bun.ps1 -> bun.exe. When Bun is installed via `npm install -g bun`,
|
||||
# Get-Command returns a .ps1 wrapper script. A .cmd launcher cannot invoke .ps1
|
||||
# directly — Windows opens the file association dialog instead of executing it.
|
||||
# directly -- Windows opens the file association dialog instead of executing it.
|
||||
# Probe known install paths instead of parsing wrapper scripts.
|
||||
if ($BunBin -and $BunBin -match '\.ps1$') {
|
||||
$resolved = $null
|
||||
@@ -129,7 +129,7 @@ if ($BunBin -and $BunBin -match '\.ps1$') {
|
||||
if (Test-Path $chocoBin) { $resolved = $chocoBin }
|
||||
}
|
||||
if ($resolved) {
|
||||
Write-Dim "Resolved bun.ps1 → $resolved"
|
||||
Write-Dim "Resolved bun.ps1 -> $resolved"
|
||||
$BunBin = $resolved
|
||||
} else {
|
||||
Write-Warn "Bun resolved to .ps1 wrapper ($BunBin). The launcher may not work."
|
||||
@@ -138,11 +138,11 @@ if ($BunBin -and $BunBin -match '\.ps1$') {
|
||||
}
|
||||
Write-OK "Bun: $(& $BunBin --version)"
|
||||
|
||||
# ─── Bun version pre-flight ───────────────────────────────────────────
|
||||
# --- Bun version pre-flight -------------------------------------------
|
||||
# Anthropic builds the native binary with Bun's canary channel; stable
|
||||
# bun.sh trails by one version. Bun < 1.3.14 panics on cli.original.cjs
|
||||
# with "Expected CommonJS module to have a function wrapper". Refuse
|
||||
# early — no npm download / no patch / no late sanity surprise where
|
||||
# early -- no npm download / no patch / no late sanity surprise where
|
||||
# PowerShell's NativeCommandError display buries the friendly message.
|
||||
# Bump $MinBunVersion when Anthropic moves the embedded Bun forward
|
||||
# again.
|
||||
@@ -182,8 +182,8 @@ if (-not $BunVersionOk) {
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ─── ripgrep prerequisite (search/grep tool) ──────────────────────────
|
||||
# Hard prerequisite — without rg the Grep tool inside Claude Code fails.
|
||||
# --- ripgrep prerequisite (search/grep tool) --------------------------
|
||||
# Hard prerequisite -- without rg the Grep tool inside Claude Code fails.
|
||||
|
||||
try {
|
||||
$rgPath = (Get-Command rg -ErrorAction Stop).Source
|
||||
@@ -201,9 +201,9 @@ catch {
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ─── Locate native Bun binary (cli.js source) ──────────────────────────
|
||||
# --- Locate native Bun binary (cli.js source) --------------------------
|
||||
# Source: npm registry (@anthropic-ai/claude-code-win32-<arch>).
|
||||
# Local binary detection is intentionally skipped — see policy note below.
|
||||
# Local binary detection is intentionally skipped -- see policy note below.
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $ClawDir | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path $BinDir | Out-Null
|
||||
@@ -228,12 +228,12 @@ $platformSuffix = "win32-$arch"
|
||||
# out `claude update`, so users never re-run the underlying installers,
|
||||
# and those directories freeze at whatever version was on disk the day
|
||||
# clawgod was first installed. `claude update` (which is now redirected
|
||||
# here) would re-detect the frozen binary forever — never reaching the
|
||||
# here) would re-detect the frozen binary forever -- never reaching the
|
||||
# registry. See INCIDENT_LOG 2026-04-29 entry. The fix is to skip local
|
||||
# detection entirely; the npm tarball is ~60-90 MB compressed, fetched
|
||||
# once per upgrade.
|
||||
|
||||
# npm registry — pull the platform tarball directly via Node.
|
||||
# npm registry -- pull the platform tarball directly via Node.
|
||||
# Avoids depending on `npm` and `tar` being on PATH (older Windows 10
|
||||
# builds lack tar.exe; some PowerShell shims mangle `& npm`). Node is
|
||||
# already a hard prerequisite for the patcher, so reuse it.
|
||||
@@ -247,7 +247,7 @@ if (-not $NativeBin) {
|
||||
$noProxy = $env:NO_PROXY
|
||||
if ($env:HTTPS_PROXY -or $env:HTTP_PROXY) {
|
||||
if ($noProxy -match '(?i)npmjs\.org') {
|
||||
Write-Dim "NO_PROXY includes npmjs.org — using direct fetch"
|
||||
Write-Dim "NO_PROXY includes npmjs.org -- using direct fetch"
|
||||
} elseif (Get-Command npm -ErrorAction SilentlyContinue) {
|
||||
$useNpmFetch = $true
|
||||
} else {
|
||||
@@ -393,9 +393,9 @@ $extractorPath = Join-Path $ClawDir "extract-natives.mjs"
|
||||
* (the official Claude Code native binary).
|
||||
*
|
||||
* Supports:
|
||||
* - Mach-O (macOS) — arm64 + x86_64 thin binaries
|
||||
* - ELF (Linux) — arm64 + x86_64
|
||||
* - PE (Windows) — x86_64 + arm64
|
||||
* - Mach-O (macOS) -- arm64 + x86_64 thin binaries
|
||||
* - ELF (Linux) -- arm64 + x86_64
|
||||
* - PE (Windows) -- x86_64 + arm64
|
||||
*
|
||||
* Usage:
|
||||
* node extract-natives.mjs <binary-path> <output-dir>
|
||||
@@ -404,7 +404,7 @@ $extractorPath = Join-Path $ClawDir "extract-natives.mjs"
|
||||
import { readFileSync, writeFileSync, mkdirSync, existsSync, statSync } from 'fs';
|
||||
import { join, basename } from 'path';
|
||||
|
||||
// ─── Mach-O constants ────────────────────────────────────────────────
|
||||
// --- Mach-O constants ------------------------------------------------
|
||||
|
||||
const MH_MAGIC_64 = 0xfeedfacf; // little-endian 64-bit
|
||||
const LC_SEGMENT_64 = 0x19;
|
||||
@@ -413,14 +413,14 @@ const MH_DYLIB = 6;
|
||||
const CPU_TYPE_X86_64 = 0x01000007;
|
||||
const CPU_TYPE_ARM64 = 0x0100000c;
|
||||
|
||||
// ─── ELF constants ───────────────────────────────────────────────────
|
||||
// --- ELF constants ---------------------------------------------------
|
||||
|
||||
const ELF_MAGIC = Buffer.from([0x7f, 0x45, 0x4c, 0x46]); // 7f 'E' 'L' 'F'
|
||||
const ET_DYN = 3; // shared object
|
||||
const EM_X86_64 = 62;
|
||||
const EM_AARCH64 = 183;
|
||||
|
||||
// ─── PE constants ────────────────────────────────────────────────────
|
||||
// --- PE constants ----------------------------------------------------
|
||||
|
||||
const MZ_MAGIC = Buffer.from([0x4d, 0x5a]); // "MZ"
|
||||
const PE_MAGIC = Buffer.from([0x50, 0x45, 0, 0]); // "PE\0\0"
|
||||
@@ -428,7 +428,7 @@ const IMAGE_FILE_MACHINE_AMD64 = 0x8664;
|
||||
const IMAGE_FILE_MACHINE_ARM64 = 0xaa64;
|
||||
const IMAGE_FILE_DLL = 0x2000;
|
||||
|
||||
// ─── Helpers ─────────────────────────────────────────────────────────
|
||||
// --- Helpers ---------------------------------------------------------
|
||||
|
||||
function archName(format, cputype) {
|
||||
if (format === 'macho') {
|
||||
@@ -451,7 +451,7 @@ function platformSuffix(format, arch) {
|
||||
return `${arch}-${os}`;
|
||||
}
|
||||
|
||||
// ─── Mach-O parser ───────────────────────────────────────────────────
|
||||
// --- Mach-O parser ---------------------------------------------------
|
||||
|
||||
function parseMachODylib(buf, off) {
|
||||
const magic = buf.readUInt32LE(off);
|
||||
@@ -525,7 +525,7 @@ function extractMachODylibs(buf) {
|
||||
return dylibs;
|
||||
}
|
||||
|
||||
// ─── ELF parser ──────────────────────────────────────────────────────
|
||||
// --- ELF parser ------------------------------------------------------
|
||||
|
||||
function parseELFSharedObject(buf, off) {
|
||||
if (buf.length - off < 64) return null;
|
||||
@@ -580,7 +580,7 @@ function extractELFSharedObjects(buf) {
|
||||
return sos;
|
||||
}
|
||||
|
||||
// ─── PE parser ───────────────────────────────────────────────────────
|
||||
// --- PE parser -------------------------------------------------------
|
||||
|
||||
function parsePEDll(buf, off) {
|
||||
if (buf.length - off < 1024) return null;
|
||||
@@ -639,7 +639,7 @@ function extractPEDlls(buf) {
|
||||
return dlls;
|
||||
}
|
||||
|
||||
// ─── Main dispatch ───────────────────────────────────────────────────
|
||||
// --- Main dispatch ---------------------------------------------------
|
||||
|
||||
function detectFormat(buf) {
|
||||
if (buf.readUInt32LE(0) === MH_MAGIC_64) return 'macho';
|
||||
@@ -679,7 +679,7 @@ function identifyDylib(buf, dylib) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ─── cli.js text extraction (Bun standalone) ─────────────────────────
|
||||
// --- cli.js text extraction (Bun standalone) -------------------------
|
||||
// Two anchors: bunfs path (primary, Mach-O/ELF) and cli_after_main_complete
|
||||
// (fallback, used when Windows PE builds omit the bunfs path string).
|
||||
|
||||
@@ -727,7 +727,7 @@ function main() {
|
||||
|
||||
const stat = statSync(binaryPath);
|
||||
if (stat.size < 10 * 1024 * 1024) {
|
||||
console.error(`Binary too small (${stat.size} bytes) — not a native Claude Code binary`);
|
||||
console.error(`Binary too small (${stat.size} bytes) -- not a native Claude Code binary`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -785,7 +785,7 @@ function main() {
|
||||
const data = buf.slice(lib.offset, lib.offset + lib.size);
|
||||
writeFileSync(targetFile, data);
|
||||
|
||||
console.log(` ✓ ${name.padEnd(20)} ${lib.arch.padEnd(6)} ${(lib.size / 1024).toFixed(0).padStart(5)} KB → ${targetFile}`);
|
||||
console.log(` [OK] ${name.padEnd(20)} ${lib.arch.padEnd(6)} ${(lib.size / 1024).toFixed(0).padStart(5)} KB -> ${targetFile}`);
|
||||
summary.extracted.push({ name, platform, size: lib.size });
|
||||
}
|
||||
|
||||
@@ -803,7 +803,7 @@ function main() {
|
||||
main();
|
||||
'@ | Set-Content $extractorPath -Encoding UTF8
|
||||
|
||||
# ─── Extract cli.js + native modules from Bun binary ──────────
|
||||
# --- Extract cli.js + native modules from Bun binary ----------
|
||||
|
||||
$VendorDir = Join-Path $ClawDir "vendor"
|
||||
if (Test-Path $VendorDir) { Remove-Item -Recurse -Force $VendorDir }
|
||||
@@ -821,9 +821,9 @@ if (-not (Test-Path $dstCli)) {
|
||||
Write-Dim "Extracting native modules from $NativeBinLabel ..."
|
||||
& node $extractorPath $NativeBin $VendorDir 2>&1 | ForEach-Object { Write-Host " $_" }
|
||||
|
||||
# Note: keep extractorPath around — repatch.mjs uses it on version drift
|
||||
# Note: keep extractorPath around -- repatch.mjs uses it on version drift
|
||||
|
||||
# ─── Post-process cli.js for Bun runtime ──────────────────────
|
||||
# --- Post-process cli.js for Bun runtime ----------------------
|
||||
|
||||
Write-Dim "Rewriting bunfs paths and IIFE invocation ..."
|
||||
$postProc = Join-Path $ClawDir "post-process.mjs"
|
||||
@@ -864,7 +864,7 @@ if (-not (Test-Path (Join-Path $ClawDir "cli.original.cjs"))) {
|
||||
# Stamp source version so wrapper can detect drift on next launch
|
||||
Set-Content -Path (Join-Path $ClawDir ".source-version") -Value $NativeBinLabel -Encoding ASCII
|
||||
|
||||
# If we pulled the binary from npm into a tmpdir, clean up — extraction
|
||||
# If we pulled the binary from npm into a tmpdir, clean up -- extraction
|
||||
# is done; drift detection only consults %USERPROFILE%\.local\share\claude\versions\.
|
||||
if ($NativeBinTmpDir -and (Test-Path $NativeBinTmpDir)) {
|
||||
Remove-Item -Recurse -Force $NativeBinTmpDir -ErrorAction SilentlyContinue
|
||||
@@ -872,7 +872,7 @@ if ($NativeBinTmpDir -and (Test-Path $NativeBinTmpDir)) {
|
||||
|
||||
Write-OK "cli.original.cjs ready ($NativeBinLabel)"
|
||||
|
||||
# ─── Write re-patch helper (used by wrapper on version drift) ─────────
|
||||
# --- Write re-patch helper (used by wrapper on version drift) ---------
|
||||
|
||||
@'
|
||||
#!/usr/bin/env bun
|
||||
@@ -917,7 +917,7 @@ console.log(`[clawgod] re-patched to ${basename(nativeBin)}`);
|
||||
'@ | Set-Content (Join-Path $ClawDir "repatch.mjs") -Encoding UTF8
|
||||
Write-OK "Re-patch helper installed (repatch.mjs)"
|
||||
|
||||
# ─── Write wrapper (cli.cjs, runs under Bun) ──────────────────
|
||||
# --- Write wrapper (cli.cjs, runs under Bun) ------------------
|
||||
|
||||
@'
|
||||
#!/usr/bin/env bun
|
||||
@@ -928,10 +928,10 @@ const { spawnSync } = require('child_process');
|
||||
|
||||
const clawgodDir = join(homedir(), '.clawgod');
|
||||
|
||||
// Note: drift detection removed — see install.sh wrapper for full notes.
|
||||
// Note: drift detection removed -- see install.sh wrapper for full notes.
|
||||
// `versions/` either doesn't exist (Windows) or doesn't grow on healthy
|
||||
// clawgod installs (we patch out `claude update`), so the check could only
|
||||
// retract a fresh install.ps1 / install.sh upgrade. `claude update` →
|
||||
// retract a fresh install.ps1 / install.sh upgrade. `claude update` ->
|
||||
// install.sh redirect is the single source of truth for version upgrades.
|
||||
|
||||
// One-time migration: earlier wrapper versions set CLAUDE_CONFIG_DIR=~/.clawgod,
|
||||
@@ -984,7 +984,7 @@ if (hasProviderApiKey) {
|
||||
// vLLM / etc.) don't share Anthropic's server-side handling of
|
||||
// x-anthropic-billing-header. That header carries a per-request `cch` field
|
||||
// which Anthropic's own server excludes from prompt-cache key calculation
|
||||
// (via cacheScope:null), but third-party proxies fold into the prefix hash —
|
||||
// (via cacheScope:null), but third-party proxies fold into the prefix hash --
|
||||
// so the cached prefix changes every request and cache hit rate drops to
|
||||
// zero. Auto-disable the header whenever baseURL points away from Anthropic.
|
||||
// Users can force re-enable with CLAUDE_CODE_ATTRIBUTION_HEADER=1 if needed.
|
||||
@@ -1012,8 +1012,8 @@ require('./cli.original.cjs');
|
||||
'@ | Set-Content (Join-Path $ClawDir "cli.cjs") -Encoding UTF8
|
||||
Write-OK "Wrapper created (cli.cjs)"
|
||||
|
||||
# ─── Write universal patcher ──────────────────────────
|
||||
# (Same Node.js patcher as bash version — inline to avoid extra download)
|
||||
# --- Write universal patcher --------------------------
|
||||
# (Same Node.js patcher as bash version -- inline to avoid extra download)
|
||||
|
||||
$patcherCode = @'
|
||||
#!/usr/bin/env node
|
||||
@@ -1030,7 +1030,7 @@ const BACKUP = TARGET + '.bak';
|
||||
|
||||
const patches = [
|
||||
{
|
||||
name: 'USER_TYPE → ant',
|
||||
name: 'USER_TYPE -> ant',
|
||||
pattern: /function ([\w$]+)\(\)\{return"external"\}/g,
|
||||
replacer: (m, fn) => `function ${fn}(){return"ant"}`,
|
||||
sentinel: 'return"external"',
|
||||
@@ -1084,32 +1084,32 @@ const patches = [
|
||||
sentinel: '"tengu_review_bughunter_config"',
|
||||
},
|
||||
{
|
||||
name: 'Logo + brand color → green (RGB dark)',
|
||||
name: 'Logo + brand color -> green (RGB dark)',
|
||||
pattern: /clawd_body:"rgb\(215,119,87\)"/g,
|
||||
replacer: () => 'clawd_body:"rgb(34,197,94)"',
|
||||
},
|
||||
{
|
||||
name: 'Logo + brand color → green (ANSI)',
|
||||
name: 'Logo + brand color -> green (ANSI)',
|
||||
pattern: /clawd_body:"ansi:redBright"/g,
|
||||
replacer: () => 'clawd_body:"ansi:greenBright"',
|
||||
},
|
||||
{
|
||||
name: 'Theme claude color → green (dark)',
|
||||
name: 'Theme claude color -> green (dark)',
|
||||
pattern: /claude:"rgb\(215,119,87\)"/g,
|
||||
replacer: () => 'claude:"rgb(34,197,94)"',
|
||||
},
|
||||
{
|
||||
name: 'Theme claude color → green (light)',
|
||||
name: 'Theme claude color -> green (light)',
|
||||
pattern: /claude:"rgb\(255,153,51\)"/g,
|
||||
replacer: () => 'claude:"rgb(22,163,74)"',
|
||||
},
|
||||
{
|
||||
name: 'Shimmer → green',
|
||||
name: 'Shimmer -> green',
|
||||
pattern: /claudeShimmer:"rgb\(2[34]5,1[45]9,1[12]7\)"/g,
|
||||
replacer: () => 'claudeShimmer:"rgb(74,222,128)"',
|
||||
},
|
||||
{
|
||||
name: 'Shimmer light → green',
|
||||
name: 'Shimmer light -> green',
|
||||
pattern: /claudeShimmer:"rgb\(255,183,101\)"/g,
|
||||
replacer: () => 'claudeShimmer:"rgb(34,197,94)"',
|
||||
},
|
||||
@@ -1124,7 +1124,7 @@ const patches = [
|
||||
replacer: (m, fn) => `function ${fn}(){return!0}`,
|
||||
},
|
||||
{
|
||||
// ≤v2.1.110: let Y=Dq();if(Y!=="firstParty"&&Y!=="anthropicAws")return!1;return/^claude-(opus|sonnet)-4-6/.test(K)
|
||||
// <=v2.1.110: let Y=Dq();if(Y!=="firstParty"&&Y!=="anthropicAws")return!1;return/^claude-(opus|sonnet)-4-6/.test(K)
|
||||
// v2.1.119+: same gate plus extra branches for claude-opus-4-7.
|
||||
// v2.1.139+: gate moved inside function wuH(H){let $=R7(H),q=Wq();if(q!=="firstParty"&&q!=="anthropicAws")return!1;if($.includes("claude-3-")||...)return!0;return!1}
|
||||
// i.e. the `let` lifted to a comma-list before the if; the if-gate
|
||||
@@ -1157,14 +1157,14 @@ const patches = [
|
||||
// arg-quoting; payload must be UTF-16LE base64.
|
||||
const psScript =
|
||||
"$p=if($env:HTTPS_PROXY){$env:HTTPS_PROXY}elseif($env:HTTP_PROXY){$env:HTTP_PROXY}else{$null};" +
|
||||
"$u='https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1';" +
|
||||
"$u='https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1';" +
|
||||
"if($p){iex(irm -Proxy $p $u)}else{iex(irm $u)}";
|
||||
const psB64 = Buffer.from(psScript, 'utf16le').toString('base64');
|
||||
return (
|
||||
prefix +
|
||||
`process.stderr.write("[clawgod] 'claude update' is handled by clawgod self-update.\\n[clawgod] To leave clawgod and use vanilla update: bash ~/.clawgod/install.sh --uninstall\\n[clawgod] Continuing now\\u2026\\n");` +
|
||||
`const _w=process.platform==='win32';` +
|
||||
`const _c=_w?['powershell','-NoProfile','-EncodedCommand','${psB64}']:['bash','-c','curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash'];` +
|
||||
`const _c=_w?['powershell','-NoProfile','-EncodedCommand','${psB64}']:['bash','-c','curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash'];` +
|
||||
`const _r=require('child_process').spawnSync(_c[0],_c.slice(1),{stdio:'inherit'});` +
|
||||
`process.exit(_r.status||0);`
|
||||
);
|
||||
@@ -1172,7 +1172,7 @@ const patches = [
|
||||
sentinel: '.command("update").alias("upgrade")',
|
||||
},
|
||||
{
|
||||
name: 'Hex brand color → green',
|
||||
name: 'Hex brand color -> green',
|
||||
pattern: /#da7756/g,
|
||||
replacer: () => '#22c55e',
|
||||
},
|
||||
@@ -1258,7 +1258,7 @@ for (const p of patches) {
|
||||
if (p.validate) relevant = matches.filter(m => p.validate(m[0], code));
|
||||
if (p.selectIndex !== undefined) relevant = relevant.length > p.selectIndex ? [relevant[p.selectIndex]] : [];
|
||||
if (p.unique && relevant.length > 1) {
|
||||
console.log(` ?? ${p.name} — ${relevant.length} matches (need 1)`);
|
||||
console.log(` ?? ${p.name} -- ${relevant.length} matches (need 1)`);
|
||||
failed++; continue;
|
||||
}
|
||||
if (relevant.length === 0) {
|
||||
@@ -1267,7 +1267,7 @@ for (const p of patches) {
|
||||
const sentinels = Array.isArray(p.sentinel) ? p.sentinel : [p.sentinel];
|
||||
const stillPresent = sentinels.filter((s) => code.includes(s));
|
||||
if (stillPresent.length > 0) {
|
||||
console.log(` XX ${p.name} — regex stale, sentinel still present: ${stillPresent.map((s) => JSON.stringify(s)).join(', ')}`);
|
||||
console.log(` XX ${p.name} -- regex stale, sentinel still present: ${stillPresent.map((s) => JSON.stringify(s)).join(', ')}`);
|
||||
failed++; continue;
|
||||
}
|
||||
console.log(` OK ${p.name} (already applied, sentinel absent)`); applied++; continue;
|
||||
@@ -1275,7 +1275,7 @@ for (const p of patches) {
|
||||
console.log(` !! ${p.name} (0 matches, no sentinel)`); skipped++;
|
||||
continue;
|
||||
}
|
||||
if (verify) { console.log(` -- ${p.name} — not yet applied`); skipped++; continue; }
|
||||
if (verify) { console.log(` -- ${p.name} -- not yet applied`); skipped++; continue; }
|
||||
let count = 0;
|
||||
for (const m of relevant) {
|
||||
const replacement = p.replacer(m[0], ...m.slice(1));
|
||||
@@ -1299,12 +1299,12 @@ console.log(`${'='.repeat(55)}\n`);
|
||||
Set-Content (Join-Path $ClawDir "patch.mjs") $patcherCode -Encoding UTF8
|
||||
Write-OK "Patcher created (patch.mjs)"
|
||||
|
||||
# ─── Apply patches ────────────────────────────────────
|
||||
# --- Apply patches ------------------------------------
|
||||
|
||||
Write-Dim "Applying patches ..."
|
||||
node (Join-Path $ClawDir "patch.mjs")
|
||||
|
||||
# ─── Create default configs ───────────────────────────
|
||||
# --- Create default configs ---------------------------
|
||||
|
||||
$featuresFile = Join-Path $ClawDir "features.json"
|
||||
if (-not (Test-Path $featuresFile)) {
|
||||
@@ -1326,11 +1326,11 @@ if (-not (Test-Path $featuresFile)) {
|
||||
Write-OK "Default features.json created"
|
||||
}
|
||||
|
||||
# ─── Sanity check: ensure user's Bun can actually load cli.original.cjs ──
|
||||
# --- Sanity check: ensure user's Bun can actually load cli.original.cjs --
|
||||
# Anthropic builds the native binary with a bleeding-edge Bun build (e.g.
|
||||
# 1.3.14 while stable still ships 1.3.13). Older Bun crashes loading the
|
||||
# extracted cli.original.cjs with "Expected CommonJS module to have a
|
||||
# function wrapper". Detect this BEFORE we install the launcher — better
|
||||
# function wrapper". Detect this BEFORE we install the launcher -- better
|
||||
# to fail loudly than to leave the user with a launcher that panics on
|
||||
# first invocation.
|
||||
|
||||
@@ -1341,7 +1341,7 @@ $sanityCli = Join-Path $ClawDir "cli.cjs"
|
||||
# this script is piped through `iex`) that terminates BEFORE we even
|
||||
# read $sanityOut. Localize ErrorActionPreference + try/catch so the
|
||||
# panic message reliably lands in $sanityOut and our friendly Write-Err
|
||||
# block runs. Defense-in-depth — pre-flight already blocks Bun < $MinBunVersion;
|
||||
# block runs. Defense-in-depth -- pre-flight already blocks Bun < $MinBunVersion;
|
||||
# this remains for the day Anthropic bumps embedded Bun past our constant.
|
||||
$sanityOut = $null
|
||||
try {
|
||||
@@ -1359,7 +1359,7 @@ if ($sanityOut -match "Expected CommonJS module to have a function wrapper") {
|
||||
Write-Err ""
|
||||
Write-Err " Anthropic builds with Bun's canary channel (currently ~1.3.14), while"
|
||||
Write-Err " bun.sh's main download is on stable (currently 1.3.13). The canary build"
|
||||
Write-Err " is NOT visible on bun.sh's download page — it lives on GitHub Releases"
|
||||
Write-Err " is NOT visible on bun.sh's download page -- it lives on GitHub Releases"
|
||||
Write-Err " and is reachable only via 'bun upgrade --canary'."
|
||||
Write-Err ""
|
||||
Write-Err " If your bun is from bun.sh:"
|
||||
@@ -1372,12 +1372,12 @@ if ($sanityOut -match "Expected CommonJS module to have a function wrapper") {
|
||||
Write-Err " irm https://bun.sh/install.ps1 | iex"
|
||||
Write-Err " bun upgrade --canary"
|
||||
Write-Err ""
|
||||
Write-Err " Then re-run .\install.ps1 — this sanity check will pass."
|
||||
Write-Err " Then re-run .\install.ps1 -- this sanity check will pass."
|
||||
exit 1
|
||||
}
|
||||
Write-OK "Bun loads cli.original.cjs"
|
||||
|
||||
# ─── Replace claude command ───────────────────────────
|
||||
# --- Replace claude command ---------------------------
|
||||
|
||||
# Build launcher content using %USERPROFILE% env var where possible to avoid
|
||||
# encoding issues when the profile path contains non-ASCII characters (e.g.
|
||||
@@ -1392,11 +1392,11 @@ if ($normalizedBunBin.Equals($normalizedUserProfile, [StringComparison]::Ordinal
|
||||
$bunRelative = $normalizedBunBin.Substring($normalizedUserProfile.Length).TrimStart('\', '/')
|
||||
$bunPathInCmd = "%USERPROFILE%\$bunRelative"
|
||||
} else {
|
||||
# Bun outside USERPROFILE (e.g. system-wide install) — fall back to
|
||||
# Bun outside USERPROFILE (e.g. system-wide install) -- fall back to
|
||||
# absolute path since %USERPROFILE%-relative expansion doesn't apply.
|
||||
$bunPathInCmd = $BunBin
|
||||
}
|
||||
$launcherContent = "@echo off`r`nif not exist `"$cliPathInCmd`" (`r`n echo clawgod: cli.cjs not found. Reinstall: irm https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1 ^| iex`r`n exit /b 127`r`n)`r`nif not exist `"$bunPathInCmd`" (`r`n echo clawgod: bun not found at $bunPathInCmd. Install: https://bun.sh/install`r`n exit /b 127`r`n)`r`n`"$bunPathInCmd`" `"$cliPathInCmd`" %*"
|
||||
$launcherContent = "@echo off`r`nif not exist `"$cliPathInCmd`" (`r`n echo clawgod: cli.cjs not found. Reinstall: irm https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1 ^| iex`r`n exit /b 127`r`n)`r`nif not exist `"$bunPathInCmd`" (`r`n echo clawgod: bun not found at $bunPathInCmd. Install: https://bun.sh/install`r`n exit /b 127`r`n)`r`n`"$bunPathInCmd`" `"$cliPathInCmd`" %*"
|
||||
|
||||
# Find and back up original claude
|
||||
$claudeCmd = Join-Path $BinDir "claude.cmd"
|
||||
@@ -1416,13 +1416,13 @@ foreach ($loc in @(
|
||||
# Back up .exe if exists and not already backed up
|
||||
if ($loc -like "*.exe" -and -not (Test-Path $claudeOrigExe)) {
|
||||
Copy-Item $loc $claudeOrigExe -Force
|
||||
Write-OK "Original claude.exe backed up → claude.orig.exe"
|
||||
Write-OK "Original claude.exe backed up -> claude.orig.exe"
|
||||
$originalFound = $true
|
||||
}
|
||||
# Back up .cmd if exists and not already backed up
|
||||
if ($loc -like "*.cmd" -and -not (Test-Path $claudeOrigCmd)) {
|
||||
Copy-Item $loc $claudeOrigCmd -Force
|
||||
Write-OK "Original claude.cmd backed up → claude.orig.cmd"
|
||||
Write-OK "Original claude.cmd backed up -> claude.orig.cmd"
|
||||
$originalFound = $true
|
||||
}
|
||||
# If it's a versions directory, find the latest exe
|
||||
@@ -1430,7 +1430,7 @@ foreach ($loc in @(
|
||||
$latestExe = Get-ChildItem $loc -File | Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
||||
if ($latestExe -and -not (Test-Path $claudeOrigExe)) {
|
||||
Copy-Item $latestExe.FullName $claudeOrigExe -Force
|
||||
Write-OK "Original claude backed up → claude.orig.exe ($($latestExe.Name))"
|
||||
Write-OK "Original claude backed up -> claude.orig.exe ($($latestExe.Name))"
|
||||
$originalFound = $true
|
||||
}
|
||||
}
|
||||
@@ -1448,13 +1448,13 @@ Get-ChildItem $BinDir -Filter "claude.*.exe" -ErrorAction SilentlyContinue |
|
||||
if (Test-Path $claudeExe) {
|
||||
if (-not (Test-Path $claudeOrigExe)) {
|
||||
Rename-Item $claudeExe $claudeOrigExe -Force
|
||||
Write-OK "Renamed claude.exe → claude.orig.exe"
|
||||
Write-OK "Renamed claude.exe -> claude.orig.exe"
|
||||
} else {
|
||||
# Backup already exists — just remove the new claude.exe
|
||||
# Backup already exists -- just remove the new claude.exe
|
||||
try {
|
||||
Remove-Item -Force $claudeExe
|
||||
} catch {
|
||||
# File locked (running process) — rename aside with timestamp
|
||||
# File locked (running process) -- rename aside with timestamp
|
||||
$ts = Get-Date -Format "yyyyMMddHHmmss"
|
||||
Rename-Item $claudeExe "claude.$ts.exe" -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
@@ -1472,9 +1472,9 @@ if (Test-Path $claudeExe) {
|
||||
foreach ($cmd in @("claude", "clawgod")) {
|
||||
$launcherContent | Set-Content (Join-Path $BinDir "$cmd.cmd") -Encoding Default
|
||||
}
|
||||
Write-OK "Commands 'claude' + 'clawgod' → patched"
|
||||
Write-OK "Commands 'claude' + 'clawgod' -> patched"
|
||||
|
||||
# ─── Ensure BinDir is in PATH ─────────────────────────
|
||||
# --- Ensure BinDir is in PATH -------------------------
|
||||
|
||||
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
|
||||
if ($userPath -notlike "*$BinDir*") {
|
||||
@@ -1484,16 +1484,16 @@ if ($userPath -notlike "*$BinDir*") {
|
||||
Write-Dim "(restart terminal for PATH to take effect)"
|
||||
}
|
||||
|
||||
# ─── Done ─────────────────────────────────────────────
|
||||
# --- Done ---------------------------------------------
|
||||
|
||||
Write-Host ""
|
||||
Write-Host " ClawGod installed!" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Dim " claude — Start patched Claude Code (green logo)"
|
||||
Write-Dim " claude.orig — Run original unpatched Claude Code"
|
||||
Write-Dim " claude -- Start patched Claude Code (green logo)"
|
||||
Write-Dim " claude.orig -- Run original unpatched Claude Code"
|
||||
Write-Host ""
|
||||
Write-Dim " Updates: 'claude update' is patched to route through this installer."
|
||||
Write-Dim " Just run it as usual — pulls latest Anthropic release + re-patches"
|
||||
Write-Dim " Just run it as usual -- pulls latest Anthropic release + re-patches"
|
||||
Write-Dim " in one step. To leave clawgod and use vanilla update:"
|
||||
Write-Dim " bash ~/.clawgod/install.sh --uninstall"
|
||||
Write-Host ""
|
||||
@@ -1505,6 +1505,7 @@ Write-Host ""
|
||||
Write-Dim " If 'claude' panics with 'Expected CommonJS module to have a function wrapper',"
|
||||
Write-Dim " your Bun lags Anthropic's embedded Bun. Upgrade with one of:"
|
||||
Write-Dim " bun upgrade --canary (if installed from bun.sh)"
|
||||
Write-Dim " scoop update bun (scoop — may lag stable)"
|
||||
Write-Dim " scoop update bun (scoop -- may lag stable)"
|
||||
Write-Dim " irm https://bun.sh/install.ps1 | iex (re-install latest)"
|
||||
Write-Host ""
|
||||
|
||||
|
||||
+111
-110
@@ -1,16 +1,16 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# ─────────────────────────────────────────────────────────
|
||||
# ---------------------------------------------------------
|
||||
# ClawGod Installer
|
||||
#
|
||||
# Downloads Claude Code from npm, applies patches, replaces claude command
|
||||
#
|
||||
# 用法:
|
||||
# Usage:
|
||||
# curl -fsSL https://raw.githubusercontent.com/0Chencc/clawgod/main/install.sh | bash
|
||||
# # 或
|
||||
# # or
|
||||
# bash install.sh [--version 2.1.89]
|
||||
# ─────────────────────────────────────────────────────────
|
||||
# ---------------------------------------------------------
|
||||
|
||||
CLAWGOD_DIR="$HOME/.clawgod"
|
||||
BIN_DIR="$HOME/.local/bin"
|
||||
@@ -32,26 +32,26 @@ DIM='\033[2m'
|
||||
BOLD='\033[1m'
|
||||
NC='\033[0m'
|
||||
|
||||
info() { echo -e " ${GREEN}✓${NC} $1"; }
|
||||
warn() { echo -e " ${RED}✗${NC} $1"; }
|
||||
info() { echo -e " ${GREEN}[OK]${NC} $1"; }
|
||||
warn() { echo -e " ${RED}[X]${NC} $1"; }
|
||||
dim() { echo -e " ${DIM}$1${NC}"; }
|
||||
|
||||
echo ""
|
||||
echo -e "${BOLD} ClawGod Installer${NC}"
|
||||
echo ""
|
||||
|
||||
# ─── Uninstall ─────────────────────────────────────────
|
||||
# --- Uninstall -----------------------------------------
|
||||
|
||||
if [ "$UNINSTALL" = "1" ]; then
|
||||
CLAUDE_BIN=$(command -v claude 2>/dev/null || true)
|
||||
for DIR in "${CLAUDE_BIN:+$(dirname "$CLAUDE_BIN")}" "$BIN_DIR"; do
|
||||
[ -z "$DIR" ] && continue
|
||||
if [ -e "$DIR/claude.orig" ]; then
|
||||
# Has backup — restore it
|
||||
# Has backup -- restore it
|
||||
mv "$DIR/claude.orig" "$DIR/claude"
|
||||
info "Original claude restored ($DIR/claude)"
|
||||
elif [ -f "$DIR/claude" ] && grep -q "clawgod" "$DIR/claude" 2>/dev/null; then
|
||||
# Our launcher, no backup — remove it (otherwise it points to deleted cli.js)
|
||||
# Our launcher, no backup -- remove it (otherwise it points to deleted cli.js)
|
||||
rm -f "$DIR/claude"
|
||||
info "Removed ClawGod launcher ($DIR/claude)"
|
||||
fi
|
||||
@@ -70,7 +70,7 @@ if [ "$UNINSTALL" = "1" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ─── Prerequisites ─────────────────────────────────────
|
||||
# --- Prerequisites -------------------------------------
|
||||
|
||||
if ! command -v node &>/dev/null; then
|
||||
warn "Node.js is required (>= 18) for the patcher. Install from https://nodejs.org"
|
||||
@@ -83,7 +83,7 @@ if [ "$NODE_VERSION" -lt 18 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ─── Ensure Bun (runtime that executes the patched cli.js) ─────────────
|
||||
# --- Ensure Bun (runtime that executes the patched cli.js) -------------
|
||||
|
||||
BUN_BIN=""
|
||||
if command -v bun &>/dev/null; then
|
||||
@@ -101,11 +101,11 @@ else
|
||||
fi
|
||||
info "Bun: $($BUN_BIN --version)"
|
||||
|
||||
# ─── Bun version pre-flight ───────────────────────────────────────────
|
||||
# --- Bun version pre-flight -------------------------------------------
|
||||
# Anthropic builds the native binary with Bun's canary channel; stable
|
||||
# bun.sh trails by one version. Bun < 1.3.14 panics on cli.original.cjs
|
||||
# with "Expected CommonJS module to have a function wrapper". Refuse
|
||||
# early — no npm download / no patch / no late sanity surprise.
|
||||
# early -- no npm download / no patch / no late sanity surprise.
|
||||
# Bump MIN_BUN_VERSION when Anthropic moves the embedded Bun forward
|
||||
# again (track via 'bun upgrade --canary' on a runner + smoke test).
|
||||
|
||||
@@ -124,18 +124,18 @@ if [ -z "$BUN_VERSION_NUM" ] \
|
||||
warn " Upgrade with one of:"
|
||||
warn " bun upgrade --canary (if installed via curl/install.sh)"
|
||||
warn " brew upgrade bun (homebrew)"
|
||||
warn " scoop uninstall bun && \\ (scoop — shim blocks self-replace)"
|
||||
warn " scoop uninstall bun && \\ (scoop -- shim blocks self-replace)"
|
||||
warn " irm https://bun.sh/install.ps1 | iex && bun upgrade --canary"
|
||||
warn ""
|
||||
warn " Then re-run this installer."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ─── ripgrep prerequisite (search/grep tool) ──────────────────────────
|
||||
# --- ripgrep prerequisite (search/grep tool) --------------------------
|
||||
# Without rg the Grep tool inside Claude Code fails. Bun-bundled ripgrep
|
||||
# is only reachable from inside the standalone executable; running the
|
||||
# extracted cli.js under Bun runtime means we depend on system rg.
|
||||
# This is a hard prerequisite — refuse to install otherwise.
|
||||
# This is a hard prerequisite -- refuse to install otherwise.
|
||||
|
||||
if ! command -v rg &>/dev/null; then
|
||||
warn "ripgrep (rg) is required but not found in PATH."
|
||||
@@ -152,11 +152,11 @@ if ! command -v rg &>/dev/null; then
|
||||
fi
|
||||
info "ripgrep: $(rg --version | head -1)"
|
||||
|
||||
# ─── Locate native Bun binary (cli.js source) ──────────────────────────
|
||||
# --- Locate native Bun binary (cli.js source) --------------------------
|
||||
# v2.1.113+ ships a Bun standalone executable as the only canonical form.
|
||||
# We extract cli.js text from this binary, patch it, then run via Bun
|
||||
# runtime. Source: npm registry (@anthropic-ai/claude-code-<platform>).
|
||||
# Local binary detection is intentionally skipped — see policy note below.
|
||||
# Local binary detection is intentionally skipped -- see policy note below.
|
||||
|
||||
mkdir -p "$CLAWGOD_DIR" "$BIN_DIR"
|
||||
|
||||
@@ -172,7 +172,7 @@ NATIVE_BIN_TMPDIR=""
|
||||
# `claude update`, so users never re-run `npm install -g` / `bun add -g`.
|
||||
# Both directories freeze at whatever version was on disk the day clawgod
|
||||
# was first installed, and `claude update` (which is now redirected here)
|
||||
# would re-detect that frozen binary forever — never reaching the
|
||||
# would re-detect that frozen binary forever -- never reaching the
|
||||
# registry. See INCIDENT_LOG 2026-04-29 entry. The fix is to skip local
|
||||
# detection entirely; the npm tarball is ~60-90 MB compressed, fetched
|
||||
# once per upgrade, and npm's HTTP cache keeps repeats fast.
|
||||
@@ -254,9 +254,9 @@ cat > "$CLAWGOD_DIR/extract-natives.mjs" << 'EXTRACTOR_EOF'
|
||||
* (the official Claude Code native binary).
|
||||
*
|
||||
* Supports:
|
||||
* - Mach-O (macOS) — arm64 + x86_64 thin binaries
|
||||
* - ELF (Linux) — arm64 + x86_64
|
||||
* - PE (Windows) — x86_64 + arm64
|
||||
* - Mach-O (macOS) -- arm64 + x86_64 thin binaries
|
||||
* - ELF (Linux) -- arm64 + x86_64
|
||||
* - PE (Windows) -- x86_64 + arm64
|
||||
*
|
||||
* Usage:
|
||||
* node extract-natives.mjs <binary-path> <output-dir>
|
||||
@@ -265,7 +265,7 @@ cat > "$CLAWGOD_DIR/extract-natives.mjs" << 'EXTRACTOR_EOF'
|
||||
import { readFileSync, writeFileSync, mkdirSync, existsSync, statSync } from 'fs';
|
||||
import { join, basename } from 'path';
|
||||
|
||||
// ─── Mach-O constants ────────────────────────────────────────────────
|
||||
// --- Mach-O constants ------------------------------------------------
|
||||
|
||||
const MH_MAGIC_64 = 0xfeedfacf; // little-endian 64-bit
|
||||
const LC_SEGMENT_64 = 0x19;
|
||||
@@ -274,14 +274,14 @@ const MH_DYLIB = 6;
|
||||
const CPU_TYPE_X86_64 = 0x01000007;
|
||||
const CPU_TYPE_ARM64 = 0x0100000c;
|
||||
|
||||
// ─── ELF constants ───────────────────────────────────────────────────
|
||||
// --- ELF constants ---------------------------------------------------
|
||||
|
||||
const ELF_MAGIC = Buffer.from([0x7f, 0x45, 0x4c, 0x46]); // 7f 'E' 'L' 'F'
|
||||
const ET_DYN = 3; // shared object
|
||||
const EM_X86_64 = 62;
|
||||
const EM_AARCH64 = 183;
|
||||
|
||||
// ─── PE constants ────────────────────────────────────────────────────
|
||||
// --- PE constants ----------------------------------------------------
|
||||
|
||||
const MZ_MAGIC = Buffer.from([0x4d, 0x5a]); // "MZ"
|
||||
const PE_MAGIC = Buffer.from([0x50, 0x45, 0, 0]); // "PE\0\0"
|
||||
@@ -289,7 +289,7 @@ const IMAGE_FILE_MACHINE_AMD64 = 0x8664;
|
||||
const IMAGE_FILE_MACHINE_ARM64 = 0xaa64;
|
||||
const IMAGE_FILE_DLL = 0x2000;
|
||||
|
||||
// ─── Helpers ─────────────────────────────────────────────────────────
|
||||
// --- Helpers ---------------------------------------------------------
|
||||
|
||||
function archName(format, cputype) {
|
||||
if (format === 'macho') {
|
||||
@@ -312,7 +312,7 @@ function platformSuffix(format, arch) {
|
||||
return `${arch}-${os}`;
|
||||
}
|
||||
|
||||
// ─── Mach-O parser ───────────────────────────────────────────────────
|
||||
// --- Mach-O parser ---------------------------------------------------
|
||||
|
||||
function parseMachODylib(buf, off) {
|
||||
const magic = buf.readUInt32LE(off);
|
||||
@@ -386,7 +386,7 @@ function extractMachODylibs(buf) {
|
||||
return dylibs;
|
||||
}
|
||||
|
||||
// ─── ELF parser ──────────────────────────────────────────────────────
|
||||
// --- ELF parser ------------------------------------------------------
|
||||
|
||||
function parseELFSharedObject(buf, off) {
|
||||
if (buf.length - off < 64) return null;
|
||||
@@ -441,7 +441,7 @@ function extractELFSharedObjects(buf) {
|
||||
return sos;
|
||||
}
|
||||
|
||||
// ─── PE parser ───────────────────────────────────────────────────────
|
||||
// --- PE parser -------------------------------------------------------
|
||||
|
||||
function parsePEDll(buf, off) {
|
||||
if (buf.length - off < 1024) return null;
|
||||
@@ -500,7 +500,7 @@ function extractPEDlls(buf) {
|
||||
return dlls;
|
||||
}
|
||||
|
||||
// ─── Main dispatch ───────────────────────────────────────────────────
|
||||
// --- Main dispatch ---------------------------------------------------
|
||||
|
||||
function detectFormat(buf) {
|
||||
if (buf.readUInt32LE(0) === MH_MAGIC_64) return 'macho';
|
||||
@@ -540,7 +540,7 @@ function identifyDylib(buf, dylib) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ─── cli.js text extraction (Bun standalone) ─────────────────────────
|
||||
// --- cli.js text extraction (Bun standalone) -------------------------
|
||||
//
|
||||
// Two-stage anchor strategy:
|
||||
// 1. Primary: Bun's bunfs path marker, observed in Mach-O / ELF builds.
|
||||
@@ -575,7 +575,7 @@ function extractCliJs(buf) {
|
||||
fnStart = candidate;
|
||||
}
|
||||
|
||||
// Resolve the IIFE close — search forward from fnStart so that we close
|
||||
// Resolve the IIFE close -- search forward from fnStart so that we close
|
||||
// the wrapper we actually opened, regardless of which anchor located it.
|
||||
const tailFromFn = buf.indexOf(CLI_TAIL_MARKER, fnStart);
|
||||
if (tailFromFn === -1) return null;
|
||||
@@ -600,7 +600,7 @@ function main() {
|
||||
|
||||
const stat = statSync(binaryPath);
|
||||
if (stat.size < 10 * 1024 * 1024) {
|
||||
console.error(`Binary too small (${stat.size} bytes) — not a native Claude Code binary`);
|
||||
console.error(`Binary too small (${stat.size} bytes) -- not a native Claude Code binary`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -624,7 +624,7 @@ function main() {
|
||||
mkdirSync(outputDir, { recursive: true });
|
||||
const out = join(outputDir, 'cli.original.js');
|
||||
writeFileSync(out, js);
|
||||
console.log(` cli.js ${(js.length / 1024 / 1024).toFixed(2)} MB → ${out}`);
|
||||
console.log(` cli.js ${(js.length / 1024 / 1024).toFixed(2)} MB -> ${out}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -658,7 +658,7 @@ function main() {
|
||||
const data = buf.slice(lib.offset, lib.offset + lib.size);
|
||||
writeFileSync(targetFile, data);
|
||||
|
||||
console.log(` ✓ ${name.padEnd(20)} ${lib.arch.padEnd(6)} ${(lib.size / 1024).toFixed(0).padStart(5)} KB → ${targetFile}`);
|
||||
console.log(` [OK] ${name.padEnd(20)} ${lib.arch.padEnd(6)} ${(lib.size / 1024).toFixed(0).padStart(5)} KB -> ${targetFile}`);
|
||||
summary.extracted.push({ name, platform, size: lib.size });
|
||||
}
|
||||
|
||||
@@ -676,7 +676,7 @@ function main() {
|
||||
main();
|
||||
EXTRACTOR_EOF
|
||||
|
||||
# ─── Extract cli.js + native modules from Bun binary ──────────
|
||||
# --- Extract cli.js + native modules from Bun binary ----------
|
||||
# Note: extract-natives.mjs and post-process.mjs are kept around (NOT deleted)
|
||||
# so the wrapper's drift detector can re-run them when the user upgrades
|
||||
# their native Claude binary.
|
||||
@@ -695,7 +695,7 @@ fi
|
||||
dim "Extracting native modules from $(echo "$NATIVE_BIN_LABEL") ..."
|
||||
node "$CLAWGOD_DIR/extract-natives.mjs" "$NATIVE_BIN" "$VENDOR_DIR" 2>&1 | while IFS= read -r line; do echo " $line"; done || true
|
||||
|
||||
# ─── Post-process cli.js for Bun runtime ──────────────────────
|
||||
# --- Post-process cli.js for Bun runtime ----------------------
|
||||
# 1. Rewrite /$bunfs/root/X.node paths to point at extracted vendor modules
|
||||
# 2. Rewrite build-time /home/runner/.../*.ts URLs (used by ripgrep,
|
||||
# sandbox, computer-use, etc. for asset resolution) to __filename so
|
||||
@@ -715,14 +715,14 @@ const dst = `${here}/cli.original.cjs`;
|
||||
|
||||
let code = readFileSync(src, 'utf8');
|
||||
|
||||
// (1) bunfs .node module paths → runtime vendor lookup
|
||||
// (1) bunfs .node module paths -> runtime vendor lookup
|
||||
code = code.replace(
|
||||
/require\(['"](\/\$bunfs\/root\/([\w-]+)\.node)['"]\)/g,
|
||||
(m, _full, name) =>
|
||||
`require(require('path').join(__dirname,'vendor',${JSON.stringify(name)},\`\${process.arch==='arm64'?'arm64':'x64'}-\${process.platform==='darwin'?'darwin':process.platform==='linux'?'linux':'win32'}\`,${JSON.stringify(name + '.node')}))`,
|
||||
);
|
||||
|
||||
// (2) build-time fileURLToPath() leaks → use cli.cjs's own __filename
|
||||
// (2) build-time fileURLToPath() leaks -> use cli.cjs's own __filename
|
||||
code = code.replace(
|
||||
/[\w$]+\.fileURLToPath\("file:\/\/\/home\/runner\/work\/claude-cli-internal\/claude-cli-internal\/[^"]*"\)/g,
|
||||
() => '__filename',
|
||||
@@ -741,7 +741,7 @@ node "$CLAWGOD_DIR/post-process.mjs" 2>&1 | while IFS= read -r line; do echo "
|
||||
# Stamp the source version so the wrapper can detect drift on next launch
|
||||
echo "$NATIVE_BIN_LABEL" > "$CLAWGOD_DIR/.source-version"
|
||||
|
||||
# If we pulled the binary from npm into a tmpdir, clean it up now —
|
||||
# If we pulled the binary from npm into a tmpdir, clean it up now --
|
||||
# extraction is done, drift detection only consults ~/.local/share/claude/versions/.
|
||||
if [ -n "$NATIVE_BIN_TMPDIR" ]; then
|
||||
rm -rf "$NATIVE_BIN_TMPDIR"
|
||||
@@ -749,7 +749,7 @@ fi
|
||||
|
||||
info "cli.original.cjs ready ($NATIVE_BIN_LABEL)"
|
||||
|
||||
# ─── Write re-patch helper (used by wrapper on version drift) ─────────
|
||||
# --- Write re-patch helper (used by wrapper on version drift) ---------
|
||||
|
||||
cat > "$CLAWGOD_DIR/repatch.mjs" << 'REPATCH_EOF'
|
||||
#!/usr/bin/env bun
|
||||
@@ -798,7 +798,7 @@ REPATCH_EOF
|
||||
chmod +x "$CLAWGOD_DIR/repatch.mjs"
|
||||
info "Re-patch helper installed (repatch.mjs)"
|
||||
|
||||
# ─── Write wrapper (cli.cjs, runs under Bun) ──────────────────
|
||||
# --- Write wrapper (cli.cjs, runs under Bun) ------------------
|
||||
|
||||
cat > "$CLAWGOD_DIR/cli.cjs" << 'WRAPPER_EOF'
|
||||
#!/usr/bin/env bun
|
||||
@@ -819,8 +819,8 @@ const clawgodDir = join(homedir(), '.clawgod');
|
||||
// on a healthy clawgod install.
|
||||
// In practice the block was reading a directory that never changes, but
|
||||
// could *retract* a fresher version that install.sh just pulled from npm
|
||||
// registry — putting users into a re-patch loop. Upgrades now go through
|
||||
// the patched `claude update` → install.sh redirect, which always pulls
|
||||
// registry -- putting users into a re-patch loop. Upgrades now go through
|
||||
// the patched `claude update` -> install.sh redirect, which always pulls
|
||||
// the latest from npm.
|
||||
|
||||
// One-time migration: earlier wrapper versions set CLAUDE_CONFIG_DIR=~/.clawgod,
|
||||
@@ -873,7 +873,7 @@ if (hasProviderApiKey) {
|
||||
// vLLM / etc.) don't share Anthropic's server-side handling of
|
||||
// x-anthropic-billing-header. That header carries a per-request `cch` field
|
||||
// which Anthropic's own server excludes from prompt-cache key calculation
|
||||
// (via cacheScope:null), but third-party proxies fold into the prefix hash —
|
||||
// (via cacheScope:null), but third-party proxies fold into the prefix hash --
|
||||
// so the cached prefix changes every request and cache hit rate drops to
|
||||
// zero. Auto-disable the header whenever baseURL points away from Anthropic.
|
||||
// Users can force re-enable with CLAUDE_CODE_ATTRIBUTION_HEADER=1 if needed.
|
||||
@@ -904,12 +904,12 @@ WRAPPER_EOF
|
||||
chmod +x "$CLAWGOD_DIR/cli.cjs"
|
||||
info "Wrapper created (cli.cjs)"
|
||||
|
||||
# ─── Write universal patcher ───────────────────────────
|
||||
# --- Write universal patcher ---------------------------
|
||||
|
||||
cat > "$CLAWGOD_DIR/patch.mjs" << 'PATCHER_EOF'
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* ClawGod Universal Patcher — 正则模式匹配, 跨版本兼容
|
||||
* ClawGod Universal Patcher -- Regex matching, cross-version compatibility
|
||||
*/
|
||||
import { readFileSync, writeFileSync, existsSync, copyFileSync } from 'fs';
|
||||
import { join, dirname } from 'path';
|
||||
@@ -919,11 +919,11 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const TARGET = join(__dirname, 'cli.original.cjs');
|
||||
const BACKUP = TARGET + '.bak';
|
||||
|
||||
// ─── Regex-based patches (version-agnostic) ──────────────
|
||||
// --- Regex-based patches (version-agnostic) --------------
|
||||
|
||||
const patches = [
|
||||
{
|
||||
name: 'USER_TYPE → ant',
|
||||
name: 'USER_TYPE -> ant',
|
||||
pattern: /function ([\w$]+)\(\)\{return"external"\}/g,
|
||||
replacer: (m, fn) => `function ${fn}(){return"ant"}`,
|
||||
sentinel: 'return"external"',
|
||||
@@ -975,8 +975,8 @@ const patches = [
|
||||
sentinel: 'name:"ultraplan"',
|
||||
},
|
||||
{
|
||||
// ≤v2.1.110: function X(){return Y("tengu_review_bughunter_config",null)?.enabled===!0}
|
||||
// v2.1.119+: function X(){return Y("tengu_review_bughunter_config",null)} — getter
|
||||
// <=v2.1.110: function X(){return Y("tengu_review_bughunter_config",null)?.enabled===!0}
|
||||
// v2.1.119+: function X(){return Y("tengu_review_bughunter_config",null)} -- getter
|
||||
// and the gate at function Z(){return X()?.enabled===!0} elsewhere.
|
||||
// We override the getter to always return {enabled:!0}.
|
||||
name: 'Ultrareview enable',
|
||||
@@ -995,7 +995,7 @@ const patches = [
|
||||
replacer: (m, fn) => `function ${fn}(){return!0}`,
|
||||
},
|
||||
{
|
||||
// ≤v2.1.110: let Y=Dq();if(Y!=="firstParty"&&Y!=="anthropicAws")return!1;return/^claude-(opus|sonnet)-4-6/.test(K)
|
||||
// <=v2.1.110: let Y=Dq();if(Y!=="firstParty"&&Y!=="anthropicAws")return!1;return/^claude-(opus|sonnet)-4-6/.test(K)
|
||||
// v2.1.119+: same gate plus extra branches for claude-opus-4-7.
|
||||
// v2.1.139+: gate moved inside function wuH(H){let $=R7(H),q=Wq();if(q!=="firstParty"&&q!=="anthropicAws")return!1;if($.includes("claude-3-")||...)return!0;return!1}
|
||||
// i.e. the `let` lifted to a comma-list before the if; the if-gate
|
||||
@@ -1008,7 +1008,7 @@ const patches = [
|
||||
},
|
||||
{
|
||||
// CLI subcommand registered via commander chain:
|
||||
// .command("update").alias("upgrade").description("…").action(async()=>{…})
|
||||
// .command("update").alias("upgrade").description("...").action(async()=>{...})
|
||||
// The original action's update path is broken under clawgod: detectInstallType()
|
||||
// returns "unknown" because the launcher hides our cli.cjs from upstream's
|
||||
// path heuristics, and the unknown-fallback branch on macOS overwrites
|
||||
@@ -1038,59 +1038,59 @@ const patches = [
|
||||
// arg-quoting; payload must be UTF-16LE base64.
|
||||
const psScript =
|
||||
"$p=if($env:HTTPS_PROXY){$env:HTTPS_PROXY}elseif($env:HTTP_PROXY){$env:HTTP_PROXY}else{$null};" +
|
||||
"$u='https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1';" +
|
||||
"$u='https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1';" +
|
||||
"if($p){iex(irm -Proxy $p $u)}else{iex(irm $u)}";
|
||||
const psB64 = Buffer.from(psScript, 'utf16le').toString('base64');
|
||||
return (
|
||||
prefix +
|
||||
`process.stderr.write("[clawgod] 'claude update' is handled by clawgod self-update.\\n[clawgod] To leave clawgod and use vanilla update: bash ~/.clawgod/install.sh --uninstall\\n[clawgod] Continuing now\\u2026\\n");` +
|
||||
`const _w=process.platform==='win32';` +
|
||||
`const _c=_w?['powershell','-NoProfile','-EncodedCommand','${psB64}']:['bash','-c','curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash'];` +
|
||||
`const _c=_w?['powershell','-NoProfile','-EncodedCommand','${psB64}']:['bash','-c','curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash'];` +
|
||||
`const _r=require('child_process').spawnSync(_c[0],_c.slice(1),{stdio:'inherit'});` +
|
||||
`process.exit(_r.status||0);`
|
||||
);
|
||||
},
|
||||
sentinel: '.command("update").alias("upgrade")',
|
||||
},
|
||||
// ── 绿色主题 (patch 标识) ──
|
||||
// -- Green Theme (patch Identifier) --
|
||||
|
||||
{
|
||||
name: 'Logo + brand color → green (RGB dark)',
|
||||
name: 'Logo + brand color -> green (RGB dark)',
|
||||
pattern: /clawd_body:"rgb\(215,119,87\)"/g,
|
||||
replacer: () => 'clawd_body:"rgb(34,197,94)"',
|
||||
},
|
||||
{
|
||||
name: 'Logo + brand color → green (ANSI)',
|
||||
name: 'Logo + brand color -> green (ANSI)',
|
||||
pattern: /clawd_body:"ansi:redBright"/g,
|
||||
replacer: () => 'clawd_body:"ansi:greenBright"',
|
||||
},
|
||||
{
|
||||
name: 'Theme claude color → green (dark)',
|
||||
name: 'Theme claude color -> green (dark)',
|
||||
pattern: /claude:"rgb\(215,119,87\)"/g,
|
||||
replacer: () => 'claude:"rgb(34,197,94)"',
|
||||
},
|
||||
{
|
||||
name: 'Theme claude color → green (light)',
|
||||
name: 'Theme claude color -> green (light)',
|
||||
pattern: /claude:"rgb\(255,153,51\)"/g,
|
||||
replacer: () => 'claude:"rgb(22,163,74)"',
|
||||
},
|
||||
{
|
||||
name: 'Shimmer → green',
|
||||
name: 'Shimmer -> green',
|
||||
pattern: /claudeShimmer:"rgb\(2[34]5,1[45]9,1[12]7\)"/g,
|
||||
replacer: () => 'claudeShimmer:"rgb(74,222,128)"',
|
||||
},
|
||||
{
|
||||
name: 'Shimmer light → green',
|
||||
name: 'Shimmer light -> green',
|
||||
pattern: /claudeShimmer:"rgb\(255,183,101\)"/g,
|
||||
replacer: () => 'claudeShimmer:"rgb(34,197,94)"',
|
||||
},
|
||||
{
|
||||
name: 'Hex brand color → green',
|
||||
name: 'Hex brand color -> green',
|
||||
pattern: /#da7756/g,
|
||||
replacer: () => '#22c55e',
|
||||
},
|
||||
|
||||
// ── 限制移除 ──
|
||||
// -- Remove Restrictions --
|
||||
|
||||
{
|
||||
name: 'Remove CYBER_RISK_INSTRUCTION',
|
||||
@@ -1119,11 +1119,11 @@ const patches = [
|
||||
optional: true,
|
||||
},
|
||||
|
||||
// ── 消息过滤 ──
|
||||
// -- Message Filtering --
|
||||
|
||||
{
|
||||
// v2.1.88-~v2.1.91: fn()!=="ant"){if(q.attachment.type==="hook_additional_context"...
|
||||
// v2.1.92+ : fn()!=="ant"&&paY.has(q.attachment.type) — paY is an empty Set
|
||||
// v2.1.92+ : fn()!=="ant"&&paY.has(q.attachment.type) -- paY is an empty Set
|
||||
// in v2.1.110, so this filter is effectively a no-op; patch anyway
|
||||
// to guard against paY being populated in future versions.
|
||||
name: 'Attachment filter bypass',
|
||||
@@ -1132,7 +1132,7 @@ const patches = [
|
||||
optional: true, // filter may be removed entirely in future versions
|
||||
},
|
||||
{
|
||||
// Legacy (≤v2.1.91) ternary form: fn()!=="ant"?tRY(_,sRY(K)):K
|
||||
// Legacy (<=v2.1.91) ternary form: fn()!=="ant"?tRY(_,sRY(K)):K
|
||||
name: 'Message list filter bypass (legacy ternary)',
|
||||
pattern: /([\w$]+)\(\)!=="ant"\?([\w$]+)\(([\w$]+),([\w$]+)\(([\w$]+)\)\):([\w$]+)/g,
|
||||
replacer: (m, fn, tRY, underscore, sRY, K, fallback) => fallback,
|
||||
@@ -1148,7 +1148,7 @@ const patches = [
|
||||
},
|
||||
];
|
||||
|
||||
// ─── Main ─────────────────────────────────────────────────
|
||||
// --- Main -------------------------------------------------
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const dryRun = args.includes('--dry-run');
|
||||
@@ -1156,14 +1156,14 @@ const verify = args.includes('--verify');
|
||||
const revert = args.includes('--revert');
|
||||
|
||||
if (revert) {
|
||||
if (!existsSync(BACKUP)) { console.error('❌ No backup found'); process.exit(1); }
|
||||
if (!existsSync(BACKUP)) { console.error('[X] No backup found'); process.exit(1); }
|
||||
copyFileSync(BACKUP, TARGET);
|
||||
console.log('✅ Reverted from backup');
|
||||
console.log('[OK] Reverted from backup');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!existsSync(TARGET)) {
|
||||
console.error('❌ Target not found:', TARGET);
|
||||
console.error('[X] Target not found:', TARGET);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -1174,11 +1174,11 @@ const origSize = code.length;
|
||||
const verMatch = code.match(/Version:\s*([\d.]+)/);
|
||||
const version = verMatch ? verMatch[1] : 'unknown';
|
||||
|
||||
console.log(`\n${'═'.repeat(55)}`);
|
||||
console.log(`\n${'='.repeat(55)}`);
|
||||
console.log(` ClawGod (universal)`);
|
||||
console.log(` Target: cli.original.cjs (v${version})`);
|
||||
console.log(` Mode: ${dryRun ? 'DRY RUN' : verify ? 'VERIFY' : 'APPLY'}`);
|
||||
console.log(`${'═'.repeat(55)}\n`);
|
||||
console.log(`${'='.repeat(55)}\n`);
|
||||
|
||||
let applied = 0, skipped = 0, failed = 0;
|
||||
|
||||
@@ -1196,17 +1196,17 @@ for (const p of patches) {
|
||||
relevant = relevant.length > p.selectIndex ? [relevant[p.selectIndex]] : [];
|
||||
}
|
||||
|
||||
// Uniqueness check — skip when 0 so the sentinel / already-applied
|
||||
// Uniqueness check -- skip when 0 so the sentinel / already-applied
|
||||
// fallthrough can handle it; only fail on >1 (ambiguous).
|
||||
if (p.unique && relevant.length > 1) {
|
||||
console.log(` ⚠️ ${p.name} — ${relevant.length} matches, skipping (need 1)`);
|
||||
console.log(` ! ${p.name} -- ${relevant.length} matches, skipping (need 1)`);
|
||||
failed++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (relevant.length === 0) {
|
||||
if (p.optional) {
|
||||
console.log(` ⏭ ${p.name} (not present in this version)`);
|
||||
console.log(` >> ${p.name} (not present in this version)`);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
@@ -1217,21 +1217,21 @@ for (const p of patches) {
|
||||
const sentinels = Array.isArray(p.sentinel) ? p.sentinel : [p.sentinel];
|
||||
const stillPresent = sentinels.filter((s) => code.includes(s));
|
||||
if (stillPresent.length > 0) {
|
||||
console.log(` ❌ ${p.name} — regex stale, sentinel still in source: ${stillPresent.map((s) => JSON.stringify(s)).join(', ')}`);
|
||||
console.log(` [X] ${p.name} -- regex stale, sentinel still in source: ${stillPresent.map((s) => JSON.stringify(s)).join(', ')}`);
|
||||
failed++;
|
||||
continue;
|
||||
}
|
||||
console.log(` ✅ ${p.name} (already applied, sentinel absent)`);
|
||||
console.log(` [OK] ${p.name} (already applied, sentinel absent)`);
|
||||
applied++;
|
||||
continue;
|
||||
}
|
||||
console.log(` ⚠️ ${p.name} (0 matches, no sentinel — cannot verify)`);
|
||||
console.log(` ! ${p.name} (0 matches, no sentinel -- cannot verify)`);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (verify) {
|
||||
console.log(` ⬚ ${p.name} — ${relevant.length} match(es), not yet applied`);
|
||||
console.log(` -> ${p.name} -- ${relevant.length} match(es), not yet applied`);
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
@@ -1249,37 +1249,37 @@ for (const p of patches) {
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
console.log(` ✅ ${p.name} (${count} replacement${count > 1 ? 's' : ''})`);
|
||||
console.log(` [OK] ${p.name} (${count} replacement${count > 1 ? 's' : ''})`);
|
||||
applied++;
|
||||
} else {
|
||||
console.log(` ⏭ ${p.name} (no change needed)`);
|
||||
console.log(` >> ${p.name} (no change needed)`);
|
||||
skipped++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`\n${'─'.repeat(55)}`);
|
||||
console.log(`\n${'-'.repeat(55)}`);
|
||||
console.log(` Result: ${applied} applied, ${skipped} skipped, ${failed} failed`);
|
||||
|
||||
if (!dryRun && !verify && applied > 0) {
|
||||
if (!existsSync(BACKUP)) {
|
||||
copyFileSync(TARGET, BACKUP);
|
||||
console.log(` 📦 Backup: ${BACKUP}`);
|
||||
console.log(` [Backup] Backup: ${BACKUP}`);
|
||||
}
|
||||
writeFileSync(TARGET, code, 'utf8');
|
||||
const diff = code.length - origSize;
|
||||
console.log(` 📝 Written: cli.original.cjs (${diff >= 0 ? '+' : ''}${diff} bytes)`);
|
||||
console.log(` [Written] Written: cli.original.cjs (${diff >= 0 ? '+' : ''}${diff} bytes)`);
|
||||
}
|
||||
|
||||
console.log(`${'═'.repeat(55)}\n`);
|
||||
console.log(`${'='.repeat(55)}\n`);
|
||||
PATCHER_EOF
|
||||
info "Patcher created (patch.mjs)"
|
||||
|
||||
# ─── Apply patches ─────────────────────────────────────
|
||||
# --- Apply patches -------------------------------------
|
||||
|
||||
dim "Applying patches ..."
|
||||
node "$CLAWGOD_DIR/patch.mjs" 2>&1 | while IFS= read -r line; do echo " $line"; done
|
||||
|
||||
# ─── Create default configs ───────────────────────────
|
||||
# --- Create default configs ---------------------------
|
||||
|
||||
if [ ! -f "$CLAWGOD_DIR/features.json" ]; then
|
||||
cat > "$CLAWGOD_DIR/features.json" << 'FEATURES_EOF'
|
||||
@@ -1299,11 +1299,11 @@ FEATURES_EOF
|
||||
info "Default features.json created"
|
||||
fi
|
||||
|
||||
# ─── Sanity check: ensure user's Bun can actually load cli.original.cjs ──
|
||||
# --- Sanity check: ensure user's Bun can actually load cli.original.cjs --
|
||||
# Anthropic builds the native binary with a bleeding-edge Bun build (e.g.
|
||||
# 1.3.14 while stable still ships 1.3.13). Older Bun crashes loading the
|
||||
# extracted cli.original.cjs with "Expected CommonJS module to have a
|
||||
# function wrapper". Detect this BEFORE we install the launcher — better
|
||||
# function wrapper". Detect this BEFORE we install the launcher -- better
|
||||
# to fail loudly than to leave the user with a launcher that panics on
|
||||
# first invocation.
|
||||
|
||||
@@ -1315,7 +1315,7 @@ if echo "$sanity_out" | grep -q "Expected CommonJS module to have a function wra
|
||||
warn ""
|
||||
warn " Anthropic builds with Bun's canary channel (currently ~1.3.14), while"
|
||||
warn " bun.sh's main download is on stable (currently 1.3.13). The canary build"
|
||||
warn " is NOT visible on bun.sh's download page — it lives on GitHub Releases"
|
||||
warn " is NOT visible on bun.sh's download page -- it lives on GitHub Releases"
|
||||
warn " and is reachable only via 'bun upgrade --canary'."
|
||||
warn ""
|
||||
warn " If your bun is from bun.sh:"
|
||||
@@ -1328,12 +1328,12 @@ if echo "$sanity_out" | grep -q "Expected CommonJS module to have a function wra
|
||||
warn " curl -fsSL https://bun.sh/install | bash"
|
||||
warn " bun upgrade --canary"
|
||||
warn ""
|
||||
warn " Then re-run install.sh — this sanity check will pass."
|
||||
warn " Then re-run install.sh -- this sanity check will pass."
|
||||
exit 1
|
||||
fi
|
||||
info "Bun loads cli.original.cjs"
|
||||
|
||||
# ─── Replace claude command ───────────────────────────
|
||||
# --- Replace claude command ---------------------------
|
||||
|
||||
LAUNCHER_CONTENT="#!/bin/bash
|
||||
# clawgod launcher
|
||||
@@ -1341,7 +1341,7 @@ CLAWGOD_CLI=\"$CLAWGOD_DIR/cli.cjs\"
|
||||
BUN_BIN=\"$BUN_BIN\"
|
||||
if [ ! -f \"\$CLAWGOD_CLI\" ]; then
|
||||
echo \"clawgod: installation at $CLAWGOD_DIR is missing (cli.cjs not found)\" >&2
|
||||
echo \"clawgod: reinstall via curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash\" >&2
|
||||
echo \"clawgod: reinstall via curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash\" >&2
|
||||
echo \"clawgod: or remove this launcher: rm \\\"\$0\\\"\" >&2
|
||||
exit 127
|
||||
fi
|
||||
@@ -1361,7 +1361,7 @@ exec \"\$BUN_BIN\" \"\$CLAWGOD_CLI\" \"\$@\""
|
||||
# `set -e` via the assignment's exit status under bash 5+.
|
||||
CLAUDE_BIN=$(command -v claude 2>/dev/null || true)
|
||||
if [ -z "$CLAUDE_BIN" ]; then
|
||||
# No claude in PATH — use default location
|
||||
# No claude in PATH -- use default location
|
||||
CLAUDE_BIN="$BIN_DIR/claude"
|
||||
dim "No existing claude found, installing to $BIN_DIR"
|
||||
fi
|
||||
@@ -1370,14 +1370,14 @@ CLAUDE_DIR=$(dirname "$CLAUDE_BIN")
|
||||
# Back up original claude (only once)
|
||||
if [ ! -e "$CLAUDE_BIN.orig" ]; then
|
||||
if [ -L "$CLAUDE_BIN" ]; then
|
||||
# Symlink (native install) — preserve target
|
||||
# Symlink (native install) -- preserve target
|
||||
NATIVE_BIN="$(readlink "$CLAUDE_BIN")"
|
||||
ln -sf "$NATIVE_BIN" "$CLAUDE_BIN.orig"
|
||||
info "Original claude backed up → claude.orig (→ $NATIVE_BIN)"
|
||||
info "Original claude backed up -> claude.orig (-> $NATIVE_BIN)"
|
||||
elif [ -f "$CLAUDE_BIN" ] && file "$CLAUDE_BIN" 2>/dev/null | grep -q "Mach-O\|ELF\|script"; then
|
||||
# Binary or script (pnpm/npm global install)
|
||||
cp "$CLAUDE_BIN" "$CLAUDE_BIN.orig"
|
||||
info "Original claude backed up → claude.orig"
|
||||
info "Original claude backed up -> claude.orig"
|
||||
else
|
||||
# Try versions dir as fallback
|
||||
VERSIONS_DIR="$HOME/.local/share/claude/versions"
|
||||
@@ -1387,15 +1387,15 @@ if [ ! -e "$CLAUDE_BIN.orig" ]; then
|
||||
done)" || true
|
||||
if [ -n "$NATIVE_BIN" ]; then
|
||||
ln -sf "$NATIVE_BIN" "$CLAUDE_BIN.orig"
|
||||
info "Original claude backed up → claude.orig (→ $NATIVE_BIN)"
|
||||
info "Original claude backed up -> claude.orig (-> $NATIVE_BIN)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Write launcher to the SAME directory where claude was found.
|
||||
# CRITICAL: `echo > $f` follows symlinks — if $CLAUDE_BIN is a symlink
|
||||
# (e.g. official ~/.local/bin/claude → ~/.local/share/claude/versions/X)
|
||||
# CRITICAL: `echo > $f` follows symlinks -- if $CLAUDE_BIN is a symlink
|
||||
# (e.g. official ~/.local/bin/claude -> ~/.local/share/claude/versions/X)
|
||||
# we'd write our launcher into the real binary and destroy it. Always
|
||||
# remove the existing entry first so we write a fresh regular file.
|
||||
write_launcher() {
|
||||
@@ -1409,7 +1409,7 @@ write_launcher() {
|
||||
}
|
||||
|
||||
write_launcher "$CLAUDE_BIN"
|
||||
info "Command 'claude' → patched ($CLAUDE_BIN)"
|
||||
info "Command 'claude' -> patched ($CLAUDE_BIN)"
|
||||
|
||||
# Also install to ~/.local/bin if claude was elsewhere (ensures PATH consistency)
|
||||
if [ "$CLAUDE_DIR" != "$BIN_DIR" ]; then
|
||||
@@ -1423,9 +1423,9 @@ fi
|
||||
# - User wants explicit "patched" intent
|
||||
# - User restored claude.orig via uninstall but still wants the patched one
|
||||
write_launcher "$BIN_DIR/clawgod"
|
||||
info "Command 'clawgod' → patched ($BIN_DIR/clawgod)"
|
||||
info "Command 'clawgod' -> patched ($BIN_DIR/clawgod)"
|
||||
|
||||
# ─── Check PATH ───────────────────────────────────────
|
||||
# --- Check PATH ---------------------------------------
|
||||
|
||||
if ! echo "$PATH" | grep -q "$CLAUDE_DIR" && ! echo "$PATH" | grep -q "$BIN_DIR"; then
|
||||
# Detect shell config file
|
||||
@@ -1440,20 +1440,20 @@ if ! echo "$PATH" | grep -q "$CLAUDE_DIR" && ! echo "$PATH" | grep -q "$BIN_DIR"
|
||||
dim " echo 'export PATH=\"\$HOME/.local/bin:\$PATH\"' >> $SHELL_RC && source $SHELL_RC"
|
||||
fi
|
||||
|
||||
# ─── Flush shell cache ────────────────────────────────
|
||||
# --- Flush shell cache --------------------------------
|
||||
|
||||
hash -r 2>/dev/null
|
||||
|
||||
# ─── Done ─────────────────────────────────────────────
|
||||
# --- Done ---------------------------------------------
|
||||
|
||||
echo ""
|
||||
echo -e " ${BOLD}${GREEN}ClawGod installed!${NC}"
|
||||
echo ""
|
||||
dim " claude — Start patched Claude Code (green logo)"
|
||||
dim " claude.orig — Run original unpatched Claude Code"
|
||||
dim " claude -- Start patched Claude Code (green logo)"
|
||||
dim " claude.orig -- Run original unpatched Claude Code"
|
||||
echo ""
|
||||
dim " Updates: 'claude update' is patched to route through this installer."
|
||||
dim " Just run it as usual — pulls latest Anthropic release + re-patches"
|
||||
dim " Just run it as usual -- pulls latest Anthropic release + re-patches"
|
||||
dim " in one step. To leave clawgod and use vanilla update:"
|
||||
dim " bash ~/.clawgod/install.sh --uninstall"
|
||||
echo ""
|
||||
@@ -1465,6 +1465,7 @@ echo ""
|
||||
dim " If 'claude' panics with 'Expected CommonJS module to have a function wrapper',"
|
||||
dim " your Bun lags Anthropic's embedded Bun. Upgrade with one of:"
|
||||
dim " bun upgrade --canary (if installed via curl/install.sh)"
|
||||
dim " scoop update bun (scoop — may lag stable)"
|
||||
dim " scoop update bun (scoop -- may lag stable)"
|
||||
dim " brew upgrade bun (homebrew)"
|
||||
echo ""
|
||||
|
||||
|
||||
+12
-12
@@ -24,7 +24,7 @@
|
||||
<nav class="topbar-links">
|
||||
<a href="#patches">Patches</a>
|
||||
<a href="#how">How it works</a>
|
||||
<a href="https://github.com/0Chencc/clawgod" target="_blank" rel="noopener">GitHub</a>
|
||||
<a href="https://git.qomar.pw/omar/clawgod" target="_blank" rel="noopener">GitHub</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
@@ -52,12 +52,12 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M9.294 6.776 14.357 1h-1.2L8.756 6.013 5.235 1H1.171l5.31 7.531L1.171 15h1.2l4.642-5.296L10.762 15h4.064L9.294 6.776Zm-1.643 1.872-.539-.755L2.804 1.91h1.844l3.452 4.847.539.755 4.49 6.301h-1.844L7.65 8.648Z"/></svg>
|
||||
<span>@0chencc</span>
|
||||
</a>
|
||||
<a class="hero-link stars" href="https://github.com/0Chencc/clawgod/stargazers" target="_blank" rel="noopener">
|
||||
<a class="hero-link stars" href="https://git.qomar.pw/omar/clawgod/stargazers" target="_blank" rel="noopener">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Z"/></svg>
|
||||
<span class="stat-num loading" id="stat-stars">—</span>
|
||||
<span>stars</span>
|
||||
</a>
|
||||
<a class="hero-link downloads" href="https://github.com/0Chencc/clawgod/releases" target="_blank" rel="noopener">
|
||||
<a class="hero-link downloads" href="https://git.qomar.pw/omar/clawgod/releases" target="_blank" rel="noopener">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" aria-hidden="true"><path d="M2.75 14A1.75 1.75 0 0 1 1 12.25v-2.5a.75.75 0 0 1 1.5 0v2.5c0 .138.112.25.25.25h10.5a.25.25 0 0 0 .25-.25v-2.5a.75.75 0 0 1 1.5 0v2.5A1.75 1.75 0 0 1 13.25 14H2.75Z"/><path d="M7.25 7.689V2a.75.75 0 0 1 1.5 0v5.689l1.97-1.969a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 6.78a.75.75 0 0 1 1.06-1.06l1.97 1.969Z"/></svg>
|
||||
<span class="stat-num loading" id="stat-downloads">—</span>
|
||||
<span>downloads</span>
|
||||
@@ -73,15 +73,15 @@
|
||||
</div>
|
||||
<div class="install-panel active" id="panel-unix" role="tabpanel">
|
||||
<div class="code-block">
|
||||
<button class="copy-btn" data-copy="curl -fsSL https://github.com/0Chencc/clawgod/releases/latest/download/install.sh | bash">Copy</button>
|
||||
<pre><span class="prompt">$ </span><span class="tok tok-cmd">curl</span> <span class="tok tok-flag">-fsSL</span> <span class="tok tok-url">https://github.com/0Chencc/clawgod/releases/latest/download/install.sh</span> <span class="tok tok-op">|</span> <span class="tok tok-cmd">bash</span></pre>
|
||||
<button class="copy-btn" data-copy="curl -fsSL https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh | bash">Copy</button>
|
||||
<pre><span class="prompt">$ </span><span class="tok tok-cmd">curl</span> <span class="tok tok-flag">-fsSL</span> <span class="tok tok-url">https://git.qomar.pw/omar/clawgod/raw/HEAD/install.sh</span> <span class="tok tok-op">|</span> <span class="tok tok-cmd">bash</span></pre>
|
||||
</div>
|
||||
<div class="install-note">Idempotent — safe to re-run. Bun, Node ≥ 18, ripgrep required.</div>
|
||||
</div>
|
||||
<div class="install-panel" id="panel-win" role="tabpanel">
|
||||
<div class="code-block">
|
||||
<button class="copy-btn" data-copy="irm https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1 | iex">Copy</button>
|
||||
<pre><span class="prompt">> </span><span class="tok tok-cmd">irm</span> <span class="tok tok-url">https://github.com/0Chencc/clawgod/releases/latest/download/install.ps1</span> <span class="tok tok-op">|</span> <span class="tok tok-cmd">iex</span></pre>
|
||||
<button class="copy-btn" data-copy="irm https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1 | iex">Copy</button>
|
||||
<pre><span class="prompt">> </span><span class="tok tok-cmd">irm</span> <span class="tok tok-url">https://git.qomar.pw/omar/clawgod/raw/HEAD/install.ps1</span> <span class="tok tok-op">|</span> <span class="tok tok-cmd">iex</span></pre>
|
||||
</div>
|
||||
<div class="install-note">Idempotent — safe to re-run. Bun via <a href="https://bun.sh/install" target="_blank" rel="noopener">bun.sh</a> recommended.</div>
|
||||
</div>
|
||||
@@ -179,8 +179,8 @@
|
||||
<!-- ─── CTA ───────────────────────────────────────────────── -->
|
||||
<section class="cta">
|
||||
<div class="cta-row">
|
||||
<a class="btn primary" href="https://github.com/0Chencc/clawgod#install">Get started</a>
|
||||
<a class="btn" href="https://github.com/0Chencc/clawgod" target="_blank" rel="noopener">
|
||||
<a class="btn primary" href="https://git.qomar.pw/omar/clawgod#install">Get started</a>
|
||||
<a class="btn" href="https://git.qomar.pw/omar/clawgod" target="_blank" rel="noopener">
|
||||
<svg width="16" height="16" viewBox="0 0 16 16"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
|
||||
Source on GitHub
|
||||
</a>
|
||||
@@ -206,9 +206,9 @@
|
||||
</a>
|
||||
</span>
|
||||
<span class="footer-cell footer-links">
|
||||
<a href="https://github.com/0Chencc/clawgod/releases">Releases</a> ·
|
||||
<a href="https://github.com/0Chencc/clawgod/issues">Issues</a> ·
|
||||
<a href="https://github.com/0Chencc/clawgod/actions/workflows/compat-daily.yml">CI</a>
|
||||
<a href="https://git.qomar.pw/omar/clawgod/releases">Releases</a> ·
|
||||
<a href="https://git.qomar.pw/omar/clawgod/issues">Issues</a> ·
|
||||
<a href="https://git.qomar.pw/omar/clawgod/actions/workflows/compat-daily.yml">CI</a>
|
||||
</span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
Reference in New Issue
Block a user