@ethanhq/cc-fleet 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.
- package/README.md +38 -0
- package/bin/launcher.js +27 -0
- package/install.js +97 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# cc-fleet
|
|
2
|
+
|
|
3
|
+
Spawn any third-party LLM provider with an Anthropic-compatible API (e.g. DeepSeek,
|
|
4
|
+
GLM, Kimi, Qwen, MiniMax) as real Claude Code **agent-team teammates** or one-shot
|
|
5
|
+
subagents — driven just like native teammates. Your main session's own auth (OAuth
|
|
6
|
+
subscription or API key) is untouched; vendor workers bill the vendor key.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install -g @ethanhq/cc-fleet
|
|
12
|
+
# or run without installing:
|
|
13
|
+
npx @ethanhq/cc-fleet --help
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
`postinstall` downloads the prebuilt binary for your platform (linux/darwin ×
|
|
17
|
+
x64/arm64) from the matching GitHub Release, verifies its sha256, and installs
|
|
18
|
+
`cc-fleet` plus the `ccf` alias.
|
|
19
|
+
|
|
20
|
+
## The skill
|
|
21
|
+
|
|
22
|
+
The npm package installs only the CLI binary. To teach Claude Code *when* to use
|
|
23
|
+
the fleet, install the cc-fleet skill via the plugin:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
claude plugin marketplace add ethanhq/cc-fleet
|
|
27
|
+
claude plugin install cc-fleet@ethanhq
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## First run
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
cc-fleet init # create config at ~/.config/cc-fleet/
|
|
34
|
+
cc-fleet add <vendor> ... # register a vendor
|
|
35
|
+
cc-fleet doctor # health-check
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Full documentation: https://github.com/ethanhq/cc-fleet
|
package/bin/launcher.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Thin launcher: exec the platform binary that postinstall placed next to this
|
|
3
|
+
// file, passing through argv and the exit code. Both `cc-fleet` and `ccf` point
|
|
4
|
+
// here, so `ccf` is just the same binary under a shorter name.
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
const path = require("path");
|
|
8
|
+
const fs = require("fs");
|
|
9
|
+
const { spawnSync } = require("child_process");
|
|
10
|
+
|
|
11
|
+
const bin = path.join(__dirname, "cc-fleet");
|
|
12
|
+
|
|
13
|
+
if (!fs.existsSync(bin)) {
|
|
14
|
+
console.error(
|
|
15
|
+
"cc-fleet: the platform binary is missing — the postinstall download may " +
|
|
16
|
+
"have failed. Reinstall with `npm install -g @ethanhq/cc-fleet`, or grab a release " +
|
|
17
|
+
"from https://github.com/ethanhq/cc-fleet/releases."
|
|
18
|
+
);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const res = spawnSync(bin, process.argv.slice(2), { stdio: "inherit" });
|
|
23
|
+
if (res.error) {
|
|
24
|
+
console.error(`cc-fleet: failed to run ${bin}: ${res.error.message}`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
process.exit(res.status === null ? 1 : res.status);
|
package/install.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// postinstall: download the prebuilt cc-fleet binary for this platform from the
|
|
3
|
+
// matching GitHub Release, verify its sha256, and unpack it into bin/.
|
|
4
|
+
"use strict";
|
|
5
|
+
|
|
6
|
+
const https = require("https");
|
|
7
|
+
const fs = require("fs");
|
|
8
|
+
const os = require("os");
|
|
9
|
+
const path = require("path");
|
|
10
|
+
const crypto = require("crypto");
|
|
11
|
+
const { execFileSync } = require("child_process");
|
|
12
|
+
|
|
13
|
+
const REPO = "ethanhq/cc-fleet";
|
|
14
|
+
const version = require("./package.json").version;
|
|
15
|
+
|
|
16
|
+
const PLATFORM = { linux: "linux", darwin: "darwin" }[process.platform];
|
|
17
|
+
const ARCH = { x64: "amd64", arm64: "arm64" }[process.arch];
|
|
18
|
+
|
|
19
|
+
if (!PLATFORM || !ARCH) {
|
|
20
|
+
console.error(
|
|
21
|
+
`cc-fleet: unsupported platform ${process.platform}/${process.arch} ` +
|
|
22
|
+
"(cc-fleet supports linux|darwin on x64|arm64)"
|
|
23
|
+
);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const tarball = `cc-fleet-${PLATFORM}-${ARCH}.tar.gz`;
|
|
28
|
+
// CCF_BASE_URL overrides the asset base for a mirror or a local test.
|
|
29
|
+
const base =
|
|
30
|
+
process.env.CCF_BASE_URL ||
|
|
31
|
+
`https://github.com/${REPO}/releases/download/v${version}`;
|
|
32
|
+
|
|
33
|
+
// GET that follows redirects (GitHub release assets redirect to a CDN).
|
|
34
|
+
function get(url, redirects = 0) {
|
|
35
|
+
return new Promise((resolve, reject) => {
|
|
36
|
+
if (redirects > 10) return reject(new Error("too many redirects"));
|
|
37
|
+
https
|
|
38
|
+
.get(url, { headers: { "User-Agent": "cc-fleet-npm" } }, (res) => {
|
|
39
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
40
|
+
res.resume();
|
|
41
|
+
return resolve(get(res.headers.location, redirects + 1));
|
|
42
|
+
}
|
|
43
|
+
if (res.statusCode !== 200) {
|
|
44
|
+
res.resume();
|
|
45
|
+
return reject(new Error(`GET ${url} -> HTTP ${res.statusCode}`));
|
|
46
|
+
}
|
|
47
|
+
const chunks = [];
|
|
48
|
+
res.on("data", (c) => chunks.push(c));
|
|
49
|
+
res.on("end", () => resolve(Buffer.concat(chunks)));
|
|
50
|
+
})
|
|
51
|
+
.on("error", reject);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function checksumFor(sumsText, name) {
|
|
56
|
+
for (const line of sumsText.split("\n")) {
|
|
57
|
+
const parts = line.trim().split(/\s+/);
|
|
58
|
+
if (parts[1] === name) return parts[0];
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function main() {
|
|
64
|
+
const binDir = path.join(__dirname, "bin");
|
|
65
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
66
|
+
|
|
67
|
+
const [tarBuf, sumsBuf] = await Promise.all([
|
|
68
|
+
get(`${base}/${tarball}`),
|
|
69
|
+
get(`${base}/checksums.txt`),
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
const expected = checksumFor(sumsBuf.toString("utf8"), tarball);
|
|
73
|
+
if (!expected) throw new Error(`no checksum for ${tarball} in checksums.txt`);
|
|
74
|
+
const actual = crypto.createHash("sha256").update(tarBuf).digest("hex");
|
|
75
|
+
if (actual !== expected) {
|
|
76
|
+
throw new Error(`checksum mismatch for ${tarball}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "cc-fleet-"));
|
|
80
|
+
try {
|
|
81
|
+
const tarPath = path.join(tmp, tarball);
|
|
82
|
+
fs.writeFileSync(tarPath, tarBuf);
|
|
83
|
+
execFileSync("tar", ["-xzf", tarPath, "-C", tmp]);
|
|
84
|
+
const extracted = path.join(tmp, `cc-fleet-${PLATFORM}-${ARCH}`, "cc-fleet");
|
|
85
|
+
const dest = path.join(binDir, "cc-fleet");
|
|
86
|
+
fs.copyFileSync(extracted, dest);
|
|
87
|
+
fs.chmodSync(dest, 0o755);
|
|
88
|
+
} finally {
|
|
89
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
90
|
+
}
|
|
91
|
+
console.log(`cc-fleet: installed v${version} (${PLATFORM}/${ARCH})`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
main().catch((err) => {
|
|
95
|
+
console.error(`cc-fleet: install failed: ${err.message}`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ethanhq/cc-fleet",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Spawn any third-party LLM provider with an Anthropic-compatible API as real Claude Code agent-team teammates or one-shot subagents. The main session's own auth (OAuth or API key) is untouched.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"cc-fleet": "bin/launcher.js",
|
|
7
|
+
"ccf": "bin/launcher.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"postinstall": "node install.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin/launcher.js",
|
|
14
|
+
"install.js",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"os": [
|
|
18
|
+
"linux",
|
|
19
|
+
"darwin"
|
|
20
|
+
],
|
|
21
|
+
"cpu": [
|
|
22
|
+
"x64",
|
|
23
|
+
"arm64"
|
|
24
|
+
],
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"claude-code",
|
|
30
|
+
"vendor",
|
|
31
|
+
"teammates",
|
|
32
|
+
"subagent",
|
|
33
|
+
"tmux",
|
|
34
|
+
"deepseek",
|
|
35
|
+
"glm",
|
|
36
|
+
"kimi",
|
|
37
|
+
"qwen",
|
|
38
|
+
"minimax"
|
|
39
|
+
],
|
|
40
|
+
"license": "Apache-2.0",
|
|
41
|
+
"author": "Ethan Guo <ethanguo.dev@gmail.com>",
|
|
42
|
+
"homepage": "https://github.com/ethanhq/cc-fleet",
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/ethanhq/cc-fleet.git"
|
|
46
|
+
},
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/ethanhq/cc-fleet/issues"
|
|
49
|
+
}
|
|
50
|
+
}
|