@silicaclaw/cli 1.0.0-beta.0 → 1.0.0-beta.10
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/INSTALL.md +31 -4
- package/README.md +36 -5
- package/package.json +6 -1
- package/packages/core/dist/crypto.d.ts +6 -0
- package/packages/core/dist/crypto.js +50 -0
- package/packages/core/dist/directory.d.ts +17 -0
- package/packages/core/dist/directory.js +145 -0
- package/packages/core/dist/identity.d.ts +2 -0
- package/packages/core/dist/identity.js +18 -0
- package/packages/core/dist/index.d.ts +11 -0
- package/packages/core/dist/index.js +27 -0
- package/packages/core/dist/indexing.d.ts +6 -0
- package/packages/core/dist/indexing.js +43 -0
- package/packages/core/dist/presence.d.ts +4 -0
- package/packages/core/dist/presence.js +23 -0
- package/packages/core/dist/profile.d.ts +4 -0
- package/packages/core/dist/profile.js +39 -0
- package/packages/core/dist/publicProfileSummary.d.ts +70 -0
- package/packages/core/dist/publicProfileSummary.js +103 -0
- package/packages/core/dist/socialConfig.d.ts +99 -0
- package/packages/core/dist/socialConfig.js +287 -0
- package/packages/core/dist/socialResolver.d.ts +46 -0
- package/packages/core/dist/socialResolver.js +227 -0
- package/packages/core/dist/socialTemplate.d.ts +2 -0
- package/packages/core/dist/socialTemplate.js +88 -0
- package/packages/core/dist/types.d.ts +37 -0
- package/packages/core/dist/types.js +2 -0
- package/packages/network/dist/abstractions/messageEnvelope.d.ts +28 -0
- package/packages/network/dist/abstractions/messageEnvelope.js +36 -0
- package/packages/network/dist/abstractions/peerDiscovery.d.ts +43 -0
- package/packages/network/dist/abstractions/peerDiscovery.js +2 -0
- package/packages/network/dist/abstractions/topicCodec.d.ts +4 -0
- package/packages/network/dist/abstractions/topicCodec.js +2 -0
- package/packages/network/dist/abstractions/transport.d.ts +36 -0
- package/packages/network/dist/abstractions/transport.js +2 -0
- package/packages/network/dist/codec/jsonMessageEnvelopeCodec.d.ts +5 -0
- package/packages/network/dist/codec/jsonMessageEnvelopeCodec.js +24 -0
- package/packages/network/dist/codec/jsonTopicCodec.d.ts +5 -0
- package/packages/network/dist/codec/jsonTopicCodec.js +12 -0
- package/packages/network/dist/discovery/heartbeatPeerDiscovery.d.ts +28 -0
- package/packages/network/dist/discovery/heartbeatPeerDiscovery.js +144 -0
- package/packages/network/dist/index.d.ts +13 -0
- package/packages/network/dist/index.js +29 -0
- package/packages/network/dist/localEventBus.d.ts +9 -0
- package/packages/network/dist/localEventBus.js +47 -0
- package/packages/network/dist/mock.d.ts +8 -0
- package/packages/network/dist/mock.js +24 -0
- package/packages/network/dist/realPreview.d.ts +105 -0
- package/packages/network/dist/realPreview.js +327 -0
- package/packages/network/dist/transport/udpLanBroadcastTransport.d.ts +23 -0
- package/packages/network/dist/transport/udpLanBroadcastTransport.js +153 -0
- package/packages/network/dist/types.d.ts +6 -0
- package/packages/network/dist/types.js +2 -0
- package/packages/network/dist/webrtcPreview.d.ts +163 -0
- package/packages/network/dist/webrtcPreview.js +844 -0
- package/packages/storage/dist/index.d.ts +3 -0
- package/packages/storage/dist/index.js +19 -0
- package/packages/storage/dist/jsonRepo.d.ts +7 -0
- package/packages/storage/dist/jsonRepo.js +29 -0
- package/packages/storage/dist/repos.d.ts +21 -0
- package/packages/storage/dist/repos.js +41 -0
- package/packages/storage/dist/socialRuntimeRepo.d.ts +5 -0
- package/packages/storage/dist/socialRuntimeRepo.js +52 -0
- package/packages/storage/tsconfig.json +6 -1
- package/scripts/quickstart.sh +198 -21
- package/scripts/silicaclaw-cli.mjs +103 -0
- package/scripts/silicaclaw-gateway.mjs +321 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./jsonRepo"), exports);
|
|
18
|
+
__exportStar(require("./repos"), exports);
|
|
19
|
+
__exportStar(require("./socialRuntimeRepo"), exports);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JsonFileRepo = void 0;
|
|
4
|
+
const promises_1 = require("fs/promises");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
class JsonFileRepo {
|
|
7
|
+
filePath;
|
|
8
|
+
fallback;
|
|
9
|
+
constructor(filePath, fallback) {
|
|
10
|
+
this.filePath = filePath;
|
|
11
|
+
this.fallback = fallback;
|
|
12
|
+
}
|
|
13
|
+
async get() {
|
|
14
|
+
try {
|
|
15
|
+
const raw = await (0, promises_1.readFile)(this.filePath, "utf8");
|
|
16
|
+
return JSON.parse(raw);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
const seed = this.fallback();
|
|
20
|
+
await this.set(seed);
|
|
21
|
+
return seed;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
async set(value) {
|
|
25
|
+
await (0, promises_1.mkdir)((0, path_1.dirname)(this.filePath), { recursive: true });
|
|
26
|
+
await (0, promises_1.writeFile)(this.filePath, JSON.stringify(value, null, 2), "utf8");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.JsonFileRepo = JsonFileRepo;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { AgentIdentity, DirectoryState, PublicProfile } from "@silicaclaw/core";
|
|
2
|
+
import { JsonFileRepo } from "./jsonRepo";
|
|
3
|
+
export type LogEntry = {
|
|
4
|
+
id: string;
|
|
5
|
+
level: "info" | "warn" | "error";
|
|
6
|
+
message: string;
|
|
7
|
+
timestamp: number;
|
|
8
|
+
};
|
|
9
|
+
export declare class IdentityRepo extends JsonFileRepo<AgentIdentity | null> {
|
|
10
|
+
constructor(rootDir?: string);
|
|
11
|
+
}
|
|
12
|
+
export declare class ProfileRepo extends JsonFileRepo<PublicProfile | null> {
|
|
13
|
+
constructor(rootDir?: string);
|
|
14
|
+
}
|
|
15
|
+
export declare class CacheRepo extends JsonFileRepo<DirectoryState> {
|
|
16
|
+
constructor(rootDir?: string);
|
|
17
|
+
}
|
|
18
|
+
export declare class LogRepo extends JsonFileRepo<LogEntry[]> {
|
|
19
|
+
constructor(rootDir?: string);
|
|
20
|
+
append(entry: Omit<LogEntry, "id">): Promise<void>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LogRepo = exports.CacheRepo = exports.ProfileRepo = exports.IdentityRepo = void 0;
|
|
4
|
+
const path_1 = require("path");
|
|
5
|
+
const core_1 = require("@silicaclaw/core");
|
|
6
|
+
const jsonRepo_1 = require("./jsonRepo");
|
|
7
|
+
class IdentityRepo extends jsonRepo_1.JsonFileRepo {
|
|
8
|
+
constructor(rootDir = process.cwd()) {
|
|
9
|
+
super((0, path_1.resolve)(rootDir, "data", "identity.json"), () => null);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.IdentityRepo = IdentityRepo;
|
|
13
|
+
class ProfileRepo extends jsonRepo_1.JsonFileRepo {
|
|
14
|
+
constructor(rootDir = process.cwd()) {
|
|
15
|
+
super((0, path_1.resolve)(rootDir, "data", "profile.json"), () => null);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.ProfileRepo = ProfileRepo;
|
|
19
|
+
class CacheRepo extends jsonRepo_1.JsonFileRepo {
|
|
20
|
+
constructor(rootDir = process.cwd()) {
|
|
21
|
+
super((0, path_1.resolve)(rootDir, "data", "cache.json"), () => (0, core_1.createEmptyDirectoryState)());
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.CacheRepo = CacheRepo;
|
|
25
|
+
class LogRepo extends jsonRepo_1.JsonFileRepo {
|
|
26
|
+
constructor(rootDir = process.cwd()) {
|
|
27
|
+
super((0, path_1.resolve)(rootDir, "data", "logs.json"), () => []);
|
|
28
|
+
}
|
|
29
|
+
async append(entry) {
|
|
30
|
+
const current = await this.get();
|
|
31
|
+
const next = [
|
|
32
|
+
{
|
|
33
|
+
id: `${entry.timestamp}-${Math.random().toString(36).slice(2, 8)}`,
|
|
34
|
+
...entry,
|
|
35
|
+
},
|
|
36
|
+
...current,
|
|
37
|
+
].slice(0, 50);
|
|
38
|
+
await this.set(next);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
exports.LogRepo = LogRepo;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SocialRuntimeRepo = void 0;
|
|
4
|
+
const path_1 = require("path");
|
|
5
|
+
const jsonRepo_1 = require("./jsonRepo");
|
|
6
|
+
function emptyRuntime() {
|
|
7
|
+
return {
|
|
8
|
+
enabled: true,
|
|
9
|
+
public_enabled: false,
|
|
10
|
+
source_path: null,
|
|
11
|
+
last_loaded_at: 0,
|
|
12
|
+
social_found: false,
|
|
13
|
+
parse_error: null,
|
|
14
|
+
resolved_identity: null,
|
|
15
|
+
resolved_profile: null,
|
|
16
|
+
resolved_network: {
|
|
17
|
+
mode: "lan",
|
|
18
|
+
adapter: "real-preview",
|
|
19
|
+
namespace: "silicaclaw.preview",
|
|
20
|
+
port: null,
|
|
21
|
+
signaling_url: "http://localhost:4510",
|
|
22
|
+
signaling_urls: [],
|
|
23
|
+
room: "silicaclaw-room",
|
|
24
|
+
seed_peers: [],
|
|
25
|
+
bootstrap_hints: [],
|
|
26
|
+
bootstrap_sources: [],
|
|
27
|
+
},
|
|
28
|
+
resolved_discovery: {
|
|
29
|
+
discoverable: true,
|
|
30
|
+
allow_profile_broadcast: true,
|
|
31
|
+
allow_presence_broadcast: true,
|
|
32
|
+
},
|
|
33
|
+
visibility: {
|
|
34
|
+
show_display_name: true,
|
|
35
|
+
show_bio: true,
|
|
36
|
+
show_tags: true,
|
|
37
|
+
show_agent_id: true,
|
|
38
|
+
show_last_seen: true,
|
|
39
|
+
show_capabilities_summary: true,
|
|
40
|
+
},
|
|
41
|
+
openclaw: {
|
|
42
|
+
bind_existing_identity: true,
|
|
43
|
+
use_openclaw_profile_if_available: true,
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
class SocialRuntimeRepo extends jsonRepo_1.JsonFileRepo {
|
|
48
|
+
constructor(rootDir = process.cwd()) {
|
|
49
|
+
super((0, path_1.resolve)(rootDir, ".silicaclaw", "social.runtime.json"), emptyRuntime);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.SocialRuntimeRepo = SocialRuntimeRepo;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"extends": "../../tsconfig.base.json",
|
|
3
3
|
"compilerOptions": {
|
|
4
|
-
"outDir": "./dist"
|
|
4
|
+
"outDir": "./dist",
|
|
5
|
+
"rootDir": "./src",
|
|
6
|
+
"baseUrl": ".",
|
|
7
|
+
"paths": {
|
|
8
|
+
"@silicaclaw/core": ["../../node_modules/@silicaclaw/core/dist/index.d.ts"]
|
|
9
|
+
}
|
|
5
10
|
},
|
|
6
11
|
"include": ["src"]
|
|
7
12
|
}
|
package/scripts/quickstart.sh
CHANGED
|
@@ -1,8 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
set -euo pipefail
|
|
3
3
|
|
|
4
|
+
INVOKE_PWD="${INIT_CWD:-$PWD}"
|
|
4
5
|
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
|
-
|
|
6
|
+
WORK_DIR="$ROOT_DIR"
|
|
7
|
+
IS_NPX_MODE=0
|
|
8
|
+
DEFAULT_MODE_PICK="${QUICKSTART_DEFAULT_MODE:-1}"
|
|
9
|
+
CONNECT_MODE="${QUICKSTART_CONNECT_MODE:-0}"
|
|
10
|
+
|
|
11
|
+
case "$DEFAULT_MODE_PICK" in
|
|
12
|
+
1|2|3) ;;
|
|
13
|
+
*) DEFAULT_MODE_PICK="1" ;;
|
|
14
|
+
esac
|
|
15
|
+
|
|
16
|
+
case "$ROOT_DIR" in
|
|
17
|
+
*"/.npm/_npx/"*)
|
|
18
|
+
IS_NPX_MODE=1
|
|
19
|
+
;;
|
|
20
|
+
esac
|
|
6
21
|
|
|
7
22
|
STEP=1
|
|
8
23
|
|
|
@@ -22,6 +37,16 @@ run_cmd() {
|
|
|
22
37
|
eval "$cmd"
|
|
23
38
|
}
|
|
24
39
|
|
|
40
|
+
run_cmd_may_fail() {
|
|
41
|
+
local cmd="$1"
|
|
42
|
+
printf '→ %s\n' "$cmd"
|
|
43
|
+
set +e
|
|
44
|
+
eval "$cmd"
|
|
45
|
+
local code=$?
|
|
46
|
+
set -e
|
|
47
|
+
return $code
|
|
48
|
+
}
|
|
49
|
+
|
|
25
50
|
ask_yes_no() {
|
|
26
51
|
local prompt="$1"
|
|
27
52
|
local default="${2:-Y}"
|
|
@@ -43,11 +68,76 @@ pause_continue() {
|
|
|
43
68
|
read -r -p "按回车继续..." _ || true
|
|
44
69
|
}
|
|
45
70
|
|
|
71
|
+
detect_public_ip() {
|
|
72
|
+
local ip=""
|
|
73
|
+
if command -v curl >/dev/null 2>&1; then
|
|
74
|
+
ip="$(curl -fsSL --max-time 3 https://api.ipify.org 2>/dev/null || true)"
|
|
75
|
+
fi
|
|
76
|
+
if [ -z "$ip" ] && command -v curl >/dev/null 2>&1; then
|
|
77
|
+
ip="$(curl -fsSL --max-time 3 https://ifconfig.me 2>/dev/null || true)"
|
|
78
|
+
fi
|
|
79
|
+
if [ -z "$ip" ] && command -v wget >/dev/null 2>&1; then
|
|
80
|
+
ip="$(wget -qO- --timeout=3 https://api.ipify.org 2>/dev/null || true)"
|
|
81
|
+
fi
|
|
82
|
+
ip="$(printf '%s' "$ip" | tr -d '[:space:]')"
|
|
83
|
+
printf '%s' "$ip"
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
url_host() {
|
|
87
|
+
local raw="${1:-}"
|
|
88
|
+
if [ -z "$raw" ]; then
|
|
89
|
+
printf ''
|
|
90
|
+
return 0
|
|
91
|
+
fi
|
|
92
|
+
node -e "try{const u=new URL(process.argv[1]); process.stdout.write(u.hostname||'');}catch{process.stdout.write('');}" "$raw"
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
url_port_or_default() {
|
|
96
|
+
local raw="${1:-}"
|
|
97
|
+
local fallback="${2:-4510}"
|
|
98
|
+
if [ -z "$raw" ]; then
|
|
99
|
+
printf '%s' "$fallback"
|
|
100
|
+
return 0
|
|
101
|
+
fi
|
|
102
|
+
node -e "try{const u=new URL(process.argv[1]); process.stdout.write(String(u.port || '$fallback'));}catch{process.stdout.write('$fallback');}" "$raw"
|
|
103
|
+
}
|
|
104
|
+
|
|
46
105
|
title "SilicaClaw Quick Start 启动"
|
|
47
106
|
echo "目录: $ROOT_DIR"
|
|
48
107
|
echo "目标: 用终端一步步完成安装与启动(类似 OpenClaw Quick Start)"
|
|
49
108
|
pause_continue
|
|
50
109
|
|
|
110
|
+
if [ "$IS_NPX_MODE" -eq 1 ]; then
|
|
111
|
+
title "选择安装目录(npx 模式)"
|
|
112
|
+
DEFAULT_TARGET_DIR="$INVOKE_PWD/silicaclaw"
|
|
113
|
+
TARGET_DIR_INPUT=""
|
|
114
|
+
read -r -p "请输入安装目录(默认: ${DEFAULT_TARGET_DIR:-$HOME/silicaclaw}): " TARGET_DIR_INPUT || true
|
|
115
|
+
TARGET_DIR="${TARGET_DIR_INPUT:-$DEFAULT_TARGET_DIR}"
|
|
116
|
+
TARGET_DIR="${TARGET_DIR/#\~/$HOME}"
|
|
117
|
+
|
|
118
|
+
if [ -e "$TARGET_DIR" ] && [ ! -d "$TARGET_DIR" ]; then
|
|
119
|
+
echo "目标路径存在且不是目录: $TARGET_DIR"
|
|
120
|
+
exit 1
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
mkdir -p "$TARGET_DIR"
|
|
124
|
+
echo "正在复制项目文件到: $TARGET_DIR"
|
|
125
|
+
if command -v rsync >/dev/null 2>&1; then
|
|
126
|
+
rsync -a --delete \
|
|
127
|
+
--exclude '.git/' \
|
|
128
|
+
--exclude 'node_modules/' \
|
|
129
|
+
--exclude '.npm-cache/' \
|
|
130
|
+
--exclude '*.tgz' \
|
|
131
|
+
"$ROOT_DIR/" "$TARGET_DIR/"
|
|
132
|
+
else
|
|
133
|
+
cp -R "$ROOT_DIR/." "$TARGET_DIR/"
|
|
134
|
+
rm -rf "$TARGET_DIR/.git" "$TARGET_DIR/node_modules" "$TARGET_DIR/.npm-cache"
|
|
135
|
+
fi
|
|
136
|
+
WORK_DIR="$TARGET_DIR"
|
|
137
|
+
echo "工作目录已切换到: $WORK_DIR"
|
|
138
|
+
pause_continue
|
|
139
|
+
fi
|
|
140
|
+
|
|
51
141
|
title "检查 Node.js / npm"
|
|
52
142
|
if ! command -v node >/dev/null 2>&1; then
|
|
53
143
|
echo "未找到 node,请先安装 Node.js 18+"
|
|
@@ -69,23 +159,46 @@ if ! node -e "const v=process.versions.node.split('.').map(Number); if (v[0] < 1
|
|
|
69
159
|
fi
|
|
70
160
|
|
|
71
161
|
title "安装依赖"
|
|
72
|
-
if [ ! -d "$
|
|
73
|
-
run_cmd "npm install"
|
|
162
|
+
if [ ! -d "$WORK_DIR/node_modules" ]; then
|
|
163
|
+
run_cmd "cd \"$WORK_DIR\" && npm_config_cache=\"$WORK_DIR/.npm-cache\" npm install"
|
|
74
164
|
else
|
|
75
165
|
if ask_yes_no "检测到 node_modules,是否仍执行 npm install 同步依赖?" "N"; then
|
|
76
|
-
run_cmd "npm install"
|
|
166
|
+
run_cmd "cd \"$WORK_DIR\" && npm_config_cache=\"$WORK_DIR/.npm-cache\" npm install"
|
|
77
167
|
else
|
|
78
168
|
echo "跳过 npm install"
|
|
79
169
|
fi
|
|
80
170
|
fi
|
|
81
171
|
|
|
172
|
+
title "安装系统命令(silicaclaw)"
|
|
173
|
+
if command -v silicaclaw >/dev/null 2>&1; then
|
|
174
|
+
echo "已检测到系统命令: $(command -v silicaclaw)"
|
|
175
|
+
echo "跳过全局安装。"
|
|
176
|
+
else
|
|
177
|
+
echo "为了获得生产体验(可直接运行 silicaclaw ...),建议安装全局命令。"
|
|
178
|
+
if ask_yes_no "是否现在安装全局命令 @silicaclaw/cli@beta?" "Y"; then
|
|
179
|
+
if run_cmd_may_fail "npm_config_cache=\"$WORK_DIR/.npm-cache\" npm i -g @silicaclaw/cli@beta"; then
|
|
180
|
+
echo "全局命令安装成功。"
|
|
181
|
+
else
|
|
182
|
+
echo "普通权限安装失败(常见于 macOS /usr/local 权限)。"
|
|
183
|
+
if ask_yes_no "是否使用 sudo 重试安装全局命令?" "Y"; then
|
|
184
|
+
run_cmd "npm_config_cache=\"$WORK_DIR/.npm-cache\" sudo npm i -g @silicaclaw/cli@beta"
|
|
185
|
+
echo "全局命令安装成功。"
|
|
186
|
+
else
|
|
187
|
+
echo "已跳过全局安装。你仍可使用: npx @silicaclaw/cli@beta <command>"
|
|
188
|
+
fi
|
|
189
|
+
fi
|
|
190
|
+
else
|
|
191
|
+
echo "已跳过全局安装。你仍可使用: npx @silicaclaw/cli@beta <command>"
|
|
192
|
+
fi
|
|
193
|
+
fi
|
|
194
|
+
|
|
82
195
|
title "准备 social.md"
|
|
83
|
-
if [ -f "$
|
|
196
|
+
if [ -f "$WORK_DIR/social.md" ]; then
|
|
84
197
|
echo "已存在 social.md,保留现有配置。"
|
|
85
198
|
else
|
|
86
199
|
if ask_yes_no "未找到 social.md,是否自动从 social.md.example 生成?" "Y"; then
|
|
87
|
-
run_cmd "cp social.md.example social.md"
|
|
88
|
-
echo "已生成: $
|
|
200
|
+
run_cmd "cd \"$WORK_DIR\" && cp social.md.example social.md"
|
|
201
|
+
echo "已生成: $WORK_DIR/social.md"
|
|
89
202
|
else
|
|
90
203
|
echo "跳过生成 social.md(local-console 首启也会自动生成最小模板)"
|
|
91
204
|
fi
|
|
@@ -95,13 +208,21 @@ title "选择网络模式"
|
|
|
95
208
|
echo "1) local 单机预览(最快)"
|
|
96
209
|
echo "2) lan 局域网预览(A/B 双机)"
|
|
97
210
|
echo "3) global-preview 非局域网预览(WebRTC)"
|
|
98
|
-
|
|
99
|
-
|
|
211
|
+
echo "提示: 不确定就直接回车(默认 local)。"
|
|
212
|
+
echo "提示: 只有在你已有可达 signaling 地址时,才选择 3。"
|
|
213
|
+
if [ "$CONNECT_MODE" = "1" ]; then
|
|
214
|
+
MODE_PICK="3"
|
|
215
|
+
echo "connect 模式:已自动选择 global-preview。"
|
|
216
|
+
else
|
|
217
|
+
read -r -p "请输入模式编号 [1/2/3] (默认 ${DEFAULT_MODE_PICK}): " MODE_PICK || true
|
|
218
|
+
MODE_PICK="${MODE_PICK:-$DEFAULT_MODE_PICK}"
|
|
219
|
+
fi
|
|
100
220
|
|
|
101
221
|
NETWORK_MODE="local"
|
|
102
222
|
NETWORK_ADAPTER="local-event-bus"
|
|
103
223
|
WEBRTC_SIGNALING_URL_VALUE=""
|
|
104
224
|
WEBRTC_ROOM_VALUE="silicaclaw-demo"
|
|
225
|
+
AUTO_START_SIGNALING=0
|
|
105
226
|
|
|
106
227
|
case "$MODE_PICK" in
|
|
107
228
|
2)
|
|
@@ -111,11 +232,37 @@ case "$MODE_PICK" in
|
|
|
111
232
|
3)
|
|
112
233
|
NETWORK_MODE="global-preview"
|
|
113
234
|
NETWORK_ADAPTER="webrtc-preview"
|
|
114
|
-
|
|
235
|
+
PUBLIC_IP="$(detect_public_ip)"
|
|
236
|
+
SIGNALING_DEFAULT="${WEBRTC_SIGNALING_URL:-http://localhost:4510}"
|
|
237
|
+
if [ -n "$PUBLIC_IP" ]; then
|
|
238
|
+
SIGNALING_DEFAULT="http://$PUBLIC_IP:4510"
|
|
239
|
+
fi
|
|
240
|
+
echo "提示: signaling 地址需要“所有节点可访问”。"
|
|
241
|
+
if [ -n "$PUBLIC_IP" ]; then
|
|
242
|
+
echo "已检测到本机公网 IP: $PUBLIC_IP"
|
|
243
|
+
echo "如果你这台机器就是 signaling 服务器,可直接回车使用默认值。"
|
|
244
|
+
else
|
|
245
|
+
echo "未检测到公网 IP,将使用默认值: $SIGNALING_DEFAULT"
|
|
246
|
+
echo "如果 signaling 在其他机器,请输入该机器公网地址。"
|
|
247
|
+
fi
|
|
248
|
+
read -r -p "请输入 signaling URL(默认 ${SIGNALING_DEFAULT}): " WEBRTC_SIGNALING_URL_INPUT || true
|
|
249
|
+
WEBRTC_SIGNALING_URL_VALUE="${WEBRTC_SIGNALING_URL_INPUT:-$SIGNALING_DEFAULT}"
|
|
115
250
|
if [ -z "${WEBRTC_SIGNALING_URL_VALUE:-}" ]; then
|
|
116
251
|
echo "global-preview 必须提供 signaling URL"
|
|
117
252
|
exit 1
|
|
118
253
|
fi
|
|
254
|
+
|
|
255
|
+
SIGNALING_HOST="$(url_host "$WEBRTC_SIGNALING_URL_VALUE")"
|
|
256
|
+
if [ "$SIGNALING_HOST" = "localhost" ] || [ "$SIGNALING_HOST" = "127.0.0.1" ]; then
|
|
257
|
+
echo "提示: 当前 signaling URL 是本机地址,仅本机可用,不适合跨网络双机演示。"
|
|
258
|
+
fi
|
|
259
|
+
|
|
260
|
+
if ask_yes_no "是否在当前机器自动后台启动 signaling server(用于演示)?" "Y"; then
|
|
261
|
+
AUTO_START_SIGNALING=1
|
|
262
|
+
SIGNALING_PORT_VALUE="$(url_port_or_default "$WEBRTC_SIGNALING_URL_VALUE" "4510")"
|
|
263
|
+
echo "将尝试以 PORT=$SIGNALING_PORT_VALUE 后台启动 signaling server"
|
|
264
|
+
fi
|
|
265
|
+
|
|
119
266
|
read -r -p "请输入 room(默认 silicaclaw-demo): " WEBRTC_ROOM_VALUE_INPUT || true
|
|
120
267
|
WEBRTC_ROOM_VALUE="${WEBRTC_ROOM_VALUE_INPUT:-silicaclaw-demo}"
|
|
121
268
|
;;
|
|
@@ -128,17 +275,47 @@ esac
|
|
|
128
275
|
echo "已选择: $NETWORK_MODE ($NETWORK_ADAPTER)"
|
|
129
276
|
|
|
130
277
|
title "启动 local-console"
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
278
|
+
echo "1) gateway(推荐) 后台服务模式,可用 start/stop/restart/status 管理"
|
|
279
|
+
echo "2) dev watch 前台开发模式(tsx watch)"
|
|
280
|
+
read -r -p "请选择启动方式 [1/2] (默认 1): " START_MODE_PICK || true
|
|
281
|
+
START_MODE_PICK="${START_MODE_PICK:-1}"
|
|
282
|
+
|
|
283
|
+
if [ "$START_MODE_PICK" = "2" ]; then
|
|
284
|
+
if [ "$NETWORK_MODE" = "global-preview" ]; then
|
|
285
|
+
if [ "$AUTO_START_SIGNALING" -eq 1 ]; then
|
|
286
|
+
mkdir -p "$WORK_DIR/.silicaclaw"
|
|
287
|
+
SIGNALING_LOG="$WORK_DIR/.silicaclaw/signaling.log"
|
|
288
|
+
SIGNALING_PID_FILE="$WORK_DIR/.silicaclaw/signaling.pid"
|
|
289
|
+
run_cmd "cd \"$WORK_DIR\" && PORT=${SIGNALING_PORT_VALUE:-4510} nohup npm run webrtc-signaling > \"$SIGNALING_LOG\" 2>&1 & echo \$! > \"$SIGNALING_PID_FILE\""
|
|
290
|
+
echo "已后台启动 signaling server,日志: $SIGNALING_LOG"
|
|
291
|
+
echo "停止 signaling: kill \$(cat \"$SIGNALING_PID_FILE\")"
|
|
292
|
+
fi
|
|
293
|
+
echo "将使用以下参数启动(dev watch):"
|
|
294
|
+
echo "NETWORK_ADAPTER=$NETWORK_ADAPTER"
|
|
295
|
+
echo "WEBRTC_SIGNALING_URL=$WEBRTC_SIGNALING_URL_VALUE"
|
|
296
|
+
echo "WEBRTC_ROOM=$WEBRTC_ROOM_VALUE"
|
|
297
|
+
pause_continue
|
|
298
|
+
run_cmd "cd \"$WORK_DIR\" && NETWORK_ADAPTER=$NETWORK_ADAPTER WEBRTC_SIGNALING_URL=$WEBRTC_SIGNALING_URL_VALUE WEBRTC_ROOM=$WEBRTC_ROOM_VALUE npm run local-console"
|
|
299
|
+
else
|
|
300
|
+
echo "将使用以下参数启动(dev watch):"
|
|
301
|
+
echo "NETWORK_ADAPTER=$NETWORK_ADAPTER"
|
|
302
|
+
pause_continue
|
|
303
|
+
run_cmd "cd \"$WORK_DIR\" && NETWORK_ADAPTER=$NETWORK_ADAPTER npm run local-console"
|
|
304
|
+
fi
|
|
138
305
|
else
|
|
139
|
-
|
|
140
|
-
|
|
306
|
+
GATEWAY_CMD="cd \"$WORK_DIR\" && npm run gateway -- start --mode=$NETWORK_MODE"
|
|
307
|
+
if [ "$NETWORK_MODE" = "global-preview" ]; then
|
|
308
|
+
GATEWAY_CMD="$GATEWAY_CMD --signaling-url=$WEBRTC_SIGNALING_URL_VALUE --room=$WEBRTC_ROOM_VALUE"
|
|
309
|
+
fi
|
|
310
|
+
echo "将使用 gateway 后台启动:"
|
|
311
|
+
echo "$GATEWAY_CMD"
|
|
141
312
|
pause_continue
|
|
142
|
-
run_cmd "
|
|
313
|
+
run_cmd "$GATEWAY_CMD"
|
|
314
|
+
echo ""
|
|
315
|
+
echo "已启动完成。常用命令:"
|
|
316
|
+
echo "cd \"$WORK_DIR\" && npm run gateway -- status"
|
|
317
|
+
echo "cd \"$WORK_DIR\" && npm run gateway -- logs local-console"
|
|
318
|
+
echo "cd \"$WORK_DIR\" && npm run gateway -- stop"
|
|
319
|
+
echo ""
|
|
320
|
+
echo "打开: http://localhost:4310"
|
|
143
321
|
fi
|
|
144
|
-
|
|
@@ -23,18 +23,101 @@ function run(cmd, args, extra = {}) {
|
|
|
23
23
|
process.exit(result.status ?? 0);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
function runCapture(cmd, args, extra = {}) {
|
|
27
|
+
const result = spawnSync(cmd, args, {
|
|
28
|
+
cwd: ROOT_DIR,
|
|
29
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
30
|
+
encoding: "utf8",
|
|
31
|
+
env: process.env,
|
|
32
|
+
...extra,
|
|
33
|
+
});
|
|
34
|
+
if (result.error) {
|
|
35
|
+
throw result.error;
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
|
|
26
40
|
function readVersion() {
|
|
27
41
|
const versionFile = resolve(ROOT_DIR, "VERSION");
|
|
28
42
|
if (!existsSync(versionFile)) return "unknown";
|
|
29
43
|
return readFileSync(versionFile, "utf8").trim() || "unknown";
|
|
30
44
|
}
|
|
31
45
|
|
|
46
|
+
function readPackageVersion() {
|
|
47
|
+
const pkgFile = resolve(ROOT_DIR, "package.json");
|
|
48
|
+
if (!existsSync(pkgFile)) return "unknown";
|
|
49
|
+
try {
|
|
50
|
+
const pkg = JSON.parse(readFileSync(pkgFile, "utf8"));
|
|
51
|
+
return String(pkg.version || "unknown");
|
|
52
|
+
} catch {
|
|
53
|
+
return "unknown";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isNpxRun() {
|
|
58
|
+
return ROOT_DIR.includes("/.npm/_npx/");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function showUpdateGuide(current, latest, beta) {
|
|
62
|
+
console.log("SilicaClaw update check");
|
|
63
|
+
console.log(`current: ${current}`);
|
|
64
|
+
console.log(`latest : ${latest || "-"}`);
|
|
65
|
+
console.log(`beta : ${beta || "-"}`);
|
|
66
|
+
console.log("");
|
|
67
|
+
|
|
68
|
+
const upToDate = Boolean(beta) && current === beta;
|
|
69
|
+
if (upToDate) {
|
|
70
|
+
console.log("You are already on the latest beta.");
|
|
71
|
+
} else {
|
|
72
|
+
console.log("Update available.");
|
|
73
|
+
}
|
|
74
|
+
console.log("");
|
|
75
|
+
console.log("Recommended commands:");
|
|
76
|
+
console.log("1) npx mode (no global install)");
|
|
77
|
+
console.log(" npx @silicaclaw/cli@beta onboard");
|
|
78
|
+
console.log(" npx @silicaclaw/cli@beta connect");
|
|
79
|
+
console.log("");
|
|
80
|
+
console.log("2) global install mode");
|
|
81
|
+
console.log(" npm i -g @silicaclaw/cli@beta");
|
|
82
|
+
console.log(" silicaclaw version");
|
|
83
|
+
console.log("");
|
|
84
|
+
if (isNpxRun()) {
|
|
85
|
+
console.log("Detected npx runtime: use npx commands above for immediate update.");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function update() {
|
|
90
|
+
const current = readPackageVersion();
|
|
91
|
+
try {
|
|
92
|
+
const result = runCapture("npm", ["view", "@silicaclaw/cli", "dist-tags", "--json"]);
|
|
93
|
+
if ((result.status ?? 1) !== 0) {
|
|
94
|
+
console.error("Failed to query npm dist-tags.");
|
|
95
|
+
if (result.stderr) console.error(result.stderr.trim());
|
|
96
|
+
process.exit(result.status ?? 1);
|
|
97
|
+
}
|
|
98
|
+
const text = String(result.stdout || "").trim();
|
|
99
|
+
const tags = text ? JSON.parse(text) : {};
|
|
100
|
+
const latest = tags.latest ? String(tags.latest) : "";
|
|
101
|
+
const beta = tags.beta ? String(tags.beta) : "";
|
|
102
|
+
showUpdateGuide(current, latest, beta);
|
|
103
|
+
process.exit(0);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
console.error(`Update check failed: ${error.message}`);
|
|
106
|
+
console.log("Try manually:");
|
|
107
|
+
console.log("npm view @silicaclaw/cli dist-tags --json");
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
32
112
|
function help() {
|
|
33
113
|
console.log(`
|
|
34
114
|
SilicaClaw CLI
|
|
35
115
|
|
|
36
116
|
Usage:
|
|
37
117
|
silicaclaw onboard
|
|
118
|
+
silicaclaw connect
|
|
119
|
+
silicaclaw update
|
|
120
|
+
silicaclaw gateway <start|stop|restart|status|logs>
|
|
38
121
|
silicaclaw local-console
|
|
39
122
|
silicaclaw explorer
|
|
40
123
|
silicaclaw signaling
|
|
@@ -44,6 +127,9 @@ Usage:
|
|
|
44
127
|
|
|
45
128
|
Commands:
|
|
46
129
|
onboard Interactive step-by-step onboarding (recommended)
|
|
130
|
+
connect Cross-network connect wizard (global-preview first)
|
|
131
|
+
update Check latest npm version and show upgrade commands
|
|
132
|
+
gateway Manage background services (start/stop/restart/status/logs)
|
|
47
133
|
local-console Start local console (http://localhost:4310)
|
|
48
134
|
explorer Start public explorer (http://localhost:4311)
|
|
49
135
|
signaling Start WebRTC signaling preview server
|
|
@@ -59,6 +145,23 @@ switch (cmd) {
|
|
|
59
145
|
case "onboard":
|
|
60
146
|
run("bash", [resolve(ROOT_DIR, "scripts", "quickstart.sh")]);
|
|
61
147
|
break;
|
|
148
|
+
case "connect":
|
|
149
|
+
run("bash", [resolve(ROOT_DIR, "scripts", "quickstart.sh")], {
|
|
150
|
+
env: {
|
|
151
|
+
...process.env,
|
|
152
|
+
QUICKSTART_DEFAULT_MODE: "3",
|
|
153
|
+
QUICKSTART_CONNECT_MODE: "1",
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
break;
|
|
157
|
+
case "update":
|
|
158
|
+
update();
|
|
159
|
+
break;
|
|
160
|
+
case "gateway":
|
|
161
|
+
run("node", [resolve(ROOT_DIR, "scripts", "silicaclaw-gateway.mjs"), ...process.argv.slice(3)], {
|
|
162
|
+
cwd: process.cwd(),
|
|
163
|
+
});
|
|
164
|
+
break;
|
|
62
165
|
case "local-console":
|
|
63
166
|
case "console":
|
|
64
167
|
run("npm", ["run", "local-console"]);
|