@daocloud-cli/dce 0.1.0-rc.7

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 ADDED
@@ -0,0 +1,267 @@
1
+ # daocloud-skills
2
+
3
+ A generated CLI and AI skill package for DaoCloud Enterprise (DCE). It wraps the DCE REST API into a `dce` command-line tool and bundles a companion skill for AI agents.
4
+
5
+ ## Overview
6
+
7
+ - **`dce`** — a CLI generated from DCE OpenAPI specs (global-management, container-management). Supports API discovery, search, and execution with built-in auth management.
8
+ - **`skills/dce`** — an AI agent skill that teaches agents how to use `dce` safely.
9
+
10
+ Currently supported products:
11
+
12
+ | Module | Description |
13
+ |---|---|
14
+ | `global-management` | Global Management — users, groups, workspaces, roles, audit |
15
+ | `container-management` | Container Management — clusters, namespaces, workloads, storage |
16
+ | `insight` | Insight — observability, metrics, alerting, and related operations |
17
+
18
+ ## Prerequisites
19
+
20
+ - Go 1.25+
21
+ - Git (for spec sync)
22
+ - Docker with [buildx](https://docs.docker.com/buildx/working-with-buildx/) (for container image builds)
23
+
24
+ ## Quick Start
25
+
26
+ ```bash
27
+ # Sync OpenAPI specs and regenerate code
28
+ make bootstrap
29
+
30
+ # Build dce
31
+ make build
32
+
33
+ # Install dce and symlink skill for local development
34
+ make dev
35
+ ```
36
+
37
+ The `make dev` target installs `dce` to `/usr/local/bin` and symlinks `skills/dce` into `~/.agents/skills/dce` for live local development in an AI agent runtime.
38
+
39
+ ## Install the Skill
40
+
41
+ Install the `dce` skill globally:
42
+
43
+ ```bash
44
+ npx skills add daocloud/daocloud-skills -g
45
+ ```
46
+
47
+ For non-interactive installs, add confirmation flags:
48
+
49
+ ```bash
50
+ npx -y skills add daocloud/daocloud-skills -g -y
51
+ ```
52
+
53
+ The `-g` flag installs the skill into the selected agent's user-level skills directory, so it is available across projects. Omit `-g` if you want to install the skill only for the current project.
54
+
55
+ This installs the skill only. The skill helps an AI agent use `dce`, but it does not install the `dce` CLI. Install the CLI separately before running DCE operations.
56
+
57
+ ### Install for a Specific Agent
58
+
59
+ Use `--agent` to install the `dce` skill for a specific AI coding agent. Common client targets include:
60
+
61
+ **Claude Code**
62
+
63
+ ```bash
64
+ npx skills add daocloud/daocloud-skills -g --skill dce --agent claude-code
65
+ ```
66
+
67
+ **Codex**
68
+
69
+ ```bash
70
+ npx skills add daocloud/daocloud-skills -g --skill dce --agent codex
71
+ ```
72
+
73
+ **Cursor**
74
+
75
+ ```bash
76
+ npx skills add daocloud/daocloud-skills -g --skill dce --agent cursor
77
+ ```
78
+
79
+ Use `--agent` more than once to install the same skill into multiple agents:
80
+
81
+ ```bash
82
+ npx skills add daocloud/daocloud-skills -g \
83
+ --skill dce \
84
+ --agent claude-code \
85
+ --agent codex \
86
+ --agent cursor
87
+ ```
88
+
89
+ This installs the skill from the repository's default branch. To inspect available skills before installing:
90
+
91
+ ```bash
92
+ npx skills add daocloud/daocloud-skills --list
93
+ ```
94
+
95
+ To uninstall the global `dce` skill, use `remove` with the same agent target:
96
+
97
+ ```bash
98
+ npx skills remove -g dce --agent codex
99
+ ```
100
+
101
+ After installation, open a new agent session and ask it to use the `dce` skill for DCE operations, for example:
102
+
103
+ ```text
104
+ Use the dce skill to list DCE clusters.
105
+ ```
106
+
107
+ ## Install the CLI
108
+
109
+ The recommended way is via npm:
110
+
111
+ ```bash
112
+ npm install -g @daocloud-cli/dce
113
+ ```
114
+
115
+ Or run on demand without a global install:
116
+
117
+ ```bash
118
+ npx @daocloud-cli/dce --help
119
+ ```
120
+
121
+ The npm package downloads the matching prebuilt binary from GitHub Releases on install and verifies it against `checksums.txt`. Supported platforms: `darwin`/`linux` on `amd64`/`arm64`, Node.js >= 16.
122
+
123
+ Alternatively, download a prebuilt archive from GitHub Releases directly:
124
+
125
+ ```bash
126
+ VERSION=v0.1.0-rc.6
127
+ OS=darwin
128
+ ARCH=amd64
129
+ PKG="dce-${VERSION}-${OS}-${ARCH}"
130
+
131
+ curl -fL "https://github.com/DaoCloud/daocloud-skills/releases/download/${VERSION}/${PKG}.tar.gz" -o dce.tar.gz
132
+ tar -xzf dce.tar.gz
133
+ sudo install -m 0755 "${PKG}/dce" /usr/local/bin/dce
134
+ ```
135
+
136
+ Use `OS=darwin` for macOS and `OS=linux` for Linux. Use `ARCH=arm64` for Apple Silicon or ARM64 Linux, and `ARCH=amd64` for Intel macOS or x86_64 Linux.
137
+
138
+ Verify the CLI is available:
139
+
140
+ ```bash
141
+ dce --help
142
+ ```
143
+
144
+ For source builds from this repository:
145
+
146
+ ```bash
147
+ make build
148
+ sudo cp bin/dce /usr/local/bin/dce
149
+ ```
150
+
151
+ For local development, use `make dev` to build the CLI, copy it to `/usr/local/bin/dce`, and symlink the local skill directory:
152
+
153
+ ```bash
154
+ make dev
155
+ ```
156
+
157
+ ## Usage
158
+
159
+ ```bash
160
+ # Log in to a DCE instance
161
+ dce auth login --hostname https://<dce-host>
162
+
163
+ # Browse available commands
164
+ dce commands --json
165
+
166
+ # Search for a command by intent
167
+ dce search "list clusters" --json
168
+
169
+ # Inspect a command before executing
170
+ dce commands show container-management cluster list-clusters --json
171
+
172
+ # Execute a command
173
+ dce container-management cluster list-clusters -o json
174
+ ```
175
+
176
+ ## Container Image
177
+
178
+ The image bundles the `dce` binary and the `skills/dce` directory under `/app/`, intended for use as a Kubernetes init container to distribute the tooling into a shared volume.
179
+
180
+ ```bash
181
+ # Build multi-arch image locally
182
+ make image
183
+
184
+ # Build and push to registry
185
+ make image-push IMAGE_REPO=registry.example.com/dce IMAGE_TAG=v1.0.0
186
+ ```
187
+
188
+ Default values: `IMAGE_REPO=daocloud/dce`, `IMAGE_TAG=latest`.
189
+
190
+ ### Init Container Example
191
+
192
+ ```yaml
193
+ initContainers:
194
+ - name: install-dce
195
+ image: daocloud/dce:latest
196
+ command:
197
+ - sh
198
+ - -c
199
+ - |
200
+ cp /app/dce /target/bin/dce
201
+ cp -r /app/skills/dce /target/.agents/skills/dce
202
+ volumeMounts:
203
+ - name: tools
204
+ mountPath: /target
205
+
206
+ volumes:
207
+ - name: tools
208
+ emptyDir: {}
209
+ ```
210
+
211
+ After the init container completes, the shared volume contains:
212
+
213
+ - `/target/bin/dce` — CLI binary
214
+ - `/target/.agents/skills/dce/` — AI agent skill
215
+
216
+ ## Development
217
+
218
+ | Target | Description |
219
+ |---|---|
220
+ | `make bootstrap` | Sync specs + regenerate all code |
221
+ | `make specsync` | Pull latest OpenAPI specs from upstream |
222
+ | `make codegen` | Regenerate Go code and skill references from specs |
223
+ | `make sync-one SOURCE=<name>` | Sync and regenerate a single source (e.g. `ghippo`) |
224
+ | `make build` | Build `bin/dce` |
225
+ | `make image` | Build multi-arch image locally (`linux/amd64`, `linux/arm64`) |
226
+ | `make image-push` | Build and push multi-arch image to registry |
227
+ | `make dev` | Build, install, and symlink skill for local debugging |
228
+ | `make dev-clean` | Remove installed binary and skill symlink |
229
+ | `make clean` | Remove `.cache` and `bin` |
230
+
231
+ ## Project Structure
232
+
233
+ ```
234
+ .
235
+ ├── cli.yaml # CLI name and auth config
236
+ ├── specs/sources.yaml # OpenAPI source definitions (pinned commits)
237
+ ├── internal/
238
+ │ ├── generated/ # Generated Go command modules (do not edit)
239
+ │ └── overlay/ # Per-source field overrides for codegen
240
+ ├── skills/dce/ # AI agent skill (SKILL.md + references)
241
+ ├── docs/ # Developer guides
242
+ ├── cmd/dce/main.go # CLI entrypoint
243
+ └── doc.go # Embeds cli.yaml for use by main
244
+ ```
245
+
246
+ ## Guides
247
+
248
+ - [Adding a new product](docs/add-new-product.md) — step-by-step guide for onboarding a new DCE product (spec source, overlay, codegen, verification)
249
+
250
+ ## How It Works
251
+
252
+ 1. **`specsync`** clones the pinned commit of `daocloud-api-docs` and extracts the OpenAPI JSON files into `.cache/specs-sync/`.
253
+ 2. **`codegen`** reads each spec, applies the overlay from `internal/overlay/<source>.yaml`, and emits:
254
+ - Go cobra subcommands under `internal/generated/<source>/`
255
+ - A command index at `skills/dce/references/modules/<source>.md`
256
+ - An updated `internal/generated/modules_gen.go` that mounts all modules
257
+ 3. **`go build`** compiles everything into a single static binary `bin/dce`.
258
+
259
+ Overlay files are the only place where human-maintained configuration lives — everything else is generated and should not be edited by hand.
260
+
261
+ ## Updating a Pinned Spec
262
+
263
+ Update the `pinned_tag` for the relevant source in `specs/sources.yaml`, then run:
264
+
265
+ ```bash
266
+ make sync-one SOURCE=<name>
267
+ ```
package/checksums.txt ADDED
@@ -0,0 +1,4 @@
1
+ a324997b6acdb1fd01a92e31d024f62bac979e10d0c5057fe19ad3639eec67fe dce-v0.1.0-rc.7-darwin-amd64.tar.gz
2
+ 89214cdfa1f66b34a961932bc2ad55645b5247d742f8a85dd7780f7954facb36 dce-v0.1.0-rc.7-darwin-arm64.tar.gz
3
+ d65367f8ad0d133815914cbdb36fe1b0b46930cf1fabae280b189395014aa5d1 dce-v0.1.0-rc.7-linux-amd64.tar.gz
4
+ 60c09746187eaf0f865761e7a36ac8cab6a07c1619b37f652b4897c32c93ca0a dce-v0.1.0-rc.7-linux-arm64.tar.gz
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@daocloud-cli/dce",
3
+ "version": "0.1.0-rc.7",
4
+ "description": "DaoCloud dce CLI",
5
+ "bin": {
6
+ "dce": "scripts/run.js"
7
+ },
8
+ "scripts": {
9
+ "postinstall": "node scripts/install.js"
10
+ },
11
+ "os": [
12
+ "darwin",
13
+ "linux"
14
+ ],
15
+ "cpu": [
16
+ "x64",
17
+ "arm64"
18
+ ],
19
+ "engines": {
20
+ "node": ">=16"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/DaoCloud/daocloud-skills.git"
25
+ },
26
+ "license": "Apache-2.0",
27
+ "files": [
28
+ "scripts/install.js",
29
+ "scripts/run.js",
30
+ "checksums.txt"
31
+ ]
32
+ }
@@ -0,0 +1,145 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const { execFileSync } = require("child_process");
4
+ const os = require("os");
5
+ const crypto = require("crypto");
6
+
7
+ const VERSION = require("../package.json").version;
8
+ const REPO = "DaoCloud/daocloud-skills";
9
+ const NAME = "dce";
10
+ const ALLOWED_HOSTS = new Set([
11
+ "github.com",
12
+ "objects.githubusercontent.com",
13
+ ]);
14
+
15
+ const PLATFORM_MAP = {
16
+ darwin: "darwin",
17
+ linux: "linux",
18
+ };
19
+
20
+ const ARCH_MAP = {
21
+ x64: "amd64",
22
+ arm64: "arm64",
23
+ };
24
+
25
+ const platform = PLATFORM_MAP[process.platform];
26
+ const arch = ARCH_MAP[process.arch];
27
+
28
+ const TAG = `v${VERSION}`;
29
+ const PKG_NAME = `${NAME}-${TAG}-${platform}-${arch}`;
30
+ const archiveName = `${PKG_NAME}.tar.gz`;
31
+ const GITHUB_URL = `https://github.com/${REPO}/releases/download/${TAG}/${archiveName}`;
32
+
33
+ const pkgRoot = path.join(__dirname, "..");
34
+ const binDir = path.join(pkgRoot, "bin");
35
+ const dest = path.join(binDir, NAME);
36
+
37
+ function assertAllowedHost(url) {
38
+ const { hostname } = new URL(url);
39
+ if (!ALLOWED_HOSTS.has(hostname)) {
40
+ throw new Error(`Download host not allowed: ${hostname}`);
41
+ }
42
+ }
43
+
44
+ function download(url, destPath) {
45
+ assertAllowedHost(url);
46
+ execFileSync(
47
+ "curl",
48
+ [
49
+ "--fail", "--location", "--silent", "--show-error",
50
+ "--connect-timeout", "10", "--max-time", "120",
51
+ "--max-redirs", "3",
52
+ "--output", destPath,
53
+ url,
54
+ ],
55
+ { stdio: ["ignore", "ignore", "pipe"] }
56
+ );
57
+ }
58
+
59
+ function getExpectedChecksum(name) {
60
+ const checksumsPath = path.join(pkgRoot, "checksums.txt");
61
+ if (!fs.existsSync(checksumsPath)) {
62
+ throw new Error(
63
+ "[SECURITY] checksums.txt not found; refusing to install without integrity verification"
64
+ );
65
+ }
66
+ const content = fs.readFileSync(checksumsPath, "utf8");
67
+ for (const line of content.split("\n")) {
68
+ const trimmed = line.trim();
69
+ if (!trimmed) continue;
70
+ const idx = trimmed.indexOf(" ");
71
+ if (idx === -1) continue;
72
+ const hash = trimmed.slice(0, idx);
73
+ const entry = trimmed.slice(idx + 2);
74
+ if (entry === name) return hash;
75
+ }
76
+ throw new Error(`Checksum entry not found for ${name}`);
77
+ }
78
+
79
+ function verifyChecksum(archivePath, expectedHash) {
80
+ const hash = crypto.createHash("sha256");
81
+ const fd = fs.openSync(archivePath, "r");
82
+ try {
83
+ const buf = Buffer.alloc(64 * 1024);
84
+ let bytesRead;
85
+ while ((bytesRead = fs.readSync(fd, buf, 0, buf.length, null)) > 0) {
86
+ hash.update(buf.subarray(0, bytesRead));
87
+ }
88
+ } finally {
89
+ fs.closeSync(fd);
90
+ }
91
+ const actual = hash.digest("hex");
92
+ if (actual.toLowerCase() !== expectedHash.toLowerCase()) {
93
+ throw new Error(
94
+ `[SECURITY] Checksum mismatch for ${path.basename(archivePath)}: expected ${expectedHash} but got ${actual}`
95
+ );
96
+ }
97
+ }
98
+
99
+ function install() {
100
+ fs.mkdirSync(binDir, { recursive: true });
101
+
102
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), `${NAME}-`));
103
+ const archivePath = path.join(tmpDir, archiveName);
104
+
105
+ try {
106
+ download(GITHUB_URL, archivePath);
107
+
108
+ const expected = getExpectedChecksum(archiveName);
109
+ verifyChecksum(archivePath, expected);
110
+
111
+ execFileSync("tar", ["-xzf", archivePath, "-C", tmpDir], { stdio: "ignore" });
112
+
113
+ const extractedRoot = path.join(tmpDir, PKG_NAME);
114
+ const extractedBinary = path.join(extractedRoot, NAME);
115
+
116
+ fs.copyFileSync(extractedBinary, dest);
117
+ fs.chmodSync(dest, 0o755);
118
+
119
+ console.log(`${NAME} ${TAG} installed successfully`);
120
+ } finally {
121
+ fs.rmSync(tmpDir, { recursive: true, force: true });
122
+ }
123
+ }
124
+
125
+ if (require.main === module) {
126
+ if (!platform || !arch) {
127
+ console.error(`Unsupported platform: ${process.platform}-${process.arch}`);
128
+ process.exit(1);
129
+ }
130
+
131
+ // Under `npx`, postinstall fires but the binary is not yet needed —
132
+ // run.js triggers install() on demand with DCE_RUN=1 set.
133
+ const isNpxPostinstall =
134
+ process.env.npm_command === "exec" && !process.env.DCE_RUN;
135
+ if (isNpxPostinstall) process.exit(0);
136
+
137
+ try {
138
+ install();
139
+ } catch (err) {
140
+ console.error(`Failed to install ${NAME}:`, err.message);
141
+ process.exit(1);
142
+ }
143
+ }
144
+
145
+ module.exports = { getExpectedChecksum, verifyChecksum, assertAllowedHost };
package/scripts/run.js ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { execFileSync } = require("child_process");
4
+ const fs = require("fs");
5
+ const path = require("path");
6
+
7
+ const bin = path.join(__dirname, "..", "bin", "dce");
8
+ const args = process.argv.slice(2);
9
+
10
+ if (!fs.existsSync(bin)) {
11
+ try {
12
+ execFileSync(process.execPath, [path.join(__dirname, "install.js")], {
13
+ stdio: "inherit",
14
+ env: { ...process.env, DCE_RUN: "true" },
15
+ });
16
+ } catch (_) {
17
+ console.error(
18
+ `\nFailed to auto-install dce binary.\n` +
19
+ `Run the install script manually:\n` +
20
+ ` node "${path.join(__dirname, "install.js")}"\n`
21
+ );
22
+ process.exit(1);
23
+ }
24
+ }
25
+
26
+ try {
27
+ execFileSync(bin, args, { stdio: "inherit" });
28
+ } catch (e) {
29
+ process.exit(e.status || 1);
30
+ }