capix-code 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env bash
2
+ # install-config.sh — drop the Capix provider config as the default.
3
+ set -uo pipefail
4
+
5
+ DIR="$(cd "$(dirname "$0")/.." && pwd)"
6
+ CAPIX_CODE_DIR="${CAPIX_CODE_DIR:-$DIR/upstream}"
7
+ CONFIG_SRC="$DIR/config/defaults.json"
8
+
9
+ if [ ! -f "$CONFIG_SRC" ]; then
10
+ echo "✗ Missing $CONFIG_SRC"
11
+ exit 1
12
+ fi
13
+
14
+ # 1. Bundle the config into the capix-code package as a default.
15
+ DEST_DIR="$CAPIX_CODE_DIR/packages/capix-code/config"
16
+ mkdir -p "$DEST_DIR"
17
+ cp "$CONFIG_SRC" "$DEST_DIR/capix-defaults.json"
18
+ echo " ✓ bundled capix-defaults.json"
19
+
20
+ # 2. Create the init script that writes the default config on first run.
21
+ WRAPPER="$CAPIX_CODE_DIR/packages/capix-code/scripts/init-capix-config.ts"
22
+ mkdir -p "$(dirname "$WRAPPER")"
23
+ cat > "$WRAPPER" << 'WRAPPER_EOF'
24
+ import { existsSync, mkdirSync, writeFileSync, readFileSync } from "node:fs";
25
+ import { homedir } from "node:os";
26
+ import { join } from "node:path";
27
+
28
+ function getConfigDir(): string {
29
+ switch (process.platform) {
30
+ case "darwin": return join(homedir(), "Library", "Application Support", "capix-code");
31
+ case "win32": return join(homedir(), "AppData", "Roaming", "capix-code");
32
+ default: return join(homedir(), ".config", "capix-code");
33
+ }
34
+ }
35
+
36
+ const configDir = getConfigDir();
37
+ const configFile = join(configDir, "capix-code.json");
38
+
39
+ if (!existsSync(configFile)) {
40
+ let defaults = "{}";
41
+ try {
42
+ defaults = readFileSync(join(import.meta.dir, "..", "config", "capix-defaults.json"), "utf-8");
43
+ } catch {}
44
+ mkdirSync(configDir, { recursive: true });
45
+ writeFileSync(configFile, defaults, "utf-8");
46
+ }
47
+ WRAPPER_EOF
48
+ echo " ✓ created init-capix-config.ts wrapper"
49
+
50
+ # 3. Install the TUI theme + brand assets.
51
+ if [ -d "$DIR/themes" ]; then
52
+ THEME_DEST="$CAPIX_CODE_DIR/packages/capix-code/config/themes"
53
+ mkdir -p "$THEME_DEST"
54
+ cp "$DIR/themes/capix.toml" "$THEME_DEST/capix.toml" 2>/dev/null || true
55
+ cp "$DIR/tui-capix.json" "$CAPIX_CODE_DIR/packages/capix-code/config/tui-capix.json" 2>/dev/null || true
56
+ echo " ✓ TUI theme installed"
57
+ fi
58
+
59
+ if [ -d "$DIR/brand" ]; then
60
+ BRAND_DEST="$CAPIX_CODE_DIR/packages/capix-code/config/brand"
61
+ mkdir -p "$BRAND_DEST"
62
+ cp -R "$DIR/brand/"* "$BRAND_DEST/" 2>/dev/null || true
63
+ echo " ✓ brand assets installed"
64
+ fi
65
+
66
+ echo "✓ Capix config + branding installed."
@@ -0,0 +1,115 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ VERSION="${CAPIX_CODE_VERSION:-${1:-}}"
5
+ RELEASE_BASE_URL="${CAPIX_RELEASE_BASE_URL:-https://github.com/CapIX-Protocol/Capix-Code/releases/download}"
6
+ INSTALL_DIR="${CAPIX_INSTALL_DIR:-${CAPIX_CODE_INSTALL_DIR:-${HOME}/.local/bin}}"
7
+ RUNTIME_DIR="${CAPIX_CODE_RUNTIME_DIR:-${HOME}/.local/share/capix-code}"
8
+
9
+ # "latest" is permitted only by resolving it to an immutable version BEFORE any
10
+ # download — never by trusting mutable content. The release pipeline pins the
11
+ # current stable version in CAPIX_STABLE_VERSION (the single source of truth
12
+ # that also populates manifest/release-manifest.json#stableVersion). Without a
13
+ # pin, "latest" fails closed so the installer never proceeds unbounded.
14
+ if [ -z "$VERSION" ] || [ "$VERSION" = "latest" ]; then
15
+ if [ -n "${CAPIX_STABLE_VERSION:-}" ]; then
16
+ VERSION="$CAPIX_STABLE_VERSION"
17
+ echo "Resolved latest -> ${VERSION} (CAPIX_STABLE_VERSION)" >&2
18
+ else
19
+ echo "ERROR: 'latest' requires CAPIX_STABLE_VERSION to be set to an immutable release (e.g. v1.2.3)." >&2
20
+ echo "The release pipeline pins the current stable version there; do not pin to mutable content." >&2
21
+ exit 2
22
+ fi
23
+ fi
24
+
25
+ if [[ ! "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?$ ]]; then
26
+ echo "ERROR: invalid version '$VERSION' (expected vMAJOR.MINOR.PATCH)" >&2
27
+ exit 2
28
+ fi
29
+
30
+ OS="${CAPIX_INSTALL_OS:-$(uname -s | tr '[:upper:]' '[:lower:]')}"
31
+ ARCH="${CAPIX_INSTALL_ARCH:-$(uname -m)}"
32
+ case "$OS" in
33
+ darwin|linux) ;;
34
+ mingw*|msys*|cygwin*|win32*|windows*)
35
+ echo "ERROR: Windows is not supported by this shell installer." >&2
36
+ echo "Download the Windows binary from:" >&2
37
+ echo " https://github.com/CapIX-Protocol/Capix-Code/releases" >&2
38
+ echo "Or use PowerShell:" >&2
39
+ echo " iwr -UseBasicParsing https://github.com/CapIX-Protocol/Capix-Code/releases/download/${VERSION}/capix-code-windows-x64.exe -OutFile capix-code.exe" >&2
40
+ exit 2
41
+ ;;
42
+ *)
43
+ echo "ERROR: unsupported operating system '$OS'" >&2
44
+ echo "Download a binary from: https://github.com/CapIX-Protocol/Capix-Code/releases" >&2
45
+ exit 2
46
+ ;;
47
+ esac
48
+ case "$ARCH" in
49
+ x86_64) ARCH="x64" ;;
50
+ arm64|aarch64) ARCH="arm64" ;;
51
+ *) echo "ERROR: unsupported architecture '$ARCH'" >&2; exit 2 ;;
52
+ esac
53
+
54
+ RELEASE_VERSION="${VERSION#v}"
55
+ ARTIFACT="capix-code-${RELEASE_VERSION}-${OS}-${ARCH}-unsigned.tar.gz"
56
+ BASE_URL="${RELEASE_BASE_URL}/${VERSION}"
57
+ WORK_DIR=$(mktemp -d "${TMPDIR:-/tmp}/capix-code-install.XXXXXX")
58
+ trap 'rm -rf "$WORK_DIR"' EXIT INT TERM
59
+
60
+ if [[ "$BASE_URL" == https://* ]]; then
61
+ curl --proto '=https' --tlsv1.2 -fsSL "${BASE_URL}/${ARTIFACT}.sha256" -o "${WORK_DIR}/${ARTIFACT}.sha256"
62
+ curl --proto '=https' --tlsv1.2 -fsSL "${BASE_URL}/${ARTIFACT}" -o "${WORK_DIR}/${ARTIFACT}"
63
+ else
64
+ curl -fsSL "${BASE_URL}/${ARTIFACT}.sha256" -o "${WORK_DIR}/${ARTIFACT}.sha256"
65
+ curl -fsSL "${BASE_URL}/${ARTIFACT}" -o "${WORK_DIR}/${ARTIFACT}"
66
+ fi
67
+
68
+ CHECKSUM_LINES=$(awk 'NF { count++ } END { print count + 0 }' "${WORK_DIR}/${ARTIFACT}.sha256")
69
+ EXPECTED=$(awk 'NF { print $1 }' "${WORK_DIR}/${ARTIFACT}.sha256")
70
+ RECORDED_ARTIFACT=$(awk 'NF { print $2 }' "${WORK_DIR}/${ARTIFACT}.sha256")
71
+ RECORDED_ARTIFACT="${RECORDED_ARTIFACT#\*}"
72
+ RECORDED_ARTIFACT="${RECORDED_ARTIFACT##*/}"
73
+ if [ "$CHECKSUM_LINES" -ne 1 ] || [ "$RECORDED_ARTIFACT" != "$ARTIFACT" ] || [[ ! "$EXPECTED" =~ ^[0-9a-fA-F]{64}$ ]]; then
74
+ echo "ERROR: adjacent checksum must contain exactly one valid SHA-256 entry for ${ARTIFACT}" >&2
75
+ exit 1
76
+ fi
77
+
78
+ if command -v shasum >/dev/null 2>&1; then
79
+ ACTUAL=$(shasum -a 256 "${WORK_DIR}/${ARTIFACT}" | awk '{print $1}')
80
+ elif command -v sha256sum >/dev/null 2>&1; then
81
+ ACTUAL=$(sha256sum "${WORK_DIR}/${ARTIFACT}" | awk '{print $1}')
82
+ else
83
+ echo "ERROR: neither shasum nor sha256sum is available" >&2
84
+ exit 1
85
+ fi
86
+
87
+ if [ "$EXPECTED" != "$ACTUAL" ]; then
88
+ echo "ERROR: checksum verification failed for ${ARTIFACT}" >&2
89
+ exit 1
90
+ fi
91
+
92
+ mkdir -p "$INSTALL_DIR" "$(dirname "$RUNTIME_DIR")"
93
+
94
+ if [ ! -w "$INSTALL_DIR" ]; then
95
+ echo "ERROR: ${INSTALL_DIR} is not writable. Re-run with a user-owned CAPIX_CODE_INSTALL_DIR; this installer does not invoke sudo." >&2
96
+ exit 1
97
+ fi
98
+
99
+ tar -xzf "${WORK_DIR}/${ARTIFACT}" -C "$WORK_DIR"
100
+ test -x "${WORK_DIR}/customer/bin/capix-code" || {
101
+ echo "ERROR: verified archive does not contain customer/bin/capix-code" >&2
102
+ exit 1
103
+ }
104
+
105
+ STAGED_RUNTIME="${RUNTIME_DIR}.${VERSION}.new"
106
+ rm -rf "$STAGED_RUNTIME"
107
+ mkdir -p "$STAGED_RUNTIME"
108
+ cp -a "${WORK_DIR}/customer/." "$STAGED_RUNTIME/"
109
+ rm -rf "$RUNTIME_DIR"
110
+ mv "$STAGED_RUNTIME" "$RUNTIME_DIR"
111
+ ln -sfn "${RUNTIME_DIR}/bin/capix-code" "${INSTALL_DIR}/capix-code"
112
+ TARGET="${INSTALL_DIR}/capix-code"
113
+
114
+ echo "Installed verified Capix Code ${VERSION} at ${TARGET}"
115
+ echo "This artifact is unsigned. Verification used the release's exact SHA-256 manifest entry."
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ VERSION="${1:?version required}"
4
+ PLATFORM="${2:?platform required}"
5
+ ARCH="${3:?architecture required}"
6
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
7
+ CUSTOMER="$ROOT/dist/customer"
8
+ OUT="$ROOT/release-artifacts"
9
+ NAME="capix-code-$VERSION-$PLATFORM-$ARCH-unsigned"
10
+
11
+ "$ROOT/scripts/assert-artifact.sh" "$CUSTOMER"
12
+ "$ROOT/scripts/assert-customer-brand.sh" "$CUSTOMER"
13
+ mkdir -p "$OUT"
14
+ if [ "$PLATFORM" = win32 ]; then
15
+ ARCHIVE="$OUT/$NAME.zip"
16
+ (cd "$ROOT/dist" && 7z a -tzip "$ARCHIVE" customer)
17
+ else
18
+ ARCHIVE="$OUT/$NAME.tar.gz"
19
+ tar -C "$ROOT/dist" -czf "$ARCHIVE" customer
20
+ fi
21
+ if command -v sha256sum >/dev/null 2>&1; then
22
+ sha256sum "$ARCHIVE" > "$ARCHIVE.sha256"
23
+ else
24
+ shasum -a 256 "$ARCHIVE" > "$ARCHIVE.sha256"
25
+ fi
26
+ printf '%s\n' "$(git -C "$ROOT" rev-parse HEAD)" > "$OUT/$NAME.source-commit.txt"
27
+ node "$ROOT/scripts/write-release-entry.mjs" "$VERSION" "$PLATFORM" "$ARCH" "$ARCHIVE"
28
+ echo "Verified release artifact: $ARCHIVE"
@@ -0,0 +1,84 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ VERSION="${1:-0.1.0-dev}"
5
+ ARCH="$(uname -m)"
6
+ OUTPUT_DIR="dist"
7
+ ARTIFACT_NAME="capix-code-$VERSION-darwin-$ARCH"
8
+
9
+ echo "=== Packaging Capix Code $VERSION ($ARCH) ==="
10
+
11
+ mkdir -p "$OUTPUT_DIR"
12
+
13
+ # 1. Build the TypeScript
14
+ npm run compile || true # tsc --noEmit for now — no separate build step yet
15
+
16
+ # 2. Create tarball with src/, config/, manifest/
17
+ echo "Creating tarball..."
18
+ tar -czf "$OUTPUT_DIR/$ARTIFACT_NAME.tar.gz" \
19
+ src/ \
20
+ config/ \
21
+ manifest/ \
22
+ package.json \
23
+ package-lock.json \
24
+ tui-capix.json \
25
+ tsconfig.json \
26
+ LICENSE \
27
+ NOTICE \
28
+ README.md
29
+
30
+ # 3. Generate SHA-256
31
+ echo "Generating SHA-256..."
32
+ shasum -a 256 "$OUTPUT_DIR/$ARTIFACT_NAME.tar.gz" > "$OUTPUT_DIR/$ARTIFACT_NAME.tar.gz.sha256"
33
+
34
+ # 4. Provenance
35
+ cat > "$OUTPUT_DIR/$ARTIFACT_NAME.provenance.json" << EOF
36
+ {
37
+ "artifact": "$ARTIFACT_NAME.tar.gz",
38
+ "version": "$VERSION",
39
+ "platform": "darwin-$ARCH",
40
+ "signed": false,
41
+ "sourceCommit": "$(git rev-parse HEAD)",
42
+ "builtAt": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
43
+ "builder": "$(whoami)@$(hostname)",
44
+ "checksum": "$(cat "$OUTPUT_DIR/$ARTIFACT_NAME.tar.gz.sha256" | awk '{print $1}')"
45
+ }
46
+ EOF
47
+
48
+ # 5. Minimal SBOM
49
+ cat > "$OUTPUT_DIR/$ARTIFACT_NAME.sbom.json" << EOF
50
+ {
51
+ "sbomFormat": "CapIX-minimal",
52
+ "version": "0.1.0",
53
+ "generatedAt": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
54
+ "dependencies": "See package-lock.json",
55
+ "sourceCommit": "$(git rev-parse HEAD)",
56
+ "unsigned": true
57
+ }
58
+ EOF
59
+
60
+ # 6. Installation instructions
61
+ cat << INST
62
+
63
+ === Capix Code $VERSION (UNSIGNED) ===
64
+
65
+ Artifact: $OUTPUT_DIR/$ARTIFACT_NAME.tar.gz
66
+ SHA-256: $(cat "$OUTPUT_DIR/$ARTIFACT_NAME.tar.gz.sha256" | awk '{print $1}')
67
+
68
+ ## Installation (UNSIGNED)
69
+
70
+ 1. Verify checksum:
71
+ shasum -a 256 $OUTPUT_DIR/$ARTIFACT_NAME.tar.gz
72
+
73
+ 2. Extract:
74
+ tar -xzf $OUTPUT_DIR/$ARTIFACT_NAME.tar.gz -C ~/capix-code
75
+
76
+ 3. Install dependencies:
77
+ cd ~/capix-code && npm install --production
78
+
79
+ 4. Run:
80
+ node ~/capix-code/src/index.ts # or after tsc: node dist/index.js
81
+
82
+ Source commit: $(git rev-parse HEAD)
83
+
84
+ INST
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env node
2
+ const { execSync } = require('child_process');
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const os = require('os');
6
+
7
+ const PLATFORM = process.platform === 'darwin' ? 'darwin' : 'linux';
8
+ const ARCH = process.arch === 'arm64' ? 'arm64' : 'x64';
9
+ const VERSION = '1.3.0';
10
+ const RELEASE = `https://github.com/CapIX-Protocol/CapIX-Code/releases/download/v${VERSION}`;
11
+
12
+ const installDir = path.join(os.homedir(), '.capix-code');
13
+ const binDir = path.join(installDir, 'bin');
14
+ const engineDir = path.join(installDir, 'engine');
15
+
16
+ fs.mkdirSync(binDir, { recursive: true });
17
+ fs.mkdirSync(engineDir, { recursive: true });
18
+
19
+ try {
20
+ console.log('Downloading capix-code binary...');
21
+ execSync(`curl -fsSL ${RELEASE}/capix-code -o ${binDir}/capix-code`, { stdio: 'inherit' });
22
+ fs.chmodSync(path.join(binDir, 'capix-code'), 0o755);
23
+
24
+ console.log('Downloading capix-engine (this may take a minute)...');
25
+ execSync(`curl -fsSL ${RELEASE}/capix-engine -o ${engineDir}/capix-engine`, { stdio: 'inherit', timeout: 300000 });
26
+ fs.chmodSync(path.join(engineDir, 'capix-engine'), 0o755);
27
+
28
+ console.log('✓ Capix Code installed to ' + installDir);
29
+ console.log('Run: capix-code --version');
30
+ } catch (err) {
31
+ console.warn('⚠ Binary download failed. Download manually from:');
32
+ console.warn(' https://github.com/CapIX-Protocol/CapIX-Code/releases');
33
+ }
@@ -0,0 +1,12 @@
1
+ import { chmodSync, existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+
4
+ const root = new URL('..', import.meta.url).pathname;
5
+ const launcher = join(root, 'bin', 'capix-code.cjs');
6
+
7
+ if (!existsSync(launcher)) {
8
+ console.error('Capix Code npm launcher is missing.');
9
+ process.exit(1);
10
+ }
11
+
12
+ chmodSync(launcher, 0o755);
@@ -0,0 +1,59 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { cpSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { join, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+
6
+ const [platform, arch, source = 'dist/customer', destination = 'npm-platform'] =
7
+ process.argv.slice(2);
8
+ const supported = new Set([
9
+ 'darwin-arm64',
10
+ 'darwin-x64',
11
+ 'linux-arm64',
12
+ 'linux-x64',
13
+ 'windows-x64',
14
+ ]);
15
+ const id = `${platform}-${arch}`;
16
+
17
+ if (!supported.has(id)) {
18
+ console.error(`Unsupported Capix Code npm platform: ${id}`);
19
+ process.exit(2);
20
+ }
21
+
22
+ const root = resolve(fileURLToPath(new URL('..', import.meta.url)));
23
+ const artifact = resolve(root, source);
24
+ const output = resolve(root, destination, id);
25
+ const isWindows = process.platform === 'win32';
26
+ const assertScript = join(root, 'scripts', 'assert-artifact.sh');
27
+ const brandScript = join(root, 'scripts', 'assert-customer-brand.sh');
28
+ if (!isWindows) {
29
+ execFileSync(assertScript, [artifact], { stdio: 'inherit' });
30
+ execFileSync(brandScript, [artifact], { stdio: 'inherit' });
31
+ } else {
32
+ // On Windows, run via bash if available; otherwise skip shell-script assertions
33
+ try {
34
+ execFileSync('bash', [assertScript, artifact], { stdio: 'inherit' });
35
+ execFileSync('bash', [brandScript, artifact], { stdio: 'inherit' });
36
+ } catch {
37
+ console.warn('Skipping shell-script assertions on Windows (bash not available)');
38
+ }
39
+ }
40
+ rmSync(output, { recursive: true, force: true });
41
+ mkdirSync(output, { recursive: true });
42
+ cpSync(artifact, join(output, 'customer'), { recursive: true });
43
+ writeFileSync(
44
+ join(output, 'package.json'),
45
+ `${JSON.stringify(
46
+ {
47
+ name: `@capix-code/${id}`,
48
+ version: '1.2.7',
49
+ description: `Capix Code native runtime for ${id}`,
50
+ license: 'Apache-2.0',
51
+ os: [platform === 'windows' ? 'win32' : platform],
52
+ cpu: [arch],
53
+ files: ['customer/'],
54
+ },
55
+ null,
56
+ 2
57
+ )}\n`
58
+ );
59
+ console.log(output);
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env bash
2
+ # rebrand.sh — apply Capix branding.
3
+ # ONLY renames: binary name, config dirs, env var prefixes, install script.
4
+ # Does NOT rename: workspace package name, npm package name, or import paths.
5
+ set -euo pipefail
6
+
7
+ DIR="$(cd "$(dirname "$0")/.." && pwd)"
8
+ CAPIX_CODE_DIR="${CAPIX_CODE_DIR:-$DIR/upstream}"
9
+
10
+ if [ ! -d "$CAPIX_CODE_DIR" ]; then
11
+ echo "✗ No $CAPIX_CODE_DIR. Run ./scripts/bootstrap.sh first."
12
+ exit 1
13
+ fi
14
+
15
+ cd "$CAPIX_CODE_DIR"
16
+
17
+ # 0. Rename the upstream package directory.
18
+ if [ -d "packages/opencode" ]; then
19
+ mv packages/opencode packages/capix-code
20
+ echo " ✓ package directory renamed"
21
+ fi
22
+
23
+ echo "▸ Rebranding in $CAPIX_CODE_DIR"
24
+
25
+ # 1. Binary name in packages/capix-code/package.json — ONLY the "bin" field.
26
+ PKG="$CAPIX_CODE_DIR/packages/capix-code/package.json"
27
+ if [ -f "$PKG" ]; then
28
+ # Change only the binary name, not the package name (workspace deps depend on it).
29
+ sed -i.bak 's|"bin": {"opencode"|"bin": {"capix-code"|g' "$PKG"
30
+ rm -f "$PKG.bak"
31
+ echo " ✓ binary name renamed"
32
+ fi
33
+
34
+ # 2. Build script — only the output directory/file naming.
35
+ BUILD="$CAPIX_CODE_DIR/packages/capix-code/script/build.ts"
36
+ if [ -f "$BUILD" ]; then
37
+ sed -i.bak 's|bin/opencode|bin/capix-code|g' "$BUILD"
38
+ rm -f "$BUILD.bak"
39
+ echo " ✓ build.ts: output binary renamed"
40
+ fi
41
+
42
+ # 3. Env prefixes in environment accesses only. Never rewrite imported symbols.
43
+ echo "▸ Replacing env var prefixes…"
44
+ find "$CAPIX_CODE_DIR/packages/capix-code/src" \( -name '*.ts' -o -name '*.js' -o -name '*.tsx' \) -type f 2>/dev/null | while IFS= read -r f; do
45
+ perl -0pi.bak -e 's/(process[.]env|Bun[.]env)[.]OPENCODE_/$1.CAPIX_CODE_/g' "$f"
46
+ rm -f "$f.bak"
47
+ done
48
+ echo " ✓ env prefix replaced"
49
+
50
+ # 4. Config directory paths in source.
51
+ echo "▸ Replacing config directory paths…"
52
+ find "$CAPIX_CODE_DIR/packages/capix-code/src" \( -name '*.ts' -o -name '*.js' -o -name '*.tsx' \) -type f 2>/dev/null | while IFS= read -r f; do
53
+ sed -i.bak \
54
+ -e 's|\.config/opencode|.config/capix-code|g' \
55
+ -e 's|\.opencode/|.capix-code/|g' \
56
+ -e "s|opencode/auth|capix-code/auth|g" \
57
+ "$f"
58
+ rm -f "$f.bak"
59
+ done
60
+ echo " ✓ config dirs updated"
61
+
62
+ # 5. Config filename: opencode.json → capix-code.json (only in the default config path lookup).
63
+ echo "▸ Replacing config filename…"
64
+ find "$CAPIX_CODE_DIR/packages/capix-code/src" \( -name '*.ts' -o -name '*.js' \) -type f 2>/dev/null | while IFS= read -r f; do
65
+ sed -i.bak "s/opencode\.json/capix-code.json/g" "$f"
66
+ rm -f "$f.bak"
67
+ done
68
+ echo " ✓ config filename renamed"
69
+
70
+ # 6. Display name in source — "OpenCode" → "CapixCode" (display strings only, not imports).
71
+ echo "▸ Replacing display names…"
72
+ find "$CAPIX_CODE_DIR/packages/capix-code/src" \( -name '*.ts' -o -name '*.tsx' \) -type f 2>/dev/null | while IFS= read -r f; do
73
+ # Only replace in string literals, not import paths. Conservative: replace "OpenCode" in quotes.
74
+ sed -i.bak \
75
+ -e 's/"OpenCode"/"CapixCode"/g' \
76
+ -e "s/'OpenCode'/'CapixCode'/g" \
77
+ -e 's/`OpenCode`/`CapixCode`/g' \
78
+ "$f"
79
+ rm -f "$f.bak"
80
+ done
81
+ echo " ✓ display names updated"
82
+
83
+ # 6b. Replace the terminal identity and customer-visible command copy. These
84
+ # files are an explicit reviewed allowlist: internal package names, protocol
85
+ # identifiers and import contracts remain untouched.
86
+ cp "$DIR/assets/tui-logo.ts" "$CAPIX_CODE_DIR/packages/tui/src/logo.ts"
87
+ CLI_UI="$CAPIX_CODE_DIR/packages/capix-code/src/cli/ui.ts"
88
+ perl -0pi.bak -e 's/const wordmark = \[.*?\]\n/const wordmark = [\n ` ██████╗ █████╗ ██████╗ ██╗██╗ ██╗ ██████╗ ██████╗ ██████╗ ███████╗`,\n ` ██╔════╝██╔══██╗██╔══██╗██║╚██╗██╔╝ ██╔════╝██╔═══██╗██╔══██╗██╔════╝`,\n ` ██║ ███████║██████╔╝██║ ╚███╔╝ ██║ ██║ ██║██║ ██║█████╗ `,\n ` ██║ ██╔══██║██╔═══╝ ██║ ██╔██╗ ██║ ██║ ██║██║ ██║██╔══╝ `,\n ` ╚██████╗██║ ██║██║ ██║██╔╝ ██╗ ╚██████╗╚██████╔╝██████╔╝███████╗`,\n ` ╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝`,\n ` CAPIX CODE`,\n]\n/s' "$CLI_UI"
89
+ rm -f "$CLI_UI.bak"
90
+ TUI_PRESENTATION="$CAPIX_CODE_DIR/packages/tui/src/util/presentation.ts"
91
+ perl -0pi.bak -e 's/const logo = \{.*?\}\n/const logo = {\n left: [" ██████╗ █████╗ ██████╗ ██╗██╗ ██╗", "██╔════╝ ██╔══██╗██╔══██╗██║╚██╗██╔╝", "██║ ███████║██████╔╝██║ ╚███╔╝ ", "██║ ██╔══██║██╔═══╝ ██║ ██╔██╗ ", "╚██████╗ ██║ ██║██║ ██║██╔╝ ██╗", " ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝"],\n right: [" ██████╗ ██████╗ ██████╗ ███████╗", "██╔════╝██╔═══██╗██╔══██╗██╔════╝", "██║ ██║ ██║██║ ██║█████╗ ", "██║ ██║ ██║██║ ██║██╔══╝ ", "╚██████╗╚██████╔╝██████╔╝███████╗", " ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝"],\n}\n/s; s/opencode -s/capix-code -s/g' "$TUI_PRESENTATION"
92
+ rm -f "$TUI_PRESENTATION.bak"
93
+ PRESENTATION_FILES=(
94
+ packages/tui/src/app.tsx
95
+ packages/tui/src/util/presentation.ts
96
+ packages/capix-code/src/cli/ui.ts
97
+ packages/capix-code/src/index.ts
98
+ packages/capix-code/src/cli/error.ts
99
+ packages/capix-code/src/cli/cmd/run.ts
100
+ packages/capix-code/src/cli/cmd/run/splash.ts
101
+ packages/capix-code/src/cli/cmd/run/footer.permission.tsx
102
+ packages/capix-code/src/cli/cmd/run/footer.prompt.tsx
103
+ packages/capix-code/src/cli/cmd/run/permission.shared.ts
104
+ packages/capix-code/src/provider/error.ts
105
+ packages/capix-code/src/cli/cmd/attach.ts
106
+ packages/capix-code/src/cli/cmd/upgrade.ts
107
+ packages/capix-code/src/cli/cmd/uninstall.ts
108
+ packages/capix-code/src/cli/cmd/serve.ts
109
+ packages/capix-code/src/cli/cmd/web.ts
110
+ packages/capix-code/src/cli/cmd/pr.ts
111
+ packages/capix-code/src/cli/cmd/tui.ts
112
+ packages/capix-code/src/cli/network.ts
113
+ )
114
+ for relative in "${PRESENTATION_FILES[@]}"; do
115
+ file="$CAPIX_CODE_DIR/$relative"
116
+ test -f "$file" || { echo "ERROR: customer presentation source missing: $relative"; exit 1; }
117
+ perl -0pi.bak -e '
118
+ s/OpenCode/Capix Code/g;
119
+ s/OC \|/Capix |/g;
120
+ s/opencode --mini/capix-code --mini/g;
121
+ s/run opencode/run Capix Code/g;
122
+ s/opencode models/capix-code models/g;
123
+ s/opencode auth login/capix-code login/g;
124
+ s/opencode server/Capix Code server/g;
125
+ s/start opencode/start Capix Code/g;
126
+ s/path to start opencode/path to start Capix Code/g;
127
+ s/upgrade opencode/upgrade Capix Code/g;
128
+ s/opencode upgrade/Capix Code upgrade/g;
129
+ s/opencode session/Capix Code session/g;
130
+ s/Starting opencode/Starting Capix Code/g;
131
+ s/uninstall opencode/uninstall Capix Code/g;
132
+ s/running opencode/running Capix Code/g;
133
+ s/path to start opencode/path to start Capix Code/g;
134
+ s/Thank you for using opencode/Thank you for using Capix Code/g;
135
+ s/[.]scriptName\("opencode"\)/.scriptName("capix-code")/g;
136
+ s/startsWith\("opencode /startsWith("capix-code /g;
137
+ s/opencode[.]local/capix.local/g;
138
+ s/OPENCODE_SERVER/CAPIX_CODE_SERVER/g;
139
+ s/or '\''opencode'\''/or '\''capix'\''/g;
140
+ s/opencode does not support/Capix Code does not support/g;
141
+ ' "$file"
142
+ rm -f "$file.bak"
143
+ done
144
+ echo " ✓ terminal title, splash, logo and customer command copy replaced"
145
+
146
+ # 7. Install script references.
147
+ INSTALL="$CAPIX_CODE_DIR/install"
148
+ if [ -f "$INSTALL" ]; then
149
+ sed -i.bak \
150
+ -e 's|anomalyco/opencode|CapIX-Protocol/CapIX-Code|g' \
151
+ -e 's|opencode-ai|capix-code|g' \
152
+ "$INSTALL"
153
+ rm -f "$INSTALL.bak"
154
+ echo " ✓ install script updated"
155
+ fi
156
+
157
+ echo "✓ Rebrand complete. Only the binary name, config dirs, and env vars are rebranded."
158
+ echo " Runtime plugin/provider are staged by scripts/build.sh and verified fail-closed."
159
+ "$DIR/scripts/assert-upstream-brand.sh" "$CAPIX_CODE_DIR"