@long_88/openclaw-aicc-channel-cli 0.1.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.
Files changed (3) hide show
  1. package/README.md +34 -0
  2. package/cli.mjs +237 -0
  3. package/package.json +33 -0
package/README.md ADDED
@@ -0,0 +1,34 @@
1
+ # @long_88/openclaw-aicc-channel-cli
2
+
3
+ CLI installer for the `@long_88/openclaw-aicc-channel` plugin.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ npx -y @long_88/openclaw-aicc-channel-cli install
9
+ ```
10
+
11
+ Configure a bridge account while installing:
12
+
13
+ ```bash
14
+ npx -y @long_88/openclaw-aicc-channel-cli install \
15
+ --bridge-url http://127.0.0.1:9090 \
16
+ --secret bridge-secret \
17
+ --name "Default Bridge"
18
+ ```
19
+
20
+ Configure a named account:
21
+
22
+ ```bash
23
+ npx -y @long_88/openclaw-aicc-channel-cli install \
24
+ --account cn \
25
+ --bridge-url http://127.0.0.1:9091 \
26
+ --secret bridge-secret-cn \
27
+ --name "China Bridge"
28
+ ```
29
+
30
+ Preview commands without executing them:
31
+
32
+ ```bash
33
+ npx -y @long_88/openclaw-aicc-channel-cli install --dry-run
34
+ ```
package/cli.mjs ADDED
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawnSync } from "node:child_process";
4
+
5
+ const CLI_SPEC = "@long_88/openclaw-aicc-channel-cli";
6
+ const PLUGIN_SPEC = "@long_88/openclaw-aicc-channel";
7
+ const CHANNEL_ID = "aicc-channel";
8
+
9
+ function formatValue(value) {
10
+ if (/^[A-Za-z0-9_]+$/.test(value)) {
11
+ return value;
12
+ }
13
+
14
+ return JSON.stringify(value);
15
+ }
16
+
17
+ function formatCommand(args) {
18
+ if (args.length === 0) {
19
+ return "";
20
+ }
21
+
22
+ if (args.length === 1) {
23
+ return formatValue(args[0]);
24
+ }
25
+
26
+ return `${args.slice(0, -1).join(" ")} ${formatValue(args.at(-1))}`;
27
+ }
28
+
29
+ function log(message) {
30
+ console.log(`[aicc-channel] ${message}`);
31
+ }
32
+
33
+ function fail(message) {
34
+ console.error(`[aicc-channel] ${message}`);
35
+ process.exit(1);
36
+ }
37
+
38
+ function parseArgs(argv) {
39
+ const options = {
40
+ account: null,
41
+ bridgeUrl: null,
42
+ dryRun: false,
43
+ name: null,
44
+ restart: true,
45
+ secret: null
46
+ };
47
+
48
+ for (let index = 0; index < argv.length; index += 1) {
49
+ const arg = argv[index];
50
+
51
+ switch (arg) {
52
+ case "--account":
53
+ options.account = argv[index + 1] ?? null;
54
+ index += 1;
55
+ break;
56
+ case "--bridge-url":
57
+ options.bridgeUrl = argv[index + 1] ?? null;
58
+ index += 1;
59
+ break;
60
+ case "--dry-run":
61
+ options.dryRun = true;
62
+ break;
63
+ case "--name":
64
+ options.name = argv[index + 1] ?? null;
65
+ index += 1;
66
+ break;
67
+ case "--no-restart":
68
+ options.restart = false;
69
+ break;
70
+ case "--secret":
71
+ options.secret = argv[index + 1] ?? null;
72
+ index += 1;
73
+ break;
74
+ default:
75
+ fail(`unknown option: ${arg}`);
76
+ }
77
+ }
78
+
79
+ return options;
80
+ }
81
+
82
+ function channelConfigPath(options) {
83
+ if (!options.account) {
84
+ return `channels.${CHANNEL_ID}`;
85
+ }
86
+
87
+ return `channels.${CHANNEL_ID}.accounts.${options.account}`;
88
+ }
89
+
90
+ function buildCommands(options) {
91
+ const commands = [
92
+ ["openclaw", "plugins", "install", PLUGIN_SPEC],
93
+ ["openclaw", "config", "set", `plugins.entries.${CHANNEL_ID}.enabled`, "true"]
94
+ ];
95
+ const configBase = channelConfigPath(options);
96
+ const shouldWriteConfig =
97
+ options.account !== null ||
98
+ options.bridgeUrl !== null ||
99
+ options.secret !== null ||
100
+ options.name !== null;
101
+
102
+ if (options.bridgeUrl) {
103
+ commands.push(["openclaw", "config", "set", `${configBase}.bridgeUrl`, options.bridgeUrl]);
104
+ }
105
+
106
+ if (options.secret) {
107
+ commands.push(["openclaw", "config", "set", `${configBase}.secret`, options.secret]);
108
+ }
109
+
110
+ if (options.name) {
111
+ commands.push(["openclaw", "config", "set", `${configBase}.name`, options.name]);
112
+ }
113
+
114
+ if (shouldWriteConfig) {
115
+ commands.push(["openclaw", "config", "set", `${configBase}.enabled`, "true"]);
116
+ }
117
+
118
+ if (options.restart) {
119
+ commands.push(["openclaw", "gateway", "restart"]);
120
+ }
121
+
122
+ return commands;
123
+ }
124
+
125
+ function renderHelp() {
126
+ return `
127
+ Usage:
128
+ npx -y ${CLI_SPEC} install [options]
129
+ npx -y ${CLI_SPEC} help
130
+
131
+ Options:
132
+ --bridge-url <url> Set channels.aicc-channel(.accounts.<id>).bridgeUrl
133
+ --secret <value> Set channels.aicc-channel(.accounts.<id>).secret
134
+ --name <value> Set channels.aicc-channel(.accounts.<id>).name
135
+ --account <id> Write config under channels.aicc-channel.accounts.<id>
136
+ --no-restart Skip openclaw gateway restart
137
+ --dry-run Print commands without executing them
138
+ `.trim();
139
+ }
140
+
141
+ function runAndCapture(args) {
142
+ return spawnSync(args[0], args.slice(1), {
143
+ encoding: "utf8"
144
+ });
145
+ }
146
+
147
+ function ensureOpenclawAvailable() {
148
+ const result = runAndCapture(["openclaw", "--version"]);
149
+
150
+ if (result.error) {
151
+ fail("openclaw CLI was not found. Install OpenClaw first.");
152
+ }
153
+
154
+ if (result.status !== 0) {
155
+ fail(result.stderr.trim() || "unable to read openclaw version");
156
+ }
157
+
158
+ const version = result.stdout.trim();
159
+ if (version) {
160
+ log(`detected ${version}`);
161
+ }
162
+ }
163
+
164
+ function runCommand(args) {
165
+ log(`running: ${formatCommand(args)}`);
166
+ const result = runAndCapture(args);
167
+
168
+ if (result.status === 0) {
169
+ if (result.stdout.trim()) {
170
+ process.stdout.write(result.stdout);
171
+ if (!result.stdout.endsWith("\n")) {
172
+ process.stdout.write("\n");
173
+ }
174
+ }
175
+ return result;
176
+ }
177
+
178
+ if (result.stderr.trim()) {
179
+ process.stderr.write(result.stderr);
180
+ if (!result.stderr.endsWith("\n")) {
181
+ process.stderr.write("\n");
182
+ }
183
+ }
184
+
185
+ return result;
186
+ }
187
+
188
+ function install(options) {
189
+ const commands = buildCommands(options);
190
+
191
+ if (options.dryRun) {
192
+ for (const command of commands) {
193
+ console.log(formatCommand(command));
194
+ }
195
+ return;
196
+ }
197
+
198
+ ensureOpenclawAvailable();
199
+
200
+ const installResult = runCommand(commands[0]);
201
+ if (installResult.status !== 0) {
202
+ const combinedOutput = `${installResult.stdout ?? ""}\n${installResult.stderr ?? ""}`;
203
+
204
+ if (combinedOutput.includes("already exists")) {
205
+ const updateResult = runCommand(["openclaw", "plugins", "update", CHANNEL_ID]);
206
+ if (updateResult.status !== 0) {
207
+ fail("plugin update failed");
208
+ }
209
+ } else {
210
+ fail("plugin install failed");
211
+ }
212
+ }
213
+
214
+ for (const command of commands.slice(1)) {
215
+ const result = runCommand(command);
216
+ if (result.status !== 0) {
217
+ fail(`command failed: ${formatCommand(command)}`);
218
+ }
219
+ }
220
+ }
221
+
222
+ const command = process.argv[2];
223
+
224
+ switch (command) {
225
+ case "help":
226
+ case "--help":
227
+ case "-h":
228
+ case undefined:
229
+ console.log(renderHelp());
230
+ process.exit(0);
231
+ break;
232
+ case "install":
233
+ install(parseArgs(process.argv.slice(3)));
234
+ break;
235
+ default:
236
+ fail(`unknown command: ${command}`);
237
+ }
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@long_88/openclaw-aicc-channel-cli",
3
+ "version": "0.1.0",
4
+ "description": "CLI installer for the OpenClaw AICC channel plugin.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "bin": {
8
+ "aicc-channel-installer": "./cli.mjs"
9
+ },
10
+ "files": [
11
+ "cli.mjs",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "test": "vitest run"
16
+ },
17
+ "engines": {
18
+ "node": ">=22"
19
+ },
20
+ "peerDependencies": {
21
+ "openclaw": "*"
22
+ },
23
+ "peerDependenciesMeta": {
24
+ "openclaw": {
25
+ "optional": true
26
+ }
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^24.5.2",
30
+ "typescript": "^5.9.2",
31
+ "vitest": "^3.2.4"
32
+ }
33
+ }