@shadowob/connector 1.1.3-dev.281 → 1.1.4
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/README.md +23 -5
- package/dist/cli.js +379 -53
- package/dist/index.cjs +52 -18
- package/dist/index.js +50 -18
- package/hermes-shadowob-plugin/shadow_sdk.py +26 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,6 +98,11 @@ export SHADOW_SLASH_COMMANDS_JSON='[]'
|
|
|
98
98
|
|
|
99
99
|
## cc-connect
|
|
100
100
|
|
|
101
|
+
The connector uses the ShadowOB-capable fork
|
|
102
|
+
`buggyblues/cc-connect@63b5d59`. It does not install the official npm
|
|
103
|
+
`cc-connect` package, because the npm package currently points to the upstream
|
|
104
|
+
`chenhg5/cc-connect` release line.
|
|
105
|
+
|
|
101
106
|
```bash
|
|
102
107
|
npx @shadowob/connector@latest connect \
|
|
103
108
|
--target cc-connect \
|
|
@@ -105,9 +110,18 @@ npx @shadowob/connector@latest connect \
|
|
|
105
110
|
--token buddy-token \
|
|
106
111
|
--work-dir . \
|
|
107
112
|
--project-name shadow-buddy \
|
|
108
|
-
--agent-type codex
|
|
113
|
+
--agent-type codex \
|
|
114
|
+
--install \
|
|
115
|
+
--start
|
|
109
116
|
```
|
|
110
117
|
|
|
118
|
+
With `--install`, the CLI first tries the fork's GitHub release asset matching
|
|
119
|
+
the local OS/CPU and verifies its pinned SHA-256. If the fork release asset is
|
|
120
|
+
missing or does not match, it pulls the pinned source archive, builds a `no_web`
|
|
121
|
+
Go binary, caches it under
|
|
122
|
+
`~/.shadowob/connector/cc-connect/63b5d59/bin/`, and starts that binary when
|
|
123
|
+
`--start` is present.
|
|
124
|
+
|
|
111
125
|
Equivalent TOML:
|
|
112
126
|
|
|
113
127
|
```toml
|
|
@@ -115,8 +129,12 @@ language = "zh"
|
|
|
115
129
|
|
|
116
130
|
[[projects]]
|
|
117
131
|
name = "shadow-buddy"
|
|
132
|
+
|
|
133
|
+
[projects.agent]
|
|
134
|
+
type = "codex"
|
|
135
|
+
|
|
136
|
+
[projects.agent.options]
|
|
118
137
|
work_dir = "."
|
|
119
|
-
agent_type = "codex"
|
|
120
138
|
|
|
121
139
|
[[projects.platforms]]
|
|
122
140
|
type = "shadowob"
|
|
@@ -160,6 +178,6 @@ The tests cover plan generation, config merging for OpenClaw/Hermes/cc-connect,
|
|
|
160
178
|
|
|
161
179
|
## Capability Coverage
|
|
162
180
|
|
|
163
|
-
- OpenClaw: channel messages, DMs, threads, mentions, attachments/images, interactive components, slash commands, online status, typing/activity, reactions, edits/deletes.
|
|
164
|
-
- Hermes Agent: channel messages, DMs, threads, attachments/images, interactive components, slash commands, online status, typing/activity, cron delivery.
|
|
165
|
-
- cc-connect: channel messages, DMs, attachments/images, interactive components, slash commands, typing, streaming previews, forms.
|
|
181
|
+
- OpenClaw: channel messages, DMs, threads, mentions, attachments/images, interactive components, slash commands, online status, typing/activity, reactions, edits/deletes, status checks, usage/cost telemetry, multi-Agent Buddy binding, Shadow CLI login/notifications, official skills, cron tasks.
|
|
182
|
+
- Hermes Agent: channel messages, DMs, threads, attachments/images, interactive components, slash commands, online status, typing/activity, cron delivery, status checks, usage/cost telemetry, Shadow CLI login/notifications, official skills.
|
|
183
|
+
- cc-connect: channel messages, DMs, attachments/images, interactive components, slash commands, typing, streaming previews, forms, status checks, usage/cost telemetry, multi-Agent Buddy binding, Shadow CLI login/notifications.
|
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,280 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import { spawnSync } from "child_process";
|
|
5
|
-
import { cpSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
4
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
5
|
+
import { cpSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
6
|
+
import { homedir as homedir2 } from "os";
|
|
7
|
+
import { dirname as dirname2, resolve as resolve2 } from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
|
|
10
|
+
// src/cc-connect-installer.ts
|
|
11
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
12
|
+
import { createHash } from "crypto";
|
|
13
|
+
import {
|
|
14
|
+
chmodSync,
|
|
15
|
+
existsSync,
|
|
16
|
+
mkdirSync,
|
|
17
|
+
readdirSync,
|
|
18
|
+
renameSync,
|
|
19
|
+
rmSync,
|
|
20
|
+
writeFileSync
|
|
21
|
+
} from "fs";
|
|
22
|
+
import { get as httpGet } from "http";
|
|
23
|
+
import { get as httpsGet } from "https";
|
|
6
24
|
import { homedir } from "os";
|
|
7
25
|
import { dirname, resolve } from "path";
|
|
8
|
-
|
|
26
|
+
|
|
27
|
+
// src/cc-connect-fork.ts
|
|
28
|
+
var CC_CONNECT_FORK_REPO = "buggyblues/cc-connect";
|
|
29
|
+
var CC_CONNECT_FORK_REF = "63b5d59127b3004bc7002f2d51892b1f2a91ea83";
|
|
30
|
+
var CC_CONNECT_FORK_SHORT_REF = CC_CONNECT_FORK_REF.slice(0, 7);
|
|
31
|
+
var CC_CONNECT_FORK_PACKAGE_VERSION = "1.3.3-beta.5";
|
|
32
|
+
var CC_CONNECT_FORK_DOCS_URL = `https://github.com/${CC_CONNECT_FORK_REPO}/blob/main/docs/shadowob.md`;
|
|
33
|
+
|
|
34
|
+
// src/cc-connect-installer.ts
|
|
35
|
+
var NAME = "cc-connect";
|
|
36
|
+
var RELEASE_ARCHIVE_SHA256 = {
|
|
37
|
+
"cc-connect-v1.3.3-beta.5-darwin-amd64.tar.gz": "71677cd565f6ea79e186ffc1b842e4548faa3baeb2e3dd2ced25ab2e95c416a3",
|
|
38
|
+
"cc-connect-v1.3.3-beta.5-darwin-arm64.tar.gz": "c1fc5a3d4cfe6db97a5d864ea844dbfd86345b89cea3d89871330568e6eb43cf",
|
|
39
|
+
"cc-connect-v1.3.3-beta.5-linux-amd64.tar.gz": "812484d19733044c8c5d67d997a921e351e2ae4e9a200ce5ae258ab338400bc1",
|
|
40
|
+
"cc-connect-v1.3.3-beta.5-linux-arm64.tar.gz": "290110a60e905f5e25f6133f52c1b3988ab6aeff1b1199318398cfef06f81e9a",
|
|
41
|
+
"cc-connect-v1.3.3-beta.5-windows-amd64.zip": "a90f8a669a48412fc5896613173b5e9b3dc5fdebdee731b6f6b9d4625a200952",
|
|
42
|
+
"cc-connect-v1.3.3-beta.5-windows-arm64.zip": "3c5ff24769d95c42b95a717949dc6369169c029e1110ab4bdd76d12e0043d283"
|
|
43
|
+
};
|
|
44
|
+
var PLATFORM_MAP = {
|
|
45
|
+
darwin: "darwin",
|
|
46
|
+
linux: "linux",
|
|
47
|
+
win32: "windows"
|
|
48
|
+
};
|
|
49
|
+
var ARCH_MAP = {
|
|
50
|
+
x64: "amd64",
|
|
51
|
+
arm64: "arm64"
|
|
52
|
+
};
|
|
53
|
+
function log(options, message) {
|
|
54
|
+
options.log?.(message);
|
|
55
|
+
}
|
|
56
|
+
function quoteArg(value) {
|
|
57
|
+
return /^[A-Za-z0-9_./:@=-]+$/.test(value) ? value : JSON.stringify(value);
|
|
58
|
+
}
|
|
59
|
+
function expandHome(value) {
|
|
60
|
+
return value.startsWith("~/") ? resolve(homedir(), value.slice(2)) : resolve(value);
|
|
61
|
+
}
|
|
62
|
+
function installRoot() {
|
|
63
|
+
const override = process.env.SHADOW_CC_CONNECT_HOME?.trim();
|
|
64
|
+
return override ? expandHome(override) : resolve(homedir(), ".shadowob/connector/cc-connect");
|
|
65
|
+
}
|
|
66
|
+
function binaryName() {
|
|
67
|
+
return process.platform === "win32" ? `${NAME}.exe` : NAME;
|
|
68
|
+
}
|
|
69
|
+
function cachedBinaryPath() {
|
|
70
|
+
return resolve(installRoot(), CC_CONNECT_FORK_SHORT_REF, "bin", binaryName());
|
|
71
|
+
}
|
|
72
|
+
function runCommand(command, args, options) {
|
|
73
|
+
const rendered = [command, ...args].map(quoteArg).join(" ");
|
|
74
|
+
if (options.dryRun) {
|
|
75
|
+
console.log(`[dry-run] ${rendered}`);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const result = spawnSync(command, args, {
|
|
79
|
+
cwd: options.cwd,
|
|
80
|
+
env: options.env,
|
|
81
|
+
stdio: "inherit"
|
|
82
|
+
});
|
|
83
|
+
if (result.status !== 0) {
|
|
84
|
+
throw new Error(`Command failed with exit code ${result.status ?? "unknown"}: ${rendered}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function platformInfo() {
|
|
88
|
+
const platform = PLATFORM_MAP[process.platform];
|
|
89
|
+
const arch = ARCH_MAP[process.arch];
|
|
90
|
+
if (!platform || !arch) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Unsupported cc-connect platform: ${process.platform}/${process.arch}. Supported: linux/darwin/windows x64/arm64`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
return { platform, arch, ext: platform === "windows" ? ".zip" : ".tar.gz" };
|
|
96
|
+
}
|
|
97
|
+
function fetchBuffer(url, redirects = 5) {
|
|
98
|
+
return new Promise((resolvePromise, reject) => {
|
|
99
|
+
if (redirects <= 0) {
|
|
100
|
+
reject(new Error(`Too many redirects for ${url}`));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const client = url.startsWith("https:") ? httpsGet : httpGet;
|
|
104
|
+
const request = client(url, { headers: { "User-Agent": "shadowob-connector" } }, (response) => {
|
|
105
|
+
const location = response.headers.location;
|
|
106
|
+
if (response.statusCode && response.statusCode >= 300 && response.statusCode < 400 && location) {
|
|
107
|
+
response.resume();
|
|
108
|
+
const next = new URL(location, url).toString();
|
|
109
|
+
resolvePromise(fetchBuffer(next, redirects - 1));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (response.statusCode !== 200) {
|
|
113
|
+
response.resume();
|
|
114
|
+
reject(new Error(`HTTP ${response.statusCode ?? "unknown"} for ${url}`));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const chunks = [];
|
|
118
|
+
response.on("data", (chunk) => chunks.push(chunk));
|
|
119
|
+
response.on("end", () => resolvePromise(Buffer.concat(chunks)));
|
|
120
|
+
response.on("error", reject);
|
|
121
|
+
});
|
|
122
|
+
request.on("error", reject);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function findExtractedBinary(dir) {
|
|
126
|
+
const expected = binaryName();
|
|
127
|
+
const entries = readdirSync(dir);
|
|
128
|
+
if (entries.includes(expected)) return resolve(dir, expected);
|
|
129
|
+
return entries.filter((entry) => entry.startsWith(NAME)).map((entry) => resolve(dir, entry)).find(
|
|
130
|
+
(entry) => process.platform === "win32" ? entry.endsWith(".exe") : !entry.endsWith(".gz")
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
function extractReleaseArchive(archivePath, binDir, ext) {
|
|
134
|
+
if (ext === ".tar.gz") {
|
|
135
|
+
runCommand("tar", ["xzf", archivePath, "-C", binDir], { dryRun: false });
|
|
136
|
+
} else {
|
|
137
|
+
const unzip = spawnSync("unzip", ["-o", archivePath, "-d", binDir], { stdio: "inherit" });
|
|
138
|
+
if (unzip.status !== 0) {
|
|
139
|
+
runCommand("powershell", ["-Command", `Expand-Archive -Force '${archivePath}' '${binDir}'`], {
|
|
140
|
+
dryRun: false
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const extracted = findExtractedBinary(binDir);
|
|
145
|
+
const target = resolve(binDir, binaryName());
|
|
146
|
+
if (!extracted) throw new Error("cc-connect release archive did not contain a binary");
|
|
147
|
+
if (extracted !== target) renameSync(extracted, target);
|
|
148
|
+
}
|
|
149
|
+
function verifyReleaseChecksum(filename, data) {
|
|
150
|
+
const expected = RELEASE_ARCHIVE_SHA256[filename];
|
|
151
|
+
if (!expected) throw new Error(`No pinned SHA-256 for ${filename}`);
|
|
152
|
+
const actual = createHash("sha256").update(data).digest("hex");
|
|
153
|
+
if (actual !== expected) {
|
|
154
|
+
throw new Error(`SHA-256 mismatch for ${filename}: expected ${expected}, got ${actual}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async function installFromRelease(binaryPath, options) {
|
|
158
|
+
const { platform, arch, ext } = platformInfo();
|
|
159
|
+
const version = `v${CC_CONNECT_FORK_PACKAGE_VERSION}`;
|
|
160
|
+
const filename = `${NAME}-${version}-${platform}-${arch}${ext}`;
|
|
161
|
+
const url = `https://github.com/${CC_CONNECT_FORK_REPO}/releases/download/${version}/${filename}`;
|
|
162
|
+
const binDir = dirname(binaryPath);
|
|
163
|
+
const archivePath = resolve(binDir, `_release${ext}`);
|
|
164
|
+
log(options, `[cc-connect] Trying fork release asset ${url}`);
|
|
165
|
+
try {
|
|
166
|
+
const data = await fetchBuffer(url);
|
|
167
|
+
verifyReleaseChecksum(filename, data);
|
|
168
|
+
mkdirSync(binDir, { recursive: true });
|
|
169
|
+
writeFileSync(archivePath, data);
|
|
170
|
+
extractReleaseArchive(archivePath, binDir, ext);
|
|
171
|
+
rmSync(archivePath, { force: true });
|
|
172
|
+
if (process.platform !== "win32") chmodSync(binaryPath, 493);
|
|
173
|
+
return true;
|
|
174
|
+
} catch (error) {
|
|
175
|
+
rmSync(archivePath, { force: true });
|
|
176
|
+
log(
|
|
177
|
+
options,
|
|
178
|
+
`[cc-connect] Fork release asset unavailable (${error instanceof Error ? error.message : String(error)}); building from source`
|
|
179
|
+
);
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async function ensureSourceArchive(options) {
|
|
184
|
+
const sourceDir = resolve(installRoot(), CC_CONNECT_FORK_SHORT_REF, "source");
|
|
185
|
+
if (existsSync(resolve(sourceDir, "go.mod"))) return sourceDir;
|
|
186
|
+
if (existsSync(sourceDir)) rmSync(sourceDir, { recursive: true, force: true });
|
|
187
|
+
const parent = dirname(sourceDir);
|
|
188
|
+
const extractDir = resolve(parent, `_source-${process.pid}-${Date.now()}`);
|
|
189
|
+
const archivePath = resolve(parent, `${CC_CONNECT_FORK_SHORT_REF}.tar.gz`);
|
|
190
|
+
const sourceUrl = `https://github.com/${CC_CONNECT_FORK_REPO}/archive/${CC_CONNECT_FORK_REF}.tar.gz`;
|
|
191
|
+
log(options, `[cc-connect] Pulling fork source ${sourceUrl}`);
|
|
192
|
+
mkdirSync(parent, { recursive: true });
|
|
193
|
+
const data = await fetchBuffer(sourceUrl);
|
|
194
|
+
writeFileSync(archivePath, data);
|
|
195
|
+
mkdirSync(extractDir, { recursive: true });
|
|
196
|
+
try {
|
|
197
|
+
runCommand("tar", ["xzf", archivePath, "-C", extractDir], { dryRun: false });
|
|
198
|
+
const extracted = readdirSync(extractDir, { withFileTypes: true }).find(
|
|
199
|
+
(entry) => entry.isDirectory()
|
|
200
|
+
);
|
|
201
|
+
if (!extracted) throw new Error("cc-connect source archive did not contain a directory");
|
|
202
|
+
mkdirSync(dirname(sourceDir), { recursive: true });
|
|
203
|
+
renameSync(resolve(extractDir, extracted.name), sourceDir);
|
|
204
|
+
} finally {
|
|
205
|
+
rmSync(archivePath, { force: true });
|
|
206
|
+
rmSync(extractDir, { recursive: true, force: true });
|
|
207
|
+
}
|
|
208
|
+
return sourceDir;
|
|
209
|
+
}
|
|
210
|
+
async function buildFromSource(binaryPath, options) {
|
|
211
|
+
const sourceDir = await ensureSourceArchive(options);
|
|
212
|
+
const buildTime = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
213
|
+
const ldflags = [
|
|
214
|
+
"-s",
|
|
215
|
+
"-w",
|
|
216
|
+
"-X",
|
|
217
|
+
"main.version=dev",
|
|
218
|
+
"-X",
|
|
219
|
+
`main.commit=${CC_CONNECT_FORK_SHORT_REF}`,
|
|
220
|
+
"-X",
|
|
221
|
+
`main.buildTime=${buildTime}`
|
|
222
|
+
].join(" ");
|
|
223
|
+
mkdirSync(dirname(binaryPath), { recursive: true });
|
|
224
|
+
runCommand(
|
|
225
|
+
"go",
|
|
226
|
+
["build", "-tags", "no_web", "-ldflags", ldflags, "-o", binaryPath, "./cmd/cc-connect"],
|
|
227
|
+
{
|
|
228
|
+
cwd: sourceDir,
|
|
229
|
+
dryRun: false,
|
|
230
|
+
env: goBuildEnv()
|
|
231
|
+
}
|
|
232
|
+
);
|
|
233
|
+
if (process.platform !== "win32") chmodSync(binaryPath, 493);
|
|
234
|
+
}
|
|
235
|
+
function goBuildEnv() {
|
|
236
|
+
return {
|
|
237
|
+
...process.env,
|
|
238
|
+
CGO_ENABLED: "0",
|
|
239
|
+
GOPROXY: process.env.SHADOW_CC_CONNECT_GOPROXY?.trim() || "https://proxy.golang.org,direct",
|
|
240
|
+
GOSUMDB: process.env.SHADOW_CC_CONNECT_GOSUMDB?.trim() || process.env.GOSUMDB || "sum.golang.org"
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function binaryLooksUsable(path) {
|
|
244
|
+
if (!existsSync(path)) return false;
|
|
245
|
+
try {
|
|
246
|
+
const out = execFileSync(path, ["--version"], { encoding: "utf8", timeout: 5e3 });
|
|
247
|
+
return out.includes(CC_CONNECT_FORK_SHORT_REF) || out.includes(CC_CONNECT_FORK_PACKAGE_VERSION);
|
|
248
|
+
} catch {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async function ensureCcConnectFork(options) {
|
|
253
|
+
const override = process.env.SHADOW_CC_CONNECT_BIN?.trim();
|
|
254
|
+
if (override) {
|
|
255
|
+
const binaryPath2 = expandHome(override);
|
|
256
|
+
if (!existsSync(binaryPath2))
|
|
257
|
+
throw new Error(`SHADOW_CC_CONNECT_BIN does not exist: ${binaryPath2}`);
|
|
258
|
+
return { binaryPath: binaryPath2, source: "env" };
|
|
259
|
+
}
|
|
260
|
+
const binaryPath = cachedBinaryPath();
|
|
261
|
+
if (binaryLooksUsable(binaryPath)) {
|
|
262
|
+
return { binaryPath, source: "cache" };
|
|
263
|
+
}
|
|
264
|
+
if (options.dryRun) {
|
|
265
|
+
console.log(
|
|
266
|
+
`[dry-run] install ${CC_CONNECT_FORK_REPO}@${CC_CONNECT_FORK_SHORT_REF} -> ${binaryPath}`
|
|
267
|
+
);
|
|
268
|
+
return { binaryPath, source: "source" };
|
|
269
|
+
}
|
|
270
|
+
mkdirSync(dirname(binaryPath), { recursive: true });
|
|
271
|
+
const fromRelease = await installFromRelease(binaryPath, options);
|
|
272
|
+
if (!fromRelease) await buildFromSource(binaryPath, options);
|
|
273
|
+
if (!binaryLooksUsable(binaryPath)) {
|
|
274
|
+
throw new Error(`Installed cc-connect binary did not pass version verification: ${binaryPath}`);
|
|
275
|
+
}
|
|
276
|
+
return { binaryPath, source: fromRelease ? "release" : "source" };
|
|
277
|
+
}
|
|
9
278
|
|
|
10
279
|
// src/config-writers.ts
|
|
11
280
|
import { parse as parseDotenv } from "dotenv";
|
|
@@ -150,17 +419,30 @@ function tomlArray(value) {
|
|
|
150
419
|
}
|
|
151
420
|
return tables;
|
|
152
421
|
}
|
|
422
|
+
function ccConnectProjectWorkDir(project) {
|
|
423
|
+
const agent = asTomlTable(project.agent);
|
|
424
|
+
const options = asTomlTable(agent.options);
|
|
425
|
+
return typeof options.work_dir === "string" ? options.work_dir : typeof project.work_dir === "string" ? project.work_dir : void 0;
|
|
426
|
+
}
|
|
153
427
|
function mergeCcConnectConfigContent(existing, values) {
|
|
154
428
|
const root = parseTomlRoot(existing, "cc-connect");
|
|
155
429
|
const projects = tomlArray(root.projects);
|
|
156
|
-
let project = projects.find((item) => item.name === values.projectName) ?? projects.find((item) => item
|
|
430
|
+
let project = projects.find((item) => item.name === values.projectName) ?? projects.find((item) => ccConnectProjectWorkDir(item) === values.workDir);
|
|
157
431
|
if (!project) {
|
|
158
432
|
project = {};
|
|
159
433
|
projects.push(project);
|
|
160
434
|
}
|
|
161
435
|
project.name = values.projectName;
|
|
162
|
-
project.work_dir
|
|
163
|
-
project.agent_type
|
|
436
|
+
delete project.work_dir;
|
|
437
|
+
delete project.agent_type;
|
|
438
|
+
const agent = asTomlTable(project.agent);
|
|
439
|
+
const agentOptions = asTomlTable(agent.options);
|
|
440
|
+
agent.type = values.agentType;
|
|
441
|
+
agent.options = {
|
|
442
|
+
...agentOptions,
|
|
443
|
+
work_dir: values.workDir
|
|
444
|
+
};
|
|
445
|
+
project.agent = agent;
|
|
164
446
|
const platforms = tomlArray(project.platforms);
|
|
165
447
|
let shadowPlatform = platforms.find((item) => item.type === "shadowob");
|
|
166
448
|
if (!shadowPlatform) {
|
|
@@ -270,7 +552,14 @@ function buildOpenClawPlan(input) {
|
|
|
270
552
|
"typing",
|
|
271
553
|
"activityStatus",
|
|
272
554
|
"reactions",
|
|
273
|
-
"editDelete"
|
|
555
|
+
"editDelete",
|
|
556
|
+
"statusChecks",
|
|
557
|
+
"usageCosts",
|
|
558
|
+
"multiAgentBinding",
|
|
559
|
+
"shadowCliLogin",
|
|
560
|
+
"notifications",
|
|
561
|
+
"officialSkills",
|
|
562
|
+
"cronTasks"
|
|
274
563
|
]
|
|
275
564
|
};
|
|
276
565
|
}
|
|
@@ -356,7 +645,12 @@ function buildHermesPlan(input) {
|
|
|
356
645
|
"onlineStatus",
|
|
357
646
|
"typing",
|
|
358
647
|
"activityStatus",
|
|
359
|
-
"cronDelivery"
|
|
648
|
+
"cronDelivery",
|
|
649
|
+
"statusChecks",
|
|
650
|
+
"usageCosts",
|
|
651
|
+
"shadowCliLogin",
|
|
652
|
+
"notifications",
|
|
653
|
+
"officialSkills"
|
|
360
654
|
]
|
|
361
655
|
};
|
|
362
656
|
}
|
|
@@ -371,8 +665,12 @@ function buildCcConnectPlan(input) {
|
|
|
371
665
|
"",
|
|
372
666
|
"[[projects]]",
|
|
373
667
|
`name = "${projectName}"`,
|
|
668
|
+
"",
|
|
669
|
+
"[projects.agent]",
|
|
670
|
+
`type = "${agentType}"`,
|
|
671
|
+
"",
|
|
672
|
+
"[projects.agent.options]",
|
|
374
673
|
`work_dir = "${workDir}"`,
|
|
375
|
-
`agent_type = "${agentType}"`,
|
|
376
674
|
"",
|
|
377
675
|
"[[projects.platforms]]",
|
|
378
676
|
'type = "shadowob"',
|
|
@@ -385,15 +683,6 @@ function buildCcConnectPlan(input) {
|
|
|
385
683
|
"share_session_in_channel = false",
|
|
386
684
|
'progress_style = "compact"'
|
|
387
685
|
].join("\n");
|
|
388
|
-
const commands = [
|
|
389
|
-
{ label: "Install cc-connect", command: "npm install -g cc-connect" },
|
|
390
|
-
{ label: "Create config directory", command: "mkdir -p ~/.cc-connect" },
|
|
391
|
-
{
|
|
392
|
-
label: "Edit config",
|
|
393
|
-
command: "$EDITOR ~/.cc-connect/config.toml"
|
|
394
|
-
},
|
|
395
|
-
{ label: "Start cc-connect", command: "cc-connect" }
|
|
396
|
-
];
|
|
397
686
|
const connectCommand = [
|
|
398
687
|
"npx @shadowob/connector@latest connect",
|
|
399
688
|
"--target cc-connect",
|
|
@@ -403,12 +692,26 @@ function buildCcConnectPlan(input) {
|
|
|
403
692
|
`--project-name ${shellQuote(projectName)}`,
|
|
404
693
|
`--agent-type ${shellQuote(agentType)}`
|
|
405
694
|
].join(" ");
|
|
695
|
+
const installCommand = `${connectCommand} --install`;
|
|
696
|
+
const startCommand = `${connectCommand} --install --start`;
|
|
697
|
+
const commands = [
|
|
698
|
+
{
|
|
699
|
+
label: "Install ShadowOB cc-connect fork",
|
|
700
|
+
command: installCommand
|
|
701
|
+
},
|
|
702
|
+
{ label: "Create config directory", command: "mkdir -p ~/.cc-connect" },
|
|
703
|
+
{
|
|
704
|
+
label: "Edit config",
|
|
705
|
+
command: "$EDITOR ~/.cc-connect/config.toml"
|
|
706
|
+
},
|
|
707
|
+
{ label: "Start ShadowOB cc-connect fork", command: startCommand }
|
|
708
|
+
];
|
|
406
709
|
return {
|
|
407
710
|
target: "cc-connect",
|
|
408
711
|
title: "cc-connect",
|
|
409
|
-
summary:
|
|
410
|
-
connectCommand,
|
|
411
|
-
quickCommand:
|
|
712
|
+
summary: `Use ${CC_CONNECT_FORK_REPO}@${CC_CONNECT_FORK_SHORT_REF} with ShadowOB Socket.IO platform support for this Buddy token.`,
|
|
713
|
+
connectCommand: startCommand,
|
|
714
|
+
quickCommand: startCommand,
|
|
412
715
|
commands,
|
|
413
716
|
configBlocks: [{ label: "~/.cc-connect/config.toml", language: "toml", content: tomlConfig }],
|
|
414
717
|
aiPrompt: [
|
|
@@ -419,9 +722,9 @@ function buildCcConnectPlan(input) {
|
|
|
419
722
|
`Project work_dir: ${workDir}`,
|
|
420
723
|
`Agent type: ${agentType}`,
|
|
421
724
|
"",
|
|
422
|
-
|
|
725
|
+
`Install ${CC_CONNECT_FORK_REPO}@${CC_CONNECT_FORK_SHORT_REF}, add the TOML platform block, and start cc-connect.`
|
|
423
726
|
].join("\n"),
|
|
424
|
-
docsUrl:
|
|
727
|
+
docsUrl: CC_CONNECT_FORK_DOCS_URL,
|
|
425
728
|
capabilities: [
|
|
426
729
|
"channelMessages",
|
|
427
730
|
"dms",
|
|
@@ -431,7 +734,12 @@ function buildCcConnectPlan(input) {
|
|
|
431
734
|
"slashCommands",
|
|
432
735
|
"typing",
|
|
433
736
|
"streamingPreviews",
|
|
434
|
-
"forms"
|
|
737
|
+
"forms",
|
|
738
|
+
"statusChecks",
|
|
739
|
+
"usageCosts",
|
|
740
|
+
"multiAgentBinding",
|
|
741
|
+
"shadowCliLogin",
|
|
742
|
+
"notifications"
|
|
435
743
|
]
|
|
436
744
|
};
|
|
437
745
|
}
|
|
@@ -469,7 +777,7 @@ function usage() {
|
|
|
469
777
|
" --agent-type <type> cc-connect agent type, default codex",
|
|
470
778
|
" --json Print the full plan as JSON",
|
|
471
779
|
" --force Overwrite target config files when needed",
|
|
472
|
-
" --install Install cc-connect when target is cc-connect",
|
|
780
|
+
" --install Install the ShadowOB cc-connect fork when target is cc-connect",
|
|
473
781
|
" --no-install Skip Hermes dependency install and plugin enablement",
|
|
474
782
|
" --start Start Hermes gateway or cc-connect after setup",
|
|
475
783
|
" --dry-run Show what would be applied without changing files"
|
|
@@ -527,28 +835,39 @@ function runShell(command, dryRun) {
|
|
|
527
835
|
console.log(`[dry-run] ${command}`);
|
|
528
836
|
return;
|
|
529
837
|
}
|
|
530
|
-
const result =
|
|
838
|
+
const result = spawnSync2(command, { shell: true, stdio: "inherit" });
|
|
531
839
|
if (result.status !== 0) {
|
|
532
840
|
throw new Error(`Command failed with exit code ${result.status ?? "unknown"}: ${command}`);
|
|
533
841
|
}
|
|
534
842
|
}
|
|
843
|
+
function runBinary(binaryPath, args, dryRun) {
|
|
844
|
+
const rendered = [binaryPath, ...args].map((arg) => /^[A-Za-z0-9_./:@=-]+$/.test(arg) ? arg : JSON.stringify(arg)).join(" ");
|
|
845
|
+
if (dryRun) {
|
|
846
|
+
console.log(`[dry-run] ${rendered}`);
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
const result = spawnSync2(binaryPath, args, { stdio: "inherit" });
|
|
850
|
+
if (result.status !== 0) {
|
|
851
|
+
throw new Error(`Command failed with exit code ${result.status ?? "unknown"}: ${rendered}`);
|
|
852
|
+
}
|
|
853
|
+
}
|
|
535
854
|
function writeFile(path, content, dryRun) {
|
|
536
855
|
if (dryRun) {
|
|
537
856
|
console.log(`[dry-run] write ${path}`);
|
|
538
857
|
return;
|
|
539
858
|
}
|
|
540
|
-
|
|
541
|
-
|
|
859
|
+
mkdirSync2(dirname2(path), { recursive: true });
|
|
860
|
+
writeFileSync2(path, content.endsWith("\n") ? content : `${content}
|
|
542
861
|
`);
|
|
543
862
|
}
|
|
544
863
|
function packageRoot() {
|
|
545
|
-
return
|
|
864
|
+
return resolve2(dirname2(fileURLToPath(import.meta.url)), "..");
|
|
546
865
|
}
|
|
547
|
-
function
|
|
548
|
-
return value.startsWith("~/") ?
|
|
866
|
+
function expandHome2(value) {
|
|
867
|
+
return value.startsWith("~/") ? resolve2(homedir2(), value.slice(2)) : resolve2(value);
|
|
549
868
|
}
|
|
550
869
|
function readExisting(path) {
|
|
551
|
-
return
|
|
870
|
+
return existsSync2(path) ? readFileSync(path, "utf8") : "";
|
|
552
871
|
}
|
|
553
872
|
function normalizeServerUrl2(value) {
|
|
554
873
|
const trimmed = value.trim() || "https://shadowob.com";
|
|
@@ -556,16 +875,16 @@ function normalizeServerUrl2(value) {
|
|
|
556
875
|
}
|
|
557
876
|
function hermesPluginSource() {
|
|
558
877
|
const candidates = [
|
|
559
|
-
|
|
560
|
-
|
|
878
|
+
resolve2(packageRoot(), "hermes-shadowob-plugin"),
|
|
879
|
+
resolve2(process.cwd(), "packages/connector/hermes-shadowob-plugin")
|
|
561
880
|
];
|
|
562
|
-
const found = candidates.find((candidate) =>
|
|
881
|
+
const found = candidates.find((candidate) => existsSync2(candidate));
|
|
563
882
|
if (!found) throw new Error("Cannot find bundled hermes-shadowob-plugin directory");
|
|
564
883
|
return found;
|
|
565
884
|
}
|
|
566
885
|
function applyOpenClaw(options) {
|
|
567
886
|
const plan = createConnectorPlan(options);
|
|
568
|
-
const configPath =
|
|
887
|
+
const configPath = expandHome2(
|
|
569
888
|
options.openclawConfig ?? process.env.OPENCLAW_CONFIG ?? "~/.shadowob/openclaw.json"
|
|
570
889
|
);
|
|
571
890
|
console.log("Applying: Install plugin");
|
|
@@ -584,16 +903,16 @@ function applyOpenClaw(options) {
|
|
|
584
903
|
}
|
|
585
904
|
function applyHermes(options) {
|
|
586
905
|
const plan = createConnectorPlan(options);
|
|
587
|
-
const hermesDir =
|
|
588
|
-
const pluginTarget =
|
|
589
|
-
const envPath =
|
|
590
|
-
const configPath =
|
|
906
|
+
const hermesDir = expandHome2(options.hermesHome ?? process.env.HERMES_HOME ?? "~/.hermes");
|
|
907
|
+
const pluginTarget = resolve2(hermesDir, "plugins/shadowob");
|
|
908
|
+
const envPath = resolve2(hermesDir, ".env");
|
|
909
|
+
const configPath = resolve2(hermesDir, "config.yaml");
|
|
591
910
|
const envBlock = plan.configBlocks.find((block) => block.label === "~/.hermes/.env");
|
|
592
911
|
if (!envBlock) throw new Error("Hermes plan is missing config blocks");
|
|
593
912
|
if (options.dryRun) {
|
|
594
913
|
console.log(`[dry-run] copy ${hermesPluginSource()} -> ${pluginTarget}`);
|
|
595
914
|
} else {
|
|
596
|
-
|
|
915
|
+
mkdirSync2(resolve2(hermesDir, "plugins"), { recursive: true });
|
|
597
916
|
cpSync(hermesPluginSource(), pluginTarget, { recursive: true, force: true });
|
|
598
917
|
}
|
|
599
918
|
const nextEnv = options.force ? envBlock.content : mergeEnvContent(readExisting(envPath), {
|
|
@@ -608,7 +927,7 @@ function applyHermes(options) {
|
|
|
608
927
|
writeFile(configPath, nextConfig, options.dryRun);
|
|
609
928
|
if (options.install) {
|
|
610
929
|
runShell(
|
|
611
|
-
`python -m pip install -r "${
|
|
930
|
+
`python -m pip install -r "${resolve2(pluginTarget, "requirements.txt")}"`,
|
|
612
931
|
options.dryRun
|
|
613
932
|
);
|
|
614
933
|
runShell("hermes plugins enable shadowob", options.dryRun);
|
|
@@ -617,11 +936,11 @@ function applyHermes(options) {
|
|
|
617
936
|
runShell("hermes gateway", options.dryRun);
|
|
618
937
|
}
|
|
619
938
|
}
|
|
620
|
-
function applyCcConnect(options) {
|
|
939
|
+
async function applyCcConnect(options) {
|
|
621
940
|
const plan = createConnectorPlan(options);
|
|
622
941
|
const configBlock = plan.configBlocks.find((block) => block.label === "~/.cc-connect/config.toml");
|
|
623
942
|
if (!configBlock) throw new Error("cc-connect plan is missing config block");
|
|
624
|
-
const configPath =
|
|
943
|
+
const configPath = resolve2(homedir2(), ".cc-connect/config.toml");
|
|
625
944
|
const nextConfig = options.force ? configBlock.content : mergeCcConnectConfigContent(readExisting(configPath), {
|
|
626
945
|
token: options.token,
|
|
627
946
|
serverUrl: normalizeServerUrl2(options.serverUrl),
|
|
@@ -630,14 +949,20 @@ function applyCcConnect(options) {
|
|
|
630
949
|
agentType: options.agentType?.trim() || "codex"
|
|
631
950
|
});
|
|
632
951
|
writeFile(configPath, nextConfig, options.dryRun);
|
|
633
|
-
|
|
634
|
-
|
|
952
|
+
let binaryPath;
|
|
953
|
+
if (options.install || options.start) {
|
|
954
|
+
const installed = await ensureCcConnectFork({
|
|
955
|
+
dryRun: options.dryRun,
|
|
956
|
+
log: (message) => console.log(message)
|
|
957
|
+
});
|
|
958
|
+
binaryPath = installed.binaryPath;
|
|
959
|
+
console.log(`cc-connect binary: ${binaryPath}`);
|
|
635
960
|
}
|
|
636
961
|
if (options.start) {
|
|
637
|
-
|
|
962
|
+
runBinary(binaryPath ?? "cc-connect", [], options.dryRun);
|
|
638
963
|
}
|
|
639
964
|
}
|
|
640
|
-
function connect(options) {
|
|
965
|
+
async function connect(options) {
|
|
641
966
|
if (options.target === "openclaw") {
|
|
642
967
|
applyOpenClaw(options);
|
|
643
968
|
return;
|
|
@@ -646,18 +971,19 @@ function connect(options) {
|
|
|
646
971
|
applyHermes(options);
|
|
647
972
|
return;
|
|
648
973
|
}
|
|
649
|
-
applyCcConnect(options);
|
|
974
|
+
await applyCcConnect(options);
|
|
650
975
|
}
|
|
651
|
-
|
|
976
|
+
async function main() {
|
|
652
977
|
const options = parseArgs(process.argv.slice(2));
|
|
653
978
|
if (options.command === "connect") {
|
|
654
|
-
connect(options);
|
|
979
|
+
await connect(options);
|
|
655
980
|
} else {
|
|
656
981
|
printPlan(options);
|
|
657
982
|
}
|
|
658
|
-
}
|
|
983
|
+
}
|
|
984
|
+
main().catch((error) => {
|
|
659
985
|
console.error(error instanceof Error ? error.message : String(error));
|
|
660
986
|
console.error("");
|
|
661
987
|
console.error(usage());
|
|
662
988
|
process.exit(1);
|
|
663
|
-
}
|
|
989
|
+
});
|
package/dist/index.cjs
CHANGED
|
@@ -24,6 +24,14 @@ __export(index_exports, {
|
|
|
24
24
|
createConnectorPlans: () => createConnectorPlans
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(index_exports);
|
|
27
|
+
|
|
28
|
+
// src/cc-connect-fork.ts
|
|
29
|
+
var CC_CONNECT_FORK_REPO = "buggyblues/cc-connect";
|
|
30
|
+
var CC_CONNECT_FORK_REF = "63b5d59127b3004bc7002f2d51892b1f2a91ea83";
|
|
31
|
+
var CC_CONNECT_FORK_SHORT_REF = CC_CONNECT_FORK_REF.slice(0, 7);
|
|
32
|
+
var CC_CONNECT_FORK_DOCS_URL = `https://github.com/${CC_CONNECT_FORK_REPO}/blob/main/docs/shadowob.md`;
|
|
33
|
+
|
|
34
|
+
// src/index.ts
|
|
27
35
|
var DEFAULT_SERVER_URL = "https://shadowob.com";
|
|
28
36
|
var DEFAULT_WORK_DIR = ".";
|
|
29
37
|
var DEFAULT_PROJECT_NAME = "shadow-buddy";
|
|
@@ -110,7 +118,14 @@ function buildOpenClawPlan(input) {
|
|
|
110
118
|
"typing",
|
|
111
119
|
"activityStatus",
|
|
112
120
|
"reactions",
|
|
113
|
-
"editDelete"
|
|
121
|
+
"editDelete",
|
|
122
|
+
"statusChecks",
|
|
123
|
+
"usageCosts",
|
|
124
|
+
"multiAgentBinding",
|
|
125
|
+
"shadowCliLogin",
|
|
126
|
+
"notifications",
|
|
127
|
+
"officialSkills",
|
|
128
|
+
"cronTasks"
|
|
114
129
|
]
|
|
115
130
|
};
|
|
116
131
|
}
|
|
@@ -196,7 +211,12 @@ function buildHermesPlan(input) {
|
|
|
196
211
|
"onlineStatus",
|
|
197
212
|
"typing",
|
|
198
213
|
"activityStatus",
|
|
199
|
-
"cronDelivery"
|
|
214
|
+
"cronDelivery",
|
|
215
|
+
"statusChecks",
|
|
216
|
+
"usageCosts",
|
|
217
|
+
"shadowCliLogin",
|
|
218
|
+
"notifications",
|
|
219
|
+
"officialSkills"
|
|
200
220
|
]
|
|
201
221
|
};
|
|
202
222
|
}
|
|
@@ -211,8 +231,12 @@ function buildCcConnectPlan(input) {
|
|
|
211
231
|
"",
|
|
212
232
|
"[[projects]]",
|
|
213
233
|
`name = "${projectName}"`,
|
|
234
|
+
"",
|
|
235
|
+
"[projects.agent]",
|
|
236
|
+
`type = "${agentType}"`,
|
|
237
|
+
"",
|
|
238
|
+
"[projects.agent.options]",
|
|
214
239
|
`work_dir = "${workDir}"`,
|
|
215
|
-
`agent_type = "${agentType}"`,
|
|
216
240
|
"",
|
|
217
241
|
"[[projects.platforms]]",
|
|
218
242
|
'type = "shadowob"',
|
|
@@ -225,15 +249,6 @@ function buildCcConnectPlan(input) {
|
|
|
225
249
|
"share_session_in_channel = false",
|
|
226
250
|
'progress_style = "compact"'
|
|
227
251
|
].join("\n");
|
|
228
|
-
const commands = [
|
|
229
|
-
{ label: "Install cc-connect", command: "npm install -g cc-connect" },
|
|
230
|
-
{ label: "Create config directory", command: "mkdir -p ~/.cc-connect" },
|
|
231
|
-
{
|
|
232
|
-
label: "Edit config",
|
|
233
|
-
command: "$EDITOR ~/.cc-connect/config.toml"
|
|
234
|
-
},
|
|
235
|
-
{ label: "Start cc-connect", command: "cc-connect" }
|
|
236
|
-
];
|
|
237
252
|
const connectCommand = [
|
|
238
253
|
"npx @shadowob/connector@latest connect",
|
|
239
254
|
"--target cc-connect",
|
|
@@ -243,12 +258,26 @@ function buildCcConnectPlan(input) {
|
|
|
243
258
|
`--project-name ${shellQuote(projectName)}`,
|
|
244
259
|
`--agent-type ${shellQuote(agentType)}`
|
|
245
260
|
].join(" ");
|
|
261
|
+
const installCommand = `${connectCommand} --install`;
|
|
262
|
+
const startCommand = `${connectCommand} --install --start`;
|
|
263
|
+
const commands = [
|
|
264
|
+
{
|
|
265
|
+
label: "Install ShadowOB cc-connect fork",
|
|
266
|
+
command: installCommand
|
|
267
|
+
},
|
|
268
|
+
{ label: "Create config directory", command: "mkdir -p ~/.cc-connect" },
|
|
269
|
+
{
|
|
270
|
+
label: "Edit config",
|
|
271
|
+
command: "$EDITOR ~/.cc-connect/config.toml"
|
|
272
|
+
},
|
|
273
|
+
{ label: "Start ShadowOB cc-connect fork", command: startCommand }
|
|
274
|
+
];
|
|
246
275
|
return {
|
|
247
276
|
target: "cc-connect",
|
|
248
277
|
title: "cc-connect",
|
|
249
|
-
summary:
|
|
250
|
-
connectCommand,
|
|
251
|
-
quickCommand:
|
|
278
|
+
summary: `Use ${CC_CONNECT_FORK_REPO}@${CC_CONNECT_FORK_SHORT_REF} with ShadowOB Socket.IO platform support for this Buddy token.`,
|
|
279
|
+
connectCommand: startCommand,
|
|
280
|
+
quickCommand: startCommand,
|
|
252
281
|
commands,
|
|
253
282
|
configBlocks: [{ label: "~/.cc-connect/config.toml", language: "toml", content: tomlConfig }],
|
|
254
283
|
aiPrompt: [
|
|
@@ -259,9 +288,9 @@ function buildCcConnectPlan(input) {
|
|
|
259
288
|
`Project work_dir: ${workDir}`,
|
|
260
289
|
`Agent type: ${agentType}`,
|
|
261
290
|
"",
|
|
262
|
-
|
|
291
|
+
`Install ${CC_CONNECT_FORK_REPO}@${CC_CONNECT_FORK_SHORT_REF}, add the TOML platform block, and start cc-connect.`
|
|
263
292
|
].join("\n"),
|
|
264
|
-
docsUrl:
|
|
293
|
+
docsUrl: CC_CONNECT_FORK_DOCS_URL,
|
|
265
294
|
capabilities: [
|
|
266
295
|
"channelMessages",
|
|
267
296
|
"dms",
|
|
@@ -271,7 +300,12 @@ function buildCcConnectPlan(input) {
|
|
|
271
300
|
"slashCommands",
|
|
272
301
|
"typing",
|
|
273
302
|
"streamingPreviews",
|
|
274
|
-
"forms"
|
|
303
|
+
"forms",
|
|
304
|
+
"statusChecks",
|
|
305
|
+
"usageCosts",
|
|
306
|
+
"multiAgentBinding",
|
|
307
|
+
"shadowCliLogin",
|
|
308
|
+
"notifications"
|
|
275
309
|
]
|
|
276
310
|
};
|
|
277
311
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
// src/cc-connect-fork.ts
|
|
2
|
+
var CC_CONNECT_FORK_REPO = "buggyblues/cc-connect";
|
|
3
|
+
var CC_CONNECT_FORK_REF = "63b5d59127b3004bc7002f2d51892b1f2a91ea83";
|
|
4
|
+
var CC_CONNECT_FORK_SHORT_REF = CC_CONNECT_FORK_REF.slice(0, 7);
|
|
5
|
+
var CC_CONNECT_FORK_DOCS_URL = `https://github.com/${CC_CONNECT_FORK_REPO}/blob/main/docs/shadowob.md`;
|
|
6
|
+
|
|
1
7
|
// src/index.ts
|
|
2
8
|
var DEFAULT_SERVER_URL = "https://shadowob.com";
|
|
3
9
|
var DEFAULT_WORK_DIR = ".";
|
|
@@ -85,7 +91,14 @@ function buildOpenClawPlan(input) {
|
|
|
85
91
|
"typing",
|
|
86
92
|
"activityStatus",
|
|
87
93
|
"reactions",
|
|
88
|
-
"editDelete"
|
|
94
|
+
"editDelete",
|
|
95
|
+
"statusChecks",
|
|
96
|
+
"usageCosts",
|
|
97
|
+
"multiAgentBinding",
|
|
98
|
+
"shadowCliLogin",
|
|
99
|
+
"notifications",
|
|
100
|
+
"officialSkills",
|
|
101
|
+
"cronTasks"
|
|
89
102
|
]
|
|
90
103
|
};
|
|
91
104
|
}
|
|
@@ -171,7 +184,12 @@ function buildHermesPlan(input) {
|
|
|
171
184
|
"onlineStatus",
|
|
172
185
|
"typing",
|
|
173
186
|
"activityStatus",
|
|
174
|
-
"cronDelivery"
|
|
187
|
+
"cronDelivery",
|
|
188
|
+
"statusChecks",
|
|
189
|
+
"usageCosts",
|
|
190
|
+
"shadowCliLogin",
|
|
191
|
+
"notifications",
|
|
192
|
+
"officialSkills"
|
|
175
193
|
]
|
|
176
194
|
};
|
|
177
195
|
}
|
|
@@ -186,8 +204,12 @@ function buildCcConnectPlan(input) {
|
|
|
186
204
|
"",
|
|
187
205
|
"[[projects]]",
|
|
188
206
|
`name = "${projectName}"`,
|
|
207
|
+
"",
|
|
208
|
+
"[projects.agent]",
|
|
209
|
+
`type = "${agentType}"`,
|
|
210
|
+
"",
|
|
211
|
+
"[projects.agent.options]",
|
|
189
212
|
`work_dir = "${workDir}"`,
|
|
190
|
-
`agent_type = "${agentType}"`,
|
|
191
213
|
"",
|
|
192
214
|
"[[projects.platforms]]",
|
|
193
215
|
'type = "shadowob"',
|
|
@@ -200,15 +222,6 @@ function buildCcConnectPlan(input) {
|
|
|
200
222
|
"share_session_in_channel = false",
|
|
201
223
|
'progress_style = "compact"'
|
|
202
224
|
].join("\n");
|
|
203
|
-
const commands = [
|
|
204
|
-
{ label: "Install cc-connect", command: "npm install -g cc-connect" },
|
|
205
|
-
{ label: "Create config directory", command: "mkdir -p ~/.cc-connect" },
|
|
206
|
-
{
|
|
207
|
-
label: "Edit config",
|
|
208
|
-
command: "$EDITOR ~/.cc-connect/config.toml"
|
|
209
|
-
},
|
|
210
|
-
{ label: "Start cc-connect", command: "cc-connect" }
|
|
211
|
-
];
|
|
212
225
|
const connectCommand = [
|
|
213
226
|
"npx @shadowob/connector@latest connect",
|
|
214
227
|
"--target cc-connect",
|
|
@@ -218,12 +231,26 @@ function buildCcConnectPlan(input) {
|
|
|
218
231
|
`--project-name ${shellQuote(projectName)}`,
|
|
219
232
|
`--agent-type ${shellQuote(agentType)}`
|
|
220
233
|
].join(" ");
|
|
234
|
+
const installCommand = `${connectCommand} --install`;
|
|
235
|
+
const startCommand = `${connectCommand} --install --start`;
|
|
236
|
+
const commands = [
|
|
237
|
+
{
|
|
238
|
+
label: "Install ShadowOB cc-connect fork",
|
|
239
|
+
command: installCommand
|
|
240
|
+
},
|
|
241
|
+
{ label: "Create config directory", command: "mkdir -p ~/.cc-connect" },
|
|
242
|
+
{
|
|
243
|
+
label: "Edit config",
|
|
244
|
+
command: "$EDITOR ~/.cc-connect/config.toml"
|
|
245
|
+
},
|
|
246
|
+
{ label: "Start ShadowOB cc-connect fork", command: startCommand }
|
|
247
|
+
];
|
|
221
248
|
return {
|
|
222
249
|
target: "cc-connect",
|
|
223
250
|
title: "cc-connect",
|
|
224
|
-
summary:
|
|
225
|
-
connectCommand,
|
|
226
|
-
quickCommand:
|
|
251
|
+
summary: `Use ${CC_CONNECT_FORK_REPO}@${CC_CONNECT_FORK_SHORT_REF} with ShadowOB Socket.IO platform support for this Buddy token.`,
|
|
252
|
+
connectCommand: startCommand,
|
|
253
|
+
quickCommand: startCommand,
|
|
227
254
|
commands,
|
|
228
255
|
configBlocks: [{ label: "~/.cc-connect/config.toml", language: "toml", content: tomlConfig }],
|
|
229
256
|
aiPrompt: [
|
|
@@ -234,9 +261,9 @@ function buildCcConnectPlan(input) {
|
|
|
234
261
|
`Project work_dir: ${workDir}`,
|
|
235
262
|
`Agent type: ${agentType}`,
|
|
236
263
|
"",
|
|
237
|
-
|
|
264
|
+
`Install ${CC_CONNECT_FORK_REPO}@${CC_CONNECT_FORK_SHORT_REF}, add the TOML platform block, and start cc-connect.`
|
|
238
265
|
].join("\n"),
|
|
239
|
-
docsUrl:
|
|
266
|
+
docsUrl: CC_CONNECT_FORK_DOCS_URL,
|
|
240
267
|
capabilities: [
|
|
241
268
|
"channelMessages",
|
|
242
269
|
"dms",
|
|
@@ -246,7 +273,12 @@ function buildCcConnectPlan(input) {
|
|
|
246
273
|
"slashCommands",
|
|
247
274
|
"typing",
|
|
248
275
|
"streamingPreviews",
|
|
249
|
-
"forms"
|
|
276
|
+
"forms",
|
|
277
|
+
"statusChecks",
|
|
278
|
+
"usageCosts",
|
|
279
|
+
"multiAgentBinding",
|
|
280
|
+
"shadowCliLogin",
|
|
281
|
+
"notifications"
|
|
250
282
|
]
|
|
251
283
|
};
|
|
252
284
|
}
|
|
@@ -241,6 +241,21 @@ class ShadowAsyncClient:
|
|
|
241
241
|
async def get_channel(self, channel_id: str) -> JsonDict:
|
|
242
242
|
return await self.request("GET", f"/api/channels/{quote(str(channel_id), safe='')}")
|
|
243
243
|
|
|
244
|
+
async def get_channel_bootstrap(
|
|
245
|
+
self,
|
|
246
|
+
channel_id: str,
|
|
247
|
+
*,
|
|
248
|
+
messages_limit: int | None = None,
|
|
249
|
+
) -> JsonDict:
|
|
250
|
+
params: JsonDict = {}
|
|
251
|
+
if messages_limit is not None:
|
|
252
|
+
params["messagesLimit"] = int(messages_limit)
|
|
253
|
+
return await self.request(
|
|
254
|
+
"GET",
|
|
255
|
+
f"/api/channels/{quote(str(channel_id), safe='')}/bootstrap",
|
|
256
|
+
params=params or None,
|
|
257
|
+
)
|
|
258
|
+
|
|
244
259
|
async def get_messages(
|
|
245
260
|
self,
|
|
246
261
|
channel_id: str,
|
|
@@ -263,11 +278,20 @@ class ShadowAsyncClient:
|
|
|
263
278
|
async def get_message(self, message_id: str) -> JsonDict:
|
|
264
279
|
return await self.request("GET", f"/api/messages/{quote(str(message_id), safe='')}")
|
|
265
280
|
|
|
266
|
-
async def resolve_attachment_media_url(
|
|
281
|
+
async def resolve_attachment_media_url(
|
|
282
|
+
self,
|
|
283
|
+
attachment_id: str,
|
|
284
|
+
*,
|
|
285
|
+
disposition: str = "inline",
|
|
286
|
+
variant: str | None = None,
|
|
287
|
+
) -> JsonDict:
|
|
288
|
+
params: JsonDict = {"disposition": disposition}
|
|
289
|
+
if variant:
|
|
290
|
+
params["variant"] = variant
|
|
267
291
|
return await self.request(
|
|
268
292
|
"GET",
|
|
269
293
|
f"/api/attachments/{quote(str(attachment_id), safe='')}/media-url",
|
|
270
|
-
params=
|
|
294
|
+
params=params,
|
|
271
295
|
)
|
|
272
296
|
|
|
273
297
|
async def send_message(
|