@keychat-io/keychat 0.1.18
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 +661 -0
- package/README.md +170 -0
- package/docs/setup-guide.md +124 -0
- package/index.ts +205 -0
- package/openclaw.plugin.json +38 -0
- package/package.json +33 -0
- package/scripts/build-release.sh +76 -0
- package/scripts/install.sh +180 -0
- package/scripts/postinstall.mjs +128 -0
- package/scripts/publish.sh +25 -0
- package/scripts/setup.sh +80 -0
- package/src/bridge-client.ts +854 -0
- package/src/channel.ts +2631 -0
- package/src/config-schema.ts +50 -0
- package/src/ensure-binary.ts +65 -0
- package/src/keychain.ts +75 -0
- package/src/lightning.ts +128 -0
- package/src/media.ts +189 -0
- package/src/notify.ts +15 -0
- package/src/nwc.ts +360 -0
- package/src/paths.ts +38 -0
- package/src/qrcode-types.d.ts +5 -0
- package/src/qrcode.ts +23 -0
- package/src/runtime.ts +14 -0
- package/src/types.ts +125 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Keychat â one-line installer
|
|
3
|
+
# Usage: curl -fsSL https://raw.githubusercontent.com/keychat-io/keychat-openclaw/main/scripts/install.sh | bash
|
|
4
|
+
set -e
|
|
5
|
+
|
|
6
|
+
REPO="keychat-io/keychat-openclaw"
|
|
7
|
+
INSTALL_DIR="${OPENCLAW_EXTENSIONS:-$HOME/.openclaw/extensions}/keychat"
|
|
8
|
+
BINARY="$INSTALL_DIR/bridge/target/release/keychat-bridge"
|
|
9
|
+
|
|
10
|
+
echo "đ Installing Keychat"
|
|
11
|
+
echo ""
|
|
12
|
+
|
|
13
|
+
# ââ Check OpenClaw ââ
|
|
14
|
+
if ! command -v openclaw &>/dev/null; then
|
|
15
|
+
echo "â OpenClaw not found. Install it first: https://docs.openclaw.ai"
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
# ââ Detect platform ââ
|
|
20
|
+
detect_artifact() {
|
|
21
|
+
local arch=$(uname -m)
|
|
22
|
+
local os=$(uname -s | tr '[:upper:]' '[:lower:]')
|
|
23
|
+
case "$os-$arch" in
|
|
24
|
+
darwin-arm64) echo "keychat-openclaw-darwin-arm64" ;;
|
|
25
|
+
darwin-x86_64) echo "keychat-openclaw-darwin-x64" ;;
|
|
26
|
+
linux-x86_64) echo "keychat-openclaw-linux-x64" ;;
|
|
27
|
+
linux-aarch64) echo "keychat-openclaw-linux-arm64" ;;
|
|
28
|
+
*) echo "" ;;
|
|
29
|
+
esac
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# ââ Spinner helper ââ
|
|
33
|
+
spinner() {
|
|
34
|
+
local pid=$1
|
|
35
|
+
local msg=$2
|
|
36
|
+
local chars='⣞⣽⣝⢿⥿âŁâŁŻâŁˇ'
|
|
37
|
+
local i=0
|
|
38
|
+
while kill -0 "$pid" 2>/dev/null; do
|
|
39
|
+
printf "\r %s %s" "${chars:i++%${#chars}:1}" "$msg"
|
|
40
|
+
sleep 0.1
|
|
41
|
+
done
|
|
42
|
+
printf "\r"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# ââ Clone or update repo ââ
|
|
46
|
+
if [ -d "$INSTALL_DIR/.git" ]; then
|
|
47
|
+
echo "đŚ Updating existing installation..."
|
|
48
|
+
cd "$INSTALL_DIR"
|
|
49
|
+
git pull --ff-only 2>/dev/null || true
|
|
50
|
+
else
|
|
51
|
+
echo "đŚ Downloading Keychat source..."
|
|
52
|
+
mkdir -p "$(dirname "$INSTALL_DIR")"
|
|
53
|
+
git clone --depth 1 "https://github.com/$REPO.git" "$INSTALL_DIR" 2>/dev/null &
|
|
54
|
+
CLONE_PID=$!
|
|
55
|
+
spinner $CLONE_PID "Cloning repository..."
|
|
56
|
+
wait $CLONE_PID
|
|
57
|
+
echo " â
Source downloaded"
|
|
58
|
+
cd "$INSTALL_DIR"
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# ââ Install npm dependencies ââ
|
|
62
|
+
echo "đŚ Installing dependencies..."
|
|
63
|
+
npm install --omit=dev --silent 2>/dev/null &
|
|
64
|
+
NPM_PID=$!
|
|
65
|
+
spinner $NPM_PID "Installing npm packages (this may take a moment)..."
|
|
66
|
+
wait $NPM_PID || true
|
|
67
|
+
echo " â
Dependencies installed"
|
|
68
|
+
|
|
69
|
+
# ââ Get binary ââ
|
|
70
|
+
if [ -f "$BINARY" ]; then
|
|
71
|
+
echo "â
Bridge binary already exists"
|
|
72
|
+
else
|
|
73
|
+
ARTIFACT=$(detect_artifact)
|
|
74
|
+
DOWNLOADED=false
|
|
75
|
+
|
|
76
|
+
if [ -n "$ARTIFACT" ]; then
|
|
77
|
+
echo "đŚ Downloading bridge binary ($ARTIFACT)..."
|
|
78
|
+
echo " âł This may take 30-60 seconds depending on your connection..."
|
|
79
|
+
URL="https://github.com/$REPO/releases/latest/download/$ARTIFACT"
|
|
80
|
+
mkdir -p "$(dirname "$BINARY")"
|
|
81
|
+
if curl -fSL --progress-bar "$URL" -o "$BINARY" 2>&1; then
|
|
82
|
+
chmod +x "$BINARY"
|
|
83
|
+
echo " â
Binary downloaded"
|
|
84
|
+
DOWNLOADED=true
|
|
85
|
+
else
|
|
86
|
+
echo " â ď¸ Download failed, will try building from source..."
|
|
87
|
+
fi
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
if [ "$DOWNLOADED" = false ]; then
|
|
91
|
+
if command -v cargo &>/dev/null; then
|
|
92
|
+
echo "đ¨ Building from source..."
|
|
93
|
+
echo " âł This takes 3-5 minutes on most machines. Please wait..."
|
|
94
|
+
cd "$INSTALL_DIR/bridge"
|
|
95
|
+
cargo build --release 2>&1 &
|
|
96
|
+
BUILD_PID=$!
|
|
97
|
+
spinner $BUILD_PID "Compiling Rust code (be patient)..."
|
|
98
|
+
wait $BUILD_PID
|
|
99
|
+
cd "$INSTALL_DIR"
|
|
100
|
+
if [ ! -f "$BINARY" ]; then
|
|
101
|
+
echo " â Build failed"
|
|
102
|
+
exit 1
|
|
103
|
+
fi
|
|
104
|
+
echo " â
Built from source"
|
|
105
|
+
else
|
|
106
|
+
echo "â No pre-compiled binary for your platform and Rust not installed."
|
|
107
|
+
echo " Install Rust: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh"
|
|
108
|
+
exit 1
|
|
109
|
+
fi
|
|
110
|
+
fi
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
# ââ Register plugin ââ
|
|
114
|
+
echo ""
|
|
115
|
+
echo "đŚ Registering plugin..."
|
|
116
|
+
openclaw plugins install "$INSTALL_DIR" 2>&1 || true
|
|
117
|
+
|
|
118
|
+
# ââ Auto-configure ââ
|
|
119
|
+
CONFIG_FILE="$HOME/.openclaw/openclaw.json"
|
|
120
|
+
if [ -f "$CONFIG_FILE" ]; then
|
|
121
|
+
if grep -q '"keychat"' "$CONFIG_FILE" 2>/dev/null; then
|
|
122
|
+
echo "âšď¸ Keychat already in config"
|
|
123
|
+
else
|
|
124
|
+
if command -v python3 &>/dev/null; then
|
|
125
|
+
python3 -c "
|
|
126
|
+
import json, sys
|
|
127
|
+
try:
|
|
128
|
+
with open('$CONFIG_FILE', 'r') as f:
|
|
129
|
+
cfg = json.load(f)
|
|
130
|
+
if 'channels' not in cfg:
|
|
131
|
+
cfg['channels'] = {}
|
|
132
|
+
cfg['channels']['keychat'] = {'enabled': True}
|
|
133
|
+
with open('$CONFIG_FILE', 'w') as f:
|
|
134
|
+
json.dump(cfg, f, indent=2, ensure_ascii=False)
|
|
135
|
+
print(' â
Keychat enabled in config')
|
|
136
|
+
except Exception as e:
|
|
137
|
+
print(f' â ď¸ Could not auto-configure: {e}')
|
|
138
|
+
print(' Add manually: \"keychat\": {{\"enabled\": true}} under channels')
|
|
139
|
+
"
|
|
140
|
+
elif command -v node &>/dev/null; then
|
|
141
|
+
node -e "
|
|
142
|
+
const fs = require('fs');
|
|
143
|
+
try {
|
|
144
|
+
const cfg = JSON.parse(fs.readFileSync('$CONFIG_FILE', 'utf8'));
|
|
145
|
+
if (!cfg.channels) cfg.channels = {};
|
|
146
|
+
cfg.channels.keychat = { enabled: true };
|
|
147
|
+
fs.writeFileSync('$CONFIG_FILE', JSON.stringify(cfg, null, 2));
|
|
148
|
+
console.log(' â
Keychat enabled in config');
|
|
149
|
+
} catch(e) {
|
|
150
|
+
console.log(' â ď¸ Could not auto-configure:', e.message);
|
|
151
|
+
console.log(' Add manually: \"keychat\": {\"enabled\": true} under channels');
|
|
152
|
+
}
|
|
153
|
+
"
|
|
154
|
+
else
|
|
155
|
+
echo "â ď¸ Add to $CONFIG_FILE under \"channels\":"
|
|
156
|
+
echo ' "keychat": { "enabled": true }'
|
|
157
|
+
fi
|
|
158
|
+
fi
|
|
159
|
+
else
|
|
160
|
+
echo "â ď¸ Config not found at $CONFIG_FILE"
|
|
161
|
+
echo " Run 'openclaw init' first, then re-run this installer"
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
# ââ Restart gateway ââ
|
|
165
|
+
echo ""
|
|
166
|
+
echo "đ Restarting gateway..."
|
|
167
|
+
openclaw gateway restart 2>&1 || true
|
|
168
|
+
|
|
169
|
+
# ââ Done ââ
|
|
170
|
+
echo ""
|
|
171
|
+
echo "ââââââââââââââââââââââââââââââââââââââââ"
|
|
172
|
+
echo " đ Keychat installed successfully!"
|
|
173
|
+
echo "ââââââââââââââââââââââââââââââââââââââââ"
|
|
174
|
+
echo ""
|
|
175
|
+
echo "Your agent's Keychat ID will appear in the gateway logs."
|
|
176
|
+
echo "Run 'openclaw status' to see it."
|
|
177
|
+
echo ""
|
|
178
|
+
echo "To connect: open the Keychat app and scan the QR code."
|
|
179
|
+
echo ""
|
|
180
|
+
echo "Docs: https://github.com/$REPO"
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* postinstall â download pre-compiled keychat-bridge binary.
|
|
4
|
+
* Runs automatically after `npm install` / `openclaw plugins install`.
|
|
5
|
+
* Uses native fetch/https â no child_process dependency.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, mkdirSync, chmodSync, writeFileSync, readFileSync, rmSync } from "node:fs";
|
|
8
|
+
import { join, dirname } from "node:path";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import https from "node:https";
|
|
11
|
+
|
|
12
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const REPO = "keychat-io/keychat-openclaw";
|
|
14
|
+
const BINARY_DIR = join(__dirname, "..", "bridge", "target", "release");
|
|
15
|
+
const BINARY_PATH = join(BINARY_DIR, "keychat-bridge");
|
|
16
|
+
|
|
17
|
+
import { statSync } from "node:fs";
|
|
18
|
+
|
|
19
|
+
// Read expected version from package.json
|
|
20
|
+
const pkgPath = join(__dirname, "..", "package.json");
|
|
21
|
+
const pkgVersion = JSON.parse(readFileSync(pkgPath, "utf-8")).version;
|
|
22
|
+
const versionFile = join(BINARY_DIR, ".version");
|
|
23
|
+
|
|
24
|
+
const currentVersion = existsSync(versionFile)
|
|
25
|
+
? readFileSync(versionFile, "utf-8").trim()
|
|
26
|
+
: null;
|
|
27
|
+
|
|
28
|
+
// Clean up conflicting script-installed copy (extensions/keychat vs extensions/keychat-openclaw)
|
|
29
|
+
const pluginDir = join(__dirname, "..");
|
|
30
|
+
const pluginDirName = pluginDir.split("/").pop();
|
|
31
|
+
const scriptInstallDir = join(pluginDir, "..", "keychat");
|
|
32
|
+
if (pluginDirName === "keychat-bridge" && existsSync(scriptInstallDir)) {
|
|
33
|
+
console.log(`[keychat] Removing conflicting script-installed copy...`);
|
|
34
|
+
try { rmSync(scriptInstallDir, { recursive: true, force: true }); } catch {}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (existsSync(BINARY_PATH) && currentVersion === pkgVersion) {
|
|
38
|
+
console.log(`[keychat] Binary already exists (v${pkgVersion}), skipping download`);
|
|
39
|
+
process.exit(0);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (existsSync(BINARY_PATH)) {
|
|
43
|
+
console.log(`[keychat] Binary exists but version mismatch (${currentVersion || "unknown"} â ${pkgVersion}), re-downloading...`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const platform = process.platform; // darwin, linux
|
|
47
|
+
const arch = process.arch; // arm64, x64
|
|
48
|
+
|
|
49
|
+
const ARTIFACTS = {
|
|
50
|
+
"darwin-arm64": "keychat-openclaw-darwin-arm64",
|
|
51
|
+
"darwin-x64": "keychat-openclaw-darwin-x64",
|
|
52
|
+
"linux-x64": "keychat-openclaw-linux-x64",
|
|
53
|
+
"linux-arm64": "keychat-openclaw-linux-arm64",
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const artifact = ARTIFACTS[`${platform}-${arch}`];
|
|
57
|
+
if (!artifact) {
|
|
58
|
+
console.warn(`[keychat] No pre-compiled binary for ${platform}-${arch}`);
|
|
59
|
+
console.warn("[keychat] Build from source: cd bridge && cargo build --release");
|
|
60
|
+
process.exit(0); // Don't fail install
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const url = `https://github.com/${REPO}/releases/latest/download/${artifact}`;
|
|
64
|
+
console.log(`[keychat] Downloading ${artifact}...`);
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Download a URL following redirects, return a Buffer.
|
|
68
|
+
*/
|
|
69
|
+
function download(downloadUrl) {
|
|
70
|
+
return new Promise((resolve, reject) => {
|
|
71
|
+
https.get(downloadUrl, (res) => {
|
|
72
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
73
|
+
return download(res.headers.location).then(resolve, reject);
|
|
74
|
+
}
|
|
75
|
+
if (res.statusCode !== 200) {
|
|
76
|
+
return reject(new Error(`HTTP ${res.statusCode}`));
|
|
77
|
+
}
|
|
78
|
+
const chunks = [];
|
|
79
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
80
|
+
res.on("end", () => resolve(Buffer.concat(chunks)));
|
|
81
|
+
res.on("error", reject);
|
|
82
|
+
}).on("error", reject);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
mkdirSync(BINARY_DIR, { recursive: true });
|
|
88
|
+
const buffer = await download(url);
|
|
89
|
+
writeFileSync(BINARY_PATH, buffer);
|
|
90
|
+
chmodSync(BINARY_PATH, 0o755);
|
|
91
|
+
writeFileSync(versionFile, pkgVersion + "\n");
|
|
92
|
+
console.log(`[keychat] â
Binary installed (v${pkgVersion})`);
|
|
93
|
+
} catch (err) {
|
|
94
|
+
console.warn(`[keychat] Download failed: ${err.message}`);
|
|
95
|
+
console.warn("[keychat] Build from source: cd bridge && cargo build --release");
|
|
96
|
+
// Don't fail install â user can build manually
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Auto-initialize config if channels["keychat"] not set
|
|
100
|
+
import { homedir } from "node:os";
|
|
101
|
+
|
|
102
|
+
const configPath = join(homedir(), ".openclaw", "openclaw.json");
|
|
103
|
+
try {
|
|
104
|
+
let config = {};
|
|
105
|
+
if (existsSync(configPath)) {
|
|
106
|
+
config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (config.channels?.["keychat"] || config.channels?.keychat) {
|
|
110
|
+
console.log("[keychat] Config already contains keychat settings, skipping init");
|
|
111
|
+
// Migrate old channels.keychat â channels.keychat
|
|
112
|
+
if (config.channels?.keychat && !config.channels?.["keychat"]) {
|
|
113
|
+
config.channels["keychat"] = config.channels.keychat;
|
|
114
|
+
delete config.channels.keychat;
|
|
115
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
116
|
+
console.log("[keychat] â
Migrated channels.keychat â channels.keychat");
|
|
117
|
+
}
|
|
118
|
+
} else {
|
|
119
|
+
if (!config.channels) config.channels = {};
|
|
120
|
+
config.channels["keychat"] = { enabled: true, dmPolicy: "open" };
|
|
121
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
122
|
+
console.log('[keychat] â
Config initialized (channels.keychat.enabled = true)');
|
|
123
|
+
console.log("[keychat] Restart gateway to activate: openclaw gateway restart");
|
|
124
|
+
}
|
|
125
|
+
} catch (err) {
|
|
126
|
+
console.warn(`[keychat] Could not auto-configure: ${err.message}`);
|
|
127
|
+
console.warn('[keychat] Run manually: openclaw config set channels.keychat.enabled true');
|
|
128
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Publish @keychat-io/keychat to npm
|
|
3
|
+
# Usage: ./scripts/publish.sh [--dry-run]
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
cd "$(dirname "$0")/.."
|
|
7
|
+
|
|
8
|
+
# Load .env
|
|
9
|
+
if [ -f .env ]; then
|
|
10
|
+
export $(grep -v '^#' .env | xargs)
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
if [ -z "$NPM_TOKEN" ]; then
|
|
14
|
+
echo "â NPM_TOKEN not set. Create .env with: NPM_TOKEN=npm_xxxxx"
|
|
15
|
+
exit 1
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
# Set token for this publish
|
|
19
|
+
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc.tmp
|
|
20
|
+
|
|
21
|
+
echo "đŚ Publishing @keychat-io/keychat v$(node -p "require('./package.json').version")..."
|
|
22
|
+
npm publish --access public --tag latest --userconfig .npmrc.tmp "$@"
|
|
23
|
+
|
|
24
|
+
rm -f .npmrc.tmp
|
|
25
|
+
echo "â
Published!"
|
package/scripts/setup.sh
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Keychat OpenClaw plugin setup
|
|
3
|
+
# Downloads the bridge binary and initializes config.
|
|
4
|
+
# Run after: openclaw plugins install @keychat-io/keychat
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
# --- Locate plugin directory ---
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
9
|
+
PLUGIN_DIR="$(dirname "$SCRIPT_DIR")"
|
|
10
|
+
|
|
11
|
+
# Also check common install locations
|
|
12
|
+
if [ ! -f "$PLUGIN_DIR/package.json" ]; then
|
|
13
|
+
for d in \
|
|
14
|
+
"$HOME/.openclaw/extensions/keychat" \
|
|
15
|
+
"$HOME/.openclaw/plugins/@keychat-io/keychat"; do
|
|
16
|
+
if [ -f "$d/package.json" ]; then
|
|
17
|
+
PLUGIN_DIR="$d"
|
|
18
|
+
break
|
|
19
|
+
fi
|
|
20
|
+
done
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
BINARY_DIR="$PLUGIN_DIR/bridge/target/release"
|
|
24
|
+
BINARY_PATH="$BINARY_DIR/keychat-bridge"
|
|
25
|
+
|
|
26
|
+
# --- Download binary ---
|
|
27
|
+
if [ -f "$BINARY_PATH" ]; then
|
|
28
|
+
echo "[keychat] â
Binary already exists: $BINARY_PATH"
|
|
29
|
+
else
|
|
30
|
+
REPO="keychat-io/keychat-openclaw"
|
|
31
|
+
OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
|
|
32
|
+
ARCH="$(uname -m)"
|
|
33
|
+
|
|
34
|
+
case "$OS-$ARCH" in
|
|
35
|
+
darwin-arm64) ARTIFACT="keychat-openclaw-darwin-arm64" ;;
|
|
36
|
+
darwin-x86_64) ARTIFACT="keychat-openclaw-darwin-x64" ;;
|
|
37
|
+
linux-x86_64) ARTIFACT="keychat-openclaw-linux-x64" ;;
|
|
38
|
+
linux-aarch64) ARTIFACT="keychat-openclaw-linux-arm64" ;;
|
|
39
|
+
*)
|
|
40
|
+
echo "[keychat] â No pre-compiled binary for $OS-$ARCH"
|
|
41
|
+
echo "[keychat] Build from source: cd $PLUGIN_DIR/bridge && cargo build --release"
|
|
42
|
+
exit 1
|
|
43
|
+
;;
|
|
44
|
+
esac
|
|
45
|
+
|
|
46
|
+
URL="https://github.com/$REPO/releases/latest/download/$ARTIFACT"
|
|
47
|
+
echo "[keychat] Downloading $ARTIFACT..."
|
|
48
|
+
mkdir -p "$BINARY_DIR"
|
|
49
|
+
curl -fsSL -o "$BINARY_PATH" "$URL"
|
|
50
|
+
chmod +x "$BINARY_PATH"
|
|
51
|
+
echo "[keychat] â
Binary installed: $BINARY_PATH"
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# --- Initialize config ---
|
|
55
|
+
CONFIG_PATH="$HOME/.openclaw/openclaw.json"
|
|
56
|
+
|
|
57
|
+
if [ ! -f "$CONFIG_PATH" ]; then
|
|
58
|
+
echo '{}' > "$CONFIG_PATH"
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Check if channels.keychat already exists
|
|
62
|
+
if node -e "
|
|
63
|
+
const c = JSON.parse(require('fs').readFileSync('$CONFIG_PATH','utf-8'));
|
|
64
|
+
process.exit(c.channels?.keychat ? 0 : 1);
|
|
65
|
+
" 2>/dev/null; then
|
|
66
|
+
echo "[keychat] â
Config already has channels.keychat"
|
|
67
|
+
else
|
|
68
|
+
node -e "
|
|
69
|
+
const fs = require('fs');
|
|
70
|
+
const c = JSON.parse(fs.readFileSync('$CONFIG_PATH','utf-8'));
|
|
71
|
+
if (!c.channels) c.channels = {};
|
|
72
|
+
c.channels.keychat = { enabled: true, dmPolicy: 'open' };
|
|
73
|
+
fs.writeFileSync('$CONFIG_PATH', JSON.stringify(c, null, 2) + '\n');
|
|
74
|
+
"
|
|
75
|
+
echo "[keychat] â
Config initialized (channels.keychat.enabled = true, dmPolicy = open)"
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
echo ""
|
|
79
|
+
echo "[keychat] Setup complete! Restart gateway to activate:"
|
|
80
|
+
echo " openclaw gateway install && openclaw gateway start"
|