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.
- package/LICENSE +203 -0
- package/README.md +131 -0
- package/bin/capix-code.cjs +57 -0
- package/dist/customer/config/capix-defaults.json +22 -0
- package/dist/customer/config/defaults.json +248 -0
- package/package.json +79 -0
- package/scripts/assert-artifact.sh +30 -0
- package/scripts/assert-customer-brand.sh +54 -0
- package/scripts/assert-upstream-brand.sh +46 -0
- package/scripts/bootstrap.sh +38 -0
- package/scripts/build-manifest.mjs +219 -0
- package/scripts/build.sh +74 -0
- package/scripts/checksum.sh +8 -0
- package/scripts/dev-install.sh +30 -0
- package/scripts/dev.sh +35 -0
- package/scripts/install-config.sh +66 -0
- package/scripts/install.sh +115 -0
- package/scripts/package-customer.sh +28 -0
- package/scripts/package.sh +84 -0
- package/scripts/postinstall.js +33 -0
- package/scripts/prepare-npm-meta.mjs +12 -0
- package/scripts/prepare-npm-platform.mjs +59 -0
- package/scripts/rebrand.sh +159 -0
- package/scripts/resolve-version.mjs +126 -0
- package/scripts/validate-manifest.mjs +167 -0
- package/scripts/verify-runtime-provider.ts +9 -0
- package/scripts/write-release-entry.mjs +38 -0
|
@@ -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"
|