@dzhechkov/cloudru-hub 0.1.13 → 0.1.15

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/.dz-manifest.json CHANGED
@@ -5,19 +5,19 @@
5
5
  "files": [
6
6
  {
7
7
  "path": "CHANGELOG.md",
8
- "sha256": "d2be06e900ab3d02d367ff5d91129ef3faa9a16e1afac6fba8ae9cec4a51c322"
8
+ "sha256": "2b0dbd83deb813844a658814b9a6fa1640f1e5255c676210e61dceaa6b42195b"
9
9
  },
10
10
  {
11
11
  "path": "LICENSE",
12
- "sha256": "68da42b10dcc095cdfd7249557cee30285664e5dea00dc85475ff047d975616a"
12
+ "sha256": "78a14ae697528fa79451ea10725c5ca356f6658378bfb39849b51d05207ab3f3"
13
13
  },
14
14
  {
15
15
  "path": "README.md",
16
- "sha256": "c505a9bb7ab6f8d9fbe1cac64e22b12ec14f674f979af7120457b8ba49039484"
16
+ "sha256": "4f6a2d5928fec42f021eb10471677b902e831b99d53096661a821f6460bd55a6"
17
17
  },
18
18
  {
19
19
  "path": "THIRD_PARTY_NOTICES.md",
20
- "sha256": "109cffdaaf9402e88f6cc35a0497ba49db015b329fce87ba20762f34dc95c051"
20
+ "sha256": "1986a75d5f90631adea8fb40c9fc182371cb875c9d62d65d07fd479b32c876df"
21
21
  },
22
22
  {
23
23
  "path": "bin/cloudru-hub.js",
@@ -33,23 +33,31 @@
33
33
  },
34
34
  {
35
35
  "path": "data/tools-classification.json",
36
- "sha256": "b1216e31ed28655ea99d9ef06d82d4d35d5499bad1ecadc8e7051e8c74bd7c97"
36
+ "sha256": "9abb3ca6347b0cd6cd51b23649c59e0a0c816e6c12a325f573b392affa350d0b"
37
37
  },
38
38
  {
39
39
  "path": "data/tools-list-snapshot.json",
40
- "sha256": "c9f53d02b7ee06791eac22214ca91e999aeec2ee4dbd53b6a27dc46d4e5bcbc2"
40
+ "sha256": "dff98bb859dfbbf8ed2fb6f16f17b767444cc2172ecc7684ca3df8188c95707c"
41
+ },
42
+ {
43
+ "path": "docs/COST-COMPARE.md",
44
+ "sha256": "80b4d7ac3868f17d93565274cd6736fe5f2bd7fb059cbed0c2f0afe3f4924317"
41
45
  },
42
46
  {
43
47
  "path": "docs/HERMES-CODEX.md",
44
- "sha256": "08e1e83985c31b51aa053811b1b6a76fb1960323c5ccb8ae1d5fdd8b91b8df11"
48
+ "sha256": "3605797972f9a7c79c13fbcce0cd9ac8b8fb3a8249abbab938f2b1a45f515420"
45
49
  },
46
50
  {
47
51
  "path": "docs/LOCAL-TESTING.md",
48
- "sha256": "f043a370b9f23b2efc6c64702ab358ee168b6c9cd1b5d9efe4a9da287274e42c"
52
+ "sha256": "de6f709e820fbb831f390e274238b28ba938644670a8db04fd50d1fa0d86da75"
53
+ },
54
+ {
55
+ "path": "docs/cost-compare.example.json",
56
+ "sha256": "7eafb1ff555fb5443ded1a2c578b17eae6e73e3056efb9cbb5129b424c8c5097"
49
57
  },
50
58
  {
51
59
  "path": "package.json",
52
- "sha256": "671ebb618e9d0a939a047433791cd9a34e502339596d11a697b50fb32a0694ec"
60
+ "sha256": "1b355df670fb092da7ce8956141e702f9f78e1e2f2724c6aaba61bbab2acd8c8"
53
61
  },
54
62
  {
55
63
  "path": "src/classification.js",
@@ -57,7 +65,11 @@
57
65
  },
58
66
  {
59
67
  "path": "src/cli.js",
60
- "sha256": "af553e9261300eb46240212eb03b01ccc17234fed1a9f1587d5784f3bfacb5f4"
68
+ "sha256": "b1bd4a0ce7f1ca869c2873ca1979a74630483ee2909ff8b4f91189622f5aa2a7"
69
+ },
70
+ {
71
+ "path": "src/cost-compare.js",
72
+ "sha256": "6084ecd7f7fc53bbd441fb9e91dcd7c7bd5c409d1d4e95613fad0fd0735b7b05"
61
73
  },
62
74
  {
63
75
  "path": "src/credentials.js",
@@ -85,7 +97,7 @@
85
97
  },
86
98
  {
87
99
  "path": "src/resolve.js",
88
- "sha256": "5cbd0861c2973fab62271269b10f748b9638e74f40e8ea034f78ac63bed58001"
100
+ "sha256": "d3eba14c23be5bfb7e73952e6ae27908667d535f91be9c43e11dbf7b7c4de49d"
89
101
  },
90
102
  {
91
103
  "path": "src/safe-mcp.js",
@@ -107,6 +119,10 @@
107
119
  "path": "test/classification.test.mjs",
108
120
  "sha256": "026e3031180ce9227b4d31775b9c886b10ad0cb418ed0754aed75b12ded84e31"
109
121
  },
122
+ {
123
+ "path": "test/cost-compare.test.mjs",
124
+ "sha256": "b354913220bf725ec6b8a708b7851e2f5779a3c594cd411732d19acad9001870"
125
+ },
110
126
  {
111
127
  "path": "test/deploy-approval.test.mjs",
112
128
  "sha256": "d72e4363fd50d0fcc65fd23b40601516bd73368c3659f2a55a394c4d1ed3f85c"
@@ -137,11 +153,11 @@
137
153
  },
138
154
  {
139
155
  "path": "test/pack-holds.test.mjs",
140
- "sha256": "a083ff619f1d97b3e0e1b95dec6e98b56c4296da5171e2eb41c713dd983c8d69"
156
+ "sha256": "f5e66cce7344efb22c40bba91b422ce84979948b66bb0305377f8c12eb078002"
141
157
  },
142
158
  {
143
159
  "path": "test/resolve.test.mjs",
144
- "sha256": "3b695381c2df4f5b592b377bd3ef5b3f3953af9f6f140600cfcddc975563bffc"
160
+ "sha256": "9ad83ba418dee86ef680575a0cc7da4af4be3ae995c00f23f84b336838fbda47"
145
161
  },
146
162
  {
147
163
  "path": "test/safe-mcp.test.mjs",
@@ -149,5 +165,5 @@
149
165
  }
150
166
  ]
151
167
  },
152
- "signature": "beMcp+gzzBo2SQYH5kzMMqppEdWawWJo+JCttjU/Hf0Wns8Jzc6fNT4uU5d2NBuTP3+8bt2lKaPQn1WvlHWiBg=="
168
+ "signature": "dwHxhW1FRdiGNeOrlmZDXpWHEV3i/V9QenSrenI7+SvF6HNfxc1cM++fUKzWXZKRvTfbreooCqZHfcipil4vAw=="
153
169
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog — @dzhechkov/cloudru-hub
2
2
 
3
+ ## Unreleased — staged, no version change
4
+
5
+ - Add `cost-compare --input <json> [--json]`, an offline VM/Kubernetes cost worksheet
6
+ with explicit topology, dated tariff provenance, exact decimal sums and per-node
7
+ normal/failure capacity bounds. Incomplete prices, insufficient capacity or unknown
8
+ architecture equivalence suppress a winner. The packaged official-rate example
9
+ leaves traffic and equivalence unknown. See `docs/COST-COMPARE.md` for the schema
10
+ and limits. No engine or MCP tool changes are included.
11
+
12
+ ## 0.1.14 — 2026-10-20
13
+
14
+ - Prepare an exact optional dependency on `@dzhechkov/cloudru-vm-linux-x64@0.2.6`.
15
+ A fresh Linux/x64 installation resolves the separately packed Go engine;
16
+ no postinstall download is used.
17
+ - Credit Timur's substantial Cloud.ru API testing and the defects it revealed;
18
+ correct the earlier attribution in current package materials.
19
+ - Build the Linux/x64 platform engine with `CGO_ENABLED=0` and pin the resulting
20
+ static binary. The first GitHub Actions build exposed a C-toolchain-dependent
21
+ hash from the earlier dynamic build; the static artifact passed its GitHub CI build.
22
+
3
23
  ## 0.1.13 — 2026-10-20
4
24
 
5
25
  This release publishes the previously private launcher and host-adapter preview.
package/LICENSE CHANGED
@@ -1,14 +1,5 @@
1
1
  # LICENSE — @dzhechkov/cloudru-hub
2
2
 
3
- This file has two parts because the shipped work has two provenances. Part 1 covers every
4
- byte actually contained in this npm package. Part 2 records the licensing status of the
5
- Hermes engine additions, which this package deliberately does NOT contain.
6
-
7
- ---
8
-
9
- ## Part 1 — Code contained in this package (launcher, target adapters, installer, tests)
10
- ## and the original Go CLI foundation
11
-
12
3
  MIT License
13
4
 
14
5
  Copyright (c) 2026 Dmitry Zhechkov
@@ -31,37 +22,9 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
22
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32
23
  SOFTWARE.
33
24
 
34
- Authorship note (ADR-001 amendment AM-1, recorded 2026-08-09): the original Go CLI
35
- foundation on which the Hermes engine builds (cli.go / internal/cli) was authored by
36
- Dmitry Zhechkov, the owner of this repository. The Hermes engine is a DERIVATIVE work
37
- built on that foundation. This note states the owner's own authorship as fact; it does
38
- NOT assert, imply, or substitute for any grant by the Hermes engine author.
39
-
40
- ---
41
-
42
- ## Part 2 — The Hermes engine additions (the ~144-tool MCP layer) — NOT in this package
43
-
44
- This package contains ZERO bytes of the Hermes engine additions: no engine binary, no
45
- engine Go sources, no engine skill corpus. The engine binary is located at RUNTIME
46
- (environment variable / config path / a future platform package) and is never bundled
47
- here. See ADR-002 (distribution form) and the package README.
48
-
49
- Redistribution status of the engine additions (the Hermes author's contribution on top
50
- of the owner's CLI foundation):
51
-
52
- GRANT RECORDED (ADR-001 AM-2, exit 2 — 2026-08-12): Тимур, the author of the Hermes
53
- engine additions (the ~144-tool MCP layer built on the owner's original Go CLI
54
- foundation), approved publication of this package, as reported by the repository owner
55
- (Dmitry Zhechkov) on 2026-08-12. The approval is owner-attested; archiving the author's
56
- written confirmation is a recorded owner follow-up (see the grant record linked below).
57
- Per the owner's standing attribution condition, publication carries authorship credit:
58
- the Hermes engine additions are the work of Тимур; the original Go CLI foundation and
59
- every byte contained in this package are the work of Dmitry Zhechkov (Part 1).
60
-
61
- The author did not designate a licence text for the engine additions themselves.
62
- Accordingly: this package continues to ship ZERO bytes of the engine additions, the MIT
63
- licence in Part 1 covers ONLY the owner's code, and nothing in this file grants any
64
- third party rights to the engine additions — their use remains governed by their
65
- author's own terms.
25
+ This launcher archive contains ZERO bytes of the Go engine: no binary or Go sources.
26
+ The engine is distributed separately with its own package license and third-party
27
+ notices. Тимур contributed substantial Cloud.ru API testing and identified API
28
+ behavior and defects. The corrected attribution record is linked below.
66
29
 
67
30
  Grant-Confirmation: https://github.com/djd1m/dz-harness-hub/blob/main/features/hermes-claude-adaptation/03_adr/grant-record-2026-08-12.md
package/README.md CHANGED
@@ -1,14 +1,10 @@
1
1
  # @dzhechkov/cloudru-hub
2
2
 
3
- Site: https://aicoding.space · Source: https://github.com/djd1m/dz-harness/tree/main/packages/@dzhechkov/cloudru-hub
3
+ Site: https://aicoding.space · Source: https://github.com/djd1m/dz-harness/tree/main/packages/cloudru-hub
4
4
 
5
- > **STATUS: published — the ADR-001 licence hold is SATISFIED (AM-2, 2026-08-12).**
6
- > [Тимур](https://shkrbkv.ru/about/), the author of the Hermes engine additions, approved publication (owner-reported
7
- > 2026-08-12 — the grant record is linked from the `Grant-Confirmation:` line in LICENSE
8
- > Part 2; archiving the author's written confirmation is a recorded owner follow-up).
9
- > The `dz guard` `licence-hold` rule stays armed and keeps verifying
10
- > LICENSE/THIRD_PARTY_NOTICES/SPDX on every publish — a satisfied hold passes with the
11
- > trigger in place.
5
+ > **Linux/x64 distribution:** version 0.1.14 installs the exact optional engine
6
+ > package `@dzhechkov/cloudru-vm-linux-x64@0.2.6`. The `dz guard` `licence-hold`
7
+ > rule continues to check LICENSE, notices and SPDX on publish.
12
8
 
13
9
  > **Unofficial. NOT affiliated with, endorsed, or supported by Cloud.ru.** "Cloud.ru" is a
14
10
  > trademark of its owner; this launcher merely talks to the public Cloud.ru Evolution API
@@ -19,39 +15,41 @@ Thin JS launcher for the **`cloudru-vm` MCP engine** — a Go MCP server with **
19
15
  Evolution: VMs, k8s, PostgreSQL/Kafka/Redis, DNS, S3, certificates, billing/FinOps, and a
20
16
  docker-compose deploy wizard.
21
17
 
22
- **The npm archive contains no engine binary, and the platform binary package is not published.**
23
- All engine-backed commands, including inventory, billing, VM and Kubernetes operations,
24
- require an owner-supplied Go binary whose SHA-256 matches the pin below. A fresh npm install
25
- alone can inspect the launcher and generate configuration, but cannot run Cloud.ru tools.
18
+ The launcher archive contains no engine binary. On Linux/x64, npm installs the exact
19
+ optional platform package with the pinned Go engine. Run:
20
+
21
+ ```bash
22
+ npm install -g @dzhechkov/cloudru-hub@0.1.14
23
+ cloudru-hub self-test
24
+ ```
25
+
26
+ The self-test verifies the engine SHA-256, version, 144 live MCP tools and their
27
+ classification without Cloud.ru credentials. On another platform, or if optional
28
+ dependencies were disabled, provide a trusted binary with the same SHA-256.
26
29
 
27
30
  ## Attribution
28
31
 
29
- - **CLI foundation and everything in this package** (launcher, adapters, installer,
30
- tests): **Dmitry Zhechkov** (MIT — LICENSE Part 1). Per ADR-001 AM-1 the original Go
31
- CLI on which the engine builds is the owner's work; the Hermes engine is a derivative
32
- of it.
33
- - **Hermes engine additions** (the ~144-tool MCP layer): **[Тимур](https://shkrbkv.ru/about/)**, the Hermes author.
34
- **Zero bytes of those additions ship in this package** — no binary, no Go sources, no
35
- skill corpus. Publication of this package was approved by the author (grant recorded
36
- 2026-08-12 — LICENSE Part 2, `Grant-Confirmation:` link). The author designated no
37
- licence text for the engine additions themselves; nothing here grants third parties
38
- rights to them.
32
+ **[Тимур](https://shkrbkv.ru/about/)** carried out extensive Cloud.ru API testing,
33
+ identifying actual behavior and defects.
34
+ The JS launcher remains MIT-licensed; its archive contains no Go engine bytes.
39
35
 
40
36
  ## What ships here (our code only — ADR-002)
41
37
 
42
38
  | Piece | Where | What it does |
43
39
  |---|---|---|
44
- | Launcher | `bin/cloudru-hub.js` | resolves the engine binary at **runtime** (never bundled): `$CLOUDRU_VM_BIN` → `~/.cloudru-hub/config.json` `enginePath` → optional platform package `@dzhechkov/cloudru-vm-linux-x64` (not published); verifies sha256 against the pin in `package.json.cloudruHub.binaryHashes` |
40
+ | Launcher | `bin/cloudru-hub.js` | resolves the engine binary at **runtime** (never bundled): `$CLOUDRU_VM_BIN` → `~/.cloudru-hub/config.json` `enginePath` → optional platform package `@dzhechkov/cloudru-vm-linux-x64`; verifies sha256 against the pin in `package.json.cloudruHub.binaryHashes` |
45
41
  | Paid-step brake (ADR-004) | `src/install.js`, `templates/.claude/hooks/` | emits `permissions` **ask** rules for every mutating-or-shell-reaching tool (64 tools — MEASURED, `data/tools-classification.json` counts), **deny** for `secret_value`/`cert_private_key`, **allow** for 78 behaviour-audited read-only tools, in BOTH `mcp__cloudru-vm__`/`mcp__cloudru_vm__` spellings (prefix normalization not yet live-probed), plus a PreToolUse veto hook (ssh-guard + the kubectl `rollout` hole) — and **executes** the veto probe before declaring install success |
46
42
  | Target integration | `src/install.js`, `src/safe-mcp.js` | Codex, OpenCode and Pi get project MCP configs using a pinned proxy; Hermes gets a guarded `$HERMES_HOME/config.yaml` entry with a verified engine path. Claude Code's general install keeps its permissions and hook probe. The opt-in `vm-deploy` profile requires an exact-plan approval and confines remote commands to the returned VM. Codex, Hermes, OpenCode and Pi each completed both live static-site scenarios on 2026-10-20 with HTTP byte checks and exact resource cleanup. The `k8s-deploy` profile uses a separate exact-manifest approval and create-only Kubernetes operation; the same four hosts completed live Kubernetes deployment, readiness, exact-byte HTTP and cleanup checks. Claude Code has installer/registration checks but no live inference pass. |
47
43
  | Skill dialect compiler (ADR-006) | `src/dialects.js`, `data/dialects.json` | generates per-target variants of the canonical skill tree (which is NOT shipped — point `--canonical` at an engine distribution); hard-fails if any Hermes-dialect token survives AND if the engine codename survives in any case in any emitted file (positive invariant, not just the enumerated denylist); unlinks dangling links; enforces the 12 000-char router cap on lossy layouts; byte-deterministic |
48
44
  | Golden classification | `data/tools-classification.json` | every engine tool → allow/ask/deny; `allow` requires a BEHAVIOUR audit of the handler (read-only proven at the pinned baseline, engine file:line cited per entry). The previous `stack_status` behavior was unsafe; the imported engine now makes it observational and tests that invariant. A live tool unknown to the classifier is a drift finding. |
45
+ | Offline cost worksheet | `src/cost-compare.js`, `docs/cost-compare.example.json` | compares supplied VM and Kubernetes topology, capacity and dated tariff lines with exact decimal arithmetic; needs no engine, credentials or network access |
49
46
 
50
47
  ## Usage
51
48
 
52
49
  ```bash
53
50
  cloudru-hub resolve # where is the engine, which sha256, is it the pinned baseline
54
51
  cloudru-hub self-test # resolve → sha256 → engine version → live tools/list → coverage
52
+ cloudru-hub cost-compare --input docs/cost-compare.example.json --json # offline cost worksheet
55
53
  cloudru-hub mcp # run the engine as an MCP stdio server (what .mcp.json points at)
56
54
  cloudru-hub mcp-safe --toolsets inventory # pinned MCP proxy with a small allow-classified surface
57
55
  cloudru-hub install --target codex --toolsets billing # read-only balance, consumption and FinOps
@@ -69,15 +67,21 @@ cloudru-hub install --target agents-md # pointer-only section (no tools, no
69
67
  cloudru-hub compile-skill --canonical <engine>/skill/cloudru-hub --target claude-code --out ./skill-out
70
68
  ```
71
69
 
72
- ## Using an owner-supplied engine
70
+ The [cost worksheet guide](docs/COST-COMPARE.md) describes the versioned input, supported
71
+ units, exact calculations and limits. The packaged example uses checked official
72
+ VAT-inclusive tariff rows but leaves traffic unpriced and architecture equivalence
73
+ unknown; it therefore reports known subtotals with no winner. Supplied quantities
74
+ and tariff applicability remain operator assumptions, not verified inventory or a live bill.
75
+
76
+ ## Using an owner-supplied engine instead
73
77
 
74
78
  ```bash
75
- export CLOUDRU_VM_BIN=/path/to/private-build/cloudru-vm # pinned 0.2.6-20261020 preview
79
+ export CLOUDRU_VM_BIN=/path/to/trusted/cloudru-vm # must match the pinned build
76
80
  node bin/cloudru-hub.js self-test
77
81
  ```
78
82
 
79
83
  Expected: 5 green steps ending `self-test: ALL GREEN` (resolution, sha256 match against
80
- the pinned baseline `89c50734…12dbf10`, engine version, 144 live tools, full
84
+ the pinned baseline `4463b093…97a97c9b6`, engine version, 144 live tools, full
81
85
  classification coverage). Full walkthrough incl. `npm link` and MCP registration:
82
86
  [`docs/LOCAL-TESTING.md`](docs/LOCAL-TESTING.md).
83
87
 
@@ -85,7 +89,7 @@ Host setup, checks and limits: [`docs/HERMES-CODEX.md`](docs/HERMES-CODEX.md). T
85
89
 
86
90
  For billing through `mcp-safe`, add the optional `"agreement_id":"…"` to the owner-only `~/.config/cloudru-hub/credentials.json` alongside `key_id`, `secret` and `project_id`. The proxy forwards it to the Go child as `CLOUDRU_AGREEMENT_ID`. Existing environment-only billing setups remain supported when no credential file is configured. The current consumption tool reports the agreement-wide total; its output should not be presented as a per-project bill. See the [Cloud.ru instructions for locating the agreement ID](https://cloud.ru/docs/billing/ug/topics/faq__api_id_agreement).
87
91
 
88
- The `vm-deploy` and `k8s-deploy` profiles are included in the launcher as **opt-in previews**. They require a matching pinned Go binary and temporary credentials in a private local file. There is no published platform binary at this pin; a fresh npm installation alone cannot run them. A static site can be planned from a local HTML file or a bounded ZIP snapshot with `deploy_plan(static_site_source=...)`; the operator checks the source digest shown in the plan and supplies that digest to `approve`. Every included ZIP file is served publicly, so review the file list in the plan and keep credentials out of the artifact. Planning requires an existing available floating IP, whose ID is bound to the approval. Apply creates a dedicated TCP-80 security group, boots the VM from fixed Cloud-init data, and reports the site as verified only after the approved IP is attached to that VM and exact-byte HTTP checks pass. A private run journal keeps resource IDs for interrupted-run recovery and blocks blind replay. The estimate covers compute and disk; a public IP may have a separate charge. The static-site route does not authorize `vm_exec` over SSH. See the two-Snake acceptance procedure in `features/cloudru-cli-vm-deploy/SNAKE-ACCEPTANCE.md` in the private source tree.
92
+ The `vm-deploy` and `k8s-deploy` profiles are included in the launcher as **opt-in previews**. They require the matching pinned Go binary and temporary credentials in a private local file. On Linux/x64, a normal npm installation supplies that binary through the optional platform package. A static site can be planned from a local HTML file or a bounded ZIP snapshot with `deploy_plan(static_site_source=...)`; the operator checks the source digest shown in the plan and supplies that digest to `approve`. Every included ZIP file is served publicly, so review the file list in the plan and keep credentials out of the artifact. Planning requires an existing available floating IP, whose ID is bound to the approval. Apply creates a dedicated TCP-80 security group, boots the VM from fixed Cloud-init data, and reports the site as verified only after the approved IP is attached to that VM and exact-byte HTTP checks pass. A private run journal keeps resource IDs for interrupted-run recovery and blocks blind replay. The estimate covers compute and disk; a public IP may have a separate charge. The static-site route does not authorize `vm_exec` over SSH. See the two-Snake acceptance procedure in `features/cloudru-cli-vm-deploy/SNAKE-ACCEPTANCE.md` in the private source tree.
89
93
 
90
94
  The Kubernetes preview accepts only one reviewed manifest containing a ConfigMap, a non-root single-pod Deployment and a ClusterIP Service in an existing namespace. `k8s-approve` binds exact manifest bytes, cluster, namespace, project and a ten-minute single-use approval. The agent passes only the approval ID; the proxy forwards `create_only=true`, so an existing resource name is a conflict instead of being patched. Kubernetes `create` is not transactional across three documents: inspect and clean up any partially created resources by exact name before trying again. Use a dedicated namespace with no pre-existing resources matching the app label or the three approved names. The profile does not create a cluster, namespace, nodes, NAT, ingress or load balancer. The example, local evidence and four-host live acceptance are in `features/cloudru-k8s-snake-deploy/` in private source. The service account's initial 403 was resolved by granting the Kubernetes role; Claude Code inference remains unavailable for a live host test.
91
95
 
@@ -96,12 +100,10 @@ Every named property has a mutation-gate entry (`test/mutation-registry.json`, r
96
100
  and requires the suite to go RED. The registry passed on 2026-10-20 with 13/13
97
101
  protections proven:
98
102
 
99
- 1. **The licence gate stays armed post-grant** — the `licenseHold` trigger field
100
- deliberately STAYS in package.json, so the `dz guard` `licence-hold` HARD rule keeps
101
- verifying LICENSE (grant record + `Grant-Confirmation:` URL, no PENDING placeholder),
102
- THIRD_PARTY_NOTICES and the SPDX field on every publish; pack tests additionally pin
103
- the honest grant wording (owner-attested, no fabricated grant deed), the SPDX-matches-
104
- LICENSE invariant (ADR-001 Confirmation) and the publishable state.
103
+ 1. **The licence gate stays armed** — the `licenseHold` trigger field remains in
104
+ package.json, so `dz guard` checks LICENSE, the corrected provenance link,
105
+ THIRD_PARTY_NOTICES and the SPDX field on every publish. Pack tests verify the
106
+ corrected API-testing attribution and the publishable state.
105
107
  2. **Zero upstream engine bytes** — explicit `files[]` whitelist + a test that walks the
106
108
  `npm pack --dry-run` file list rejecting ELF magic, `.go` sources and engine paths.
107
109
  3. **The paid-step brake vetoes** — acid fixtures run the emitted hook (`sshpass` → exit 2,
@@ -130,19 +132,13 @@ protections proven:
130
132
  either scrub goes RED (`dialect-binary-path-leak-scrubbed`,
131
133
  `dialect-binary-invocation-leak-scrubbed`).
132
134
 
133
- ## Post-grant publish checklist (executed 2026-08-12)
134
-
135
- 1. ✅ Grant recorded (ADR-001 AM-2, exit 2): LICENSE Part 2 placeholder replaced with the
136
- owner-attested grant record + `Grant-Confirmation:` link, `"license": "MIT"` (owner
137
- code only), `private` removed, `licenseHold` trigger deliberately KEPT armed.
138
- Open owner follow-up: archive the author's written confirmation in the grant record.
139
- 2. ✅ `dz guard check --op publish` passes (the licence-hold rule verifies all of it).
140
- 3. ⏳ NOT YET: the platform package `@dzhechkov/cloudru-vm-linux-x64` (the binary-carrying
141
- channel) still requires the ADR-002 trusted-CI build (`-trimpath`, sha256 must equal
142
- `cloudruHub.binaryHashes['linux-x64']`) + the go-licenses reconciliation in
143
- THIRD_PARTY_NOTICES before ITS first publication. Until then the engine binary is
144
- supplied via `$CLOUDRU_VM_BIN` or `~/.cloudru-hub/config.json` (see *Local testing*).
145
- 4. ✅ Published via the repo's standard release flow.
135
+ ## Platform package status
136
+
137
+ The separate `@dzhechkov/cloudru-vm-linux-x64@0.2.6` package is installed
138
+ automatically on Linux/x64 unless optional dependencies are disabled. Its static
139
+ build reproduces the pinned SHA-256 and bundles the license and NOTICE files
140
+ of linked Go modules. `CLOUDRU_VM_BIN` and `~/.cloudru-hub/config.json` remain
141
+ available for an explicitly supplied matching binary (see *Local testing*).
146
142
 
147
143
  ## Tests
148
144
 
@@ -3,10 +3,11 @@
3
3
  This npm package itself contains no third-party code (its launcher, adapters, installer
4
4
  and tests are original work — see LICENSE Part 1, MIT).
5
5
 
6
- This file exists because of ADR-001 point 4: the `cloudru-vm` engine binary that the
7
- launcher RESOLVES AT RUNTIME (and that a future `@dzhechkov/cloudru-vm-linux-x64`
8
- platform package would carry, post-grant) is a statically linked Go executable that
9
- embeds the following third-party modules (source of record: `engine/go.mod` in the
6
+ This file provides background for the `cloudru-vm` engine binary that the launcher
7
+ RESOLVES AT RUNTIME. The separate Linux/x64 package carries its own generated inventory
8
+ and full license/NOTICE texts for modules linked into the exact packed binary. The
9
+ current Linux/x64 binary is built with `CGO_ENABLED=0`. The historical table below
10
+ comes from `engine/go.mod` in the
10
11
  pinned baseline `hermes-engine-src-20260718.tgz`, sha256
11
12
  `007e7cbe851d3ecd78f457f81ae3679904b2fd4dac660a0e349dabcde61bbe5c` — see
12
13
  `features/hermes-claude-adaptation/evidence/ENGINE-BASELINE.json`).
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$comment": "Golden classification of every cloudru-vm engine tool. allow requires a BEHAVIOUR audit of the handler at the pinned engine SHA proving both axes: (1) observational with no cloud mutation, job advancement or secret return (a local plan write is disclosed), and (2) no user-controlled argument reaching shell/exec/SSH. Shell-reaching tools remain ask even when arguments are quoted. Schema shape alone never proves allow. The old baseline had two hazards: stack_status advanced planned jobs into paid actions and logs inserted an unescaped service into a shell command. In the pinned engine, stack_status reads persisted state only; stack_apply explicitly advances jobs, and logs shell-quotes service. The specific regression tests are in go/cloudru-vm/internal/mcp/stack_status_test.go and internal/engine/logs_test.go. Any unknown live tool fails drift checks; deny by default.",
3
- "engineSha256": "89c5073418927ee71ac1de381eaba5ab69d599d615edc51b868d876e712dbf10",
3
+ "engineSha256": "4463b09323c9dfe0c32d618d335734a947e7fab0a75d07a7bea089b97a97c9b6",
4
4
  "toolCount": 144,
5
5
  "counts": {
6
6
  "ask": 64,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "capturedAt": "2026-10-20",
3
3
  "engineVersion": "cloudru-vm 0.2.6-20261020",
4
- "engineSha256": "89c5073418927ee71ac1de381eaba5ab69d599d615edc51b868d876e712dbf10",
4
+ "engineSha256": "4463b09323c9dfe0c32d618d335734a947e7fab0a75d07a7bea089b97a97c9b6",
5
5
  "method": "JSON-RPC tools/list via src/probe-child.js against locally built private engine",
6
6
  "toolCount": 144,
7
7
  "tools": [
@@ -0,0 +1,21 @@
1
+ # Offline VM / Kubernetes cost worksheet
2
+
3
+ Run from an installed package or this directory:
4
+
5
+ ```bash
6
+ cloudru-hub cost-compare --input docs/cost-compare.example.json --json
7
+ ```
8
+
9
+ The command reads one local JSON file and does not resolve the engine, request credentials, call Cloud.ru, create resources or refresh tariffs. `--json` prints exact line, category and known-subtotal decimal strings plus two-decimal display strings. Without it, the command prints a compact human summary. Invalid input exits nonzero and emits no partial JSON. Only `--input <path>` and one optional `--json` are accepted. The file must be a regular, non-symlink file of at most 128 KiB.
10
+
11
+ The [runnable example](cost-compare.example.json) models 24 active hours. Its listed official tariff rows were checked on 2026-10-21 and are pinned as supplied metadata, not live prices or an applicability guarantee. It calculates known subtotals of **251.6616 RUB for VM** and **466.1376 RUB for Kubernetes**. Both leave traffic unpriced and architecture/HA equivalence unknown, so `winner` and `savingsRubExact` are `null`. The 60GB/80GB SSD allocations, IP counts, one Kubernetes SNAT and absence of load balancers are declared scenario assumptions. The worksheet cannot establish whether root, worker or control-plane volumes are separately charged for a real deployment.
12
+
13
+ The v1 input has `schemaVersion: 1`, one decimal-string `horizonHours` (greater than zero, at most 8760), `currency: "RUB"`, and `vatBasis: "included"`. `workload` supplies integer `replicas`, `survivingReplicas` and `failedNodes`, plus decimal-string `cpuPerReplica` and `ramGBPerReplica`. Both scenarios share those targets. Raw JSON numeric tokens must be canonical non-negative safe integers; fractional, exponent, negative and oversized tokens are rejected before parsing. Decimal values belong in strings. Duplicate object member names are rejected at every depth, including escaped spellings of the same name. `equivalence` is either `{ "status": "unknown", "reason": "...", "assumptions": [...] }` or `{ "status": "assumed", "assumptions": ["..."] }`. An assumed comparison remains conditional; this tool has no verified-equivalence state.
14
+
15
+ Exactly one `vm` and one `k8s` scenario are required, each with a unique `id`. Each declares homogeneous `nodes` (`count`, `cpu`, `ramGB`, `cpuShare`, `reservedCpu`, `reservedRamGB`), `controlPlaneCount`, `resources`, and all seven `categories`. CPU reservations are in guaranteed-core units: usable CPU is `cpu × cpuShare − reservedCpu`. Usable RAM is `ramGB − reservedRamGB`. Per-node replica slots are the smaller of the two exact decimal floors. Normal slots use all worker nodes; survival slots subtract the declared failed worker-node count. Control-plane instances are excluded from workload capacity. This is a numerical homogeneous packing bound, not proof of placement, scheduling, service performance, availability or SLA. Kubernetes requires a positive billed control-plane service count; VM requires zero.
16
+
17
+ `resources` declares `storageGB`, `publicIpCount`, `snatGatewayCount`, `loadBalancerCount` and `trafficGB`. Storage and traffic are decimal strings; IP, SNAT and load-balancer counts are integers. `trafficGB` alone may be `null`, meaning usage is unknown and its category must be `unpriced` with a reason. Zero is an explicit declaration and requires `not-used`, never an implicit free charge. Every other positive or unknown declared quantity must be `priced` or `unpriced` with a reason. Compute cannot be `not-used`; VM control-plane must be `not-used`.
18
+
19
+ Every category is `{ "status": "priced", "items": [...] }`, `{ "status": "not-used", "reason": "..." }`, or `{ "status": "unpriced", "reason": "..." }`. Priced items need a unique `id`, description, positive decimal-string `quantity` and `rateRub`, exact category unit, and tariff provenance `{ "url": "https://...", "version": "...", "asOf": "YYYY-MM-DD", "vatBasis": "included", "pageOrRow": "..." }` with optional lowercase SHA-256. The tariff URL and metadata are user assertions; they are checked for format and consistency, not fetched or certified. Supported units are `instance-hour` for compute/control-plane, `GB-hour` for storage, `IP-hour`, `gateway-hour`, `LB-hour`, and `traffic-GB`. Worker and control-plane instance counts and every other priced category quantity must sum exactly to their declared scenario counts or allocations. Traffic is charged once over the whole horizon; time units multiply by the common horizon. Monthly, tiered, stopped-resource and scheduled rates are outside v1.
20
+
21
+ Exact decimal multiplication and summation precede display rounding. Each input decimal has at most nine fractional places, and file, topology, line-count, quantity, rate and result magnitudes are bounded. `knownSubtotalRubExact` is only a sum of priced lines, not a guaranteed lower bound on an actual bill. A winner appears only when both scenarios have all categories resolved, sufficient normal and declared node-failure capacity, and explicit assumed equivalence. It identifies the lower **modeled infrastructure cost under supplied assumptions**, with a tie reported separately. It is not a deployment recommendation. Discounts, taxes beyond the common VAT-inclusive basis, heterogeneous fleets, autoscaling, live billing, network traffic tariffs and real resource inventory need separate evidence.
@@ -10,7 +10,7 @@ The separate `--toolsets vm-deploy` profile allows one reviewed VM plan and remo
10
10
 
11
11
  This local approval is an operator workflow, not a hard security boundary against an agent with unrestricted shell access as the same Unix user: such an agent could invoke `approve` or edit the local files itself. Use process/user isolation and cloud IAM limits if the deployment agent is untrusted. The cost number is an estimate, and the operator cap controls the reviewed plan, not Cloud.ru's final bill.
12
12
 
13
- The engine binary is **not bundled**. The pinned preview is built from the private `go/cloudru-vm` source as `go/cloudru-vm/out/cloudru/cloudru-vm`; elsewhere set `CLOUDRU_VM_BIN` to an owner-supplied trusted copy whose hash matches `package.json.cloudruHub.binaryHashes`. Run `cloudru-hub self-test --json` first. A missing or changed binary makes `mcp-safe` refuse startup. The platform package `@dzhechkov/cloudru-vm-linux-x64` has not been published; this launcher release alone does not supply a working engine to a fresh npm installation.
13
+ The launcher archive does **not bundle** the engine. A Linux/x64 npm install pulls `@dzhechkov/cloudru-vm-linux-x64@0.2.6` as an exact optional dependency. On other platforms, or when optional dependencies are disabled, set `CLOUDRU_VM_BIN` to a trusted copy whose hash matches `package.json.cloudruHub.binaryHashes`. Run `cloudru-hub self-test --json` first. A missing or changed binary makes `mcp-safe` refuse startup.
14
14
 
15
15
  | Host | Setup | Activation check |
16
16
  |---|---|---|
@@ -1,6 +1,6 @@
1
- # Local testing — @dzhechkov/cloudru-hub (owner-supplied engine)
1
+ # Local testing — @dzhechkov/cloudru-hub
2
2
 
3
- The launcher runs against the private Go build. These checks do not publish engine bytes; public redistribution still requires the separate engine grant and dependency review.
3
+ The launcher runs against the pinned Go build. Its archive contains no engine bytes; the Linux/x64 optional package contains the static engine and its dependency-license inventory.
4
4
 
5
5
  ## 1. Point the launcher at an engine binary
6
6
 
@@ -8,19 +8,19 @@ Any of the three, in this precedence order:
8
8
 
9
9
  ```bash
10
10
  # a) environment variable (simplest — what the self-test proof below uses)
11
- export CLOUDRU_VM_BIN=/path/to/dz-harness-hub/go/cloudru-vm/out/cloudru/cloudru-vm
11
+ export CLOUDRU_VM_BIN=/path/to/dz-harness-hub/packages/@dzhechkov/cloudru-vm-linux-x64/native/cloudru-vm
12
12
 
13
13
  # b) persistent config
14
14
  mkdir -p ~/.cloudru-hub
15
15
  cat > ~/.cloudru-hub/config.json <<'EOF'
16
- { "enginePath": "/path/to/dz-harness-hub/go/cloudru-vm/out/cloudru/cloudru-vm" }
16
+ { "enginePath": "/path/to/dz-harness-hub/packages/@dzhechkov/cloudru-vm-linux-x64/native/cloudru-vm" }
17
17
  EOF
18
18
 
19
- # c) a future platform package matching the private build's pin
19
+ # c) no override: the installed Linux/x64 optional platform package
20
20
  ```
21
21
 
22
22
  The pinned binary identifies itself as `cloudru-vm 0.2.6-20261020` and has SHA-256
23
- `89c5073418927ee71ac1de381eaba5ab69d599d615edc51b868d876e712dbf10`.
23
+ `4463b09323c9dfe0c32d618d335734a947e7fab0a75d07a7bea089b97a97c9b6`.
24
24
 
25
25
  ## 2. Self-test (end-to-end, no credentials required)
26
26
 
@@ -32,8 +32,8 @@ node bin/cloudru-hub.js self-test
32
32
  Expected output for the current private build:
33
33
 
34
34
  ```
35
- ✓ resolve: …/out/cloudru/cloudru-vm (source: env)
36
- ✓ sha256: 89c5073418927ee71ac1de381eaba5ab69d599d615edc51b868d876e712dbf10 — MATCHES pinned baseline
35
+ ✓ resolve: …/cloudru-vm-linux-x64/native/cloudru-vm (source: env)
36
+ ✓ sha256: 4463b09323c9dfe0c32d618d335734a947e7fab0a75d07a7bea089b97a97c9b6 — MATCHES pinned baseline
37
37
  ✓ engine-version: cloudru-vm 0.2.6-20261020
38
38
  ✓ tools-list: 144 tools live (snapshot: 144)
39
39
  ✓ classification-coverage: every live tool is classified (144 golden entries)
@@ -66,4 +66,4 @@ appears; note which prefix spelling the runtime used.
66
66
 
67
67
  ## 5. Testing from another server (`npm install` path)
68
68
 
69
- The platform package is not published. Until the engine redistribution gate clears, another private server can install the launcher from npm but still needs an owner-supplied Go binary matching the pinned SHA-256.
69
+ On Linux/x64, install `@dzhechkov/cloudru-hub@0.1.14` normally and run `cloudru-hub self-test` without setting `CLOUDRU_VM_BIN`. npm installs the exact optional engine package. If optional dependencies were disabled or the platform is unsupported, provide a matching trusted binary explicitly.
@@ -0,0 +1,84 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "horizonHours": "24",
4
+ "currency": "RUB",
5
+ "vatBasis": "included",
6
+ "workload": {
7
+ "replicas": 3,
8
+ "cpuPerReplica": "1",
9
+ "ramGBPerReplica": "1",
10
+ "survivingReplicas": 2,
11
+ "failedNodes": 1
12
+ },
13
+ "equivalence": {
14
+ "status": "unknown",
15
+ "reason": "Application placement, availability and performance equivalence have not been verified.",
16
+ "assumptions": ["Both scenarios run the same three replicas for the full 24-hour horizon."]
17
+ },
18
+ "scenarios": [
19
+ {
20
+ "id": "vm",
21
+ "kind": "vm",
22
+ "nodes": { "count": 3, "cpu": "2", "ramGB": "4", "reservedCpu": "0", "reservedRamGB": "0", "cpuShare": "1" },
23
+ "controlPlaneCount": 0,
24
+ "resources": { "storageGB": "60", "publicIpCount": 3, "snatGatewayCount": 0, "loadBalancerCount": 0, "trafficGB": null },
25
+ "categories": {
26
+ "compute": { "status": "priced", "items": [{
27
+ "id": "vm-2cpu-4gb", "description": "Three active 2vCPU/4GB VM instances",
28
+ "quantity": "3", "unit": "instance-hour", "rateRub": "2.9707",
29
+ "tariff": { "url": "https://cdn.cloud.ru/docs/legal/tariffs/evolution/current-version/evolution-compute.pdf", "version": "261014", "asOf": "2026-10-21", "vatBasis": "included", "pageOrRow": "VM 2vCPU/4GB row 18", "sha256": "a459226e73c8db4dc650307f3f07d99d9f17be31e0e22cd65c7a360dc1685dc5" }
30
+ }] },
31
+ "controlPlane": { "status": "not-used", "reason": "VM scenario has no separately billed control-plane service." },
32
+ "storage": { "status": "priced", "items": [{
33
+ "id": "ssd-60gb", "description": "Assumed 60GB billed SSD allocation across the VM scenario",
34
+ "quantity": "60", "unit": "GB-hour", "rateRub": "0.01586",
35
+ "tariff": { "url": "https://cdn.cloud.ru/docs/legal/tariffs/evolution/current-version/evolution-compute.pdf", "version": "261014", "asOf": "2026-10-21", "vatBasis": "included", "pageOrRow": "SSD row 85", "sha256": "a459226e73c8db4dc650307f3f07d99d9f17be31e0e22cd65c7a360dc1685dc5" }
36
+ }] },
37
+ "publicIp": { "status": "priced", "items": [{
38
+ "id": "vm-public-ip", "description": "Three assumed active public IP allocations",
39
+ "quantity": "3", "unit": "IP-hour", "rateRub": "0.2074",
40
+ "tariff": { "url": "https://cdn.cloud.ru/docs/legal/tariffs/evolution/current-version/evolution-compute.pdf", "version": "261014", "asOf": "2026-10-21", "vatBasis": "included", "pageOrRow": "Public IP row 2", "sha256": "a459226e73c8db4dc650307f3f07d99d9f17be31e0e22cd65c7a360dc1685dc5" }
41
+ }] },
42
+ "snat": { "status": "not-used", "reason": "No SNAT gateway is declared in this VM scenario." },
43
+ "loadBalancer": { "status": "not-used", "reason": "No load balancer is declared; direct public IP exposure is assumed." },
44
+ "traffic": { "status": "unpriced", "reason": "Traffic quantity and applicable tariff are unknown; do not assume zero traffic cost." }
45
+ }
46
+ },
47
+ {
48
+ "id": "k8s",
49
+ "kind": "k8s",
50
+ "nodes": { "count": 3, "cpu": "2", "ramGB": "4", "reservedCpu": "0", "reservedRamGB": "0", "cpuShare": "1" },
51
+ "controlPlaneCount": 1,
52
+ "resources": { "storageGB": "80", "publicIpCount": 2, "snatGatewayCount": 1, "loadBalancerCount": 0, "trafficGB": null },
53
+ "categories": {
54
+ "compute": { "status": "priced", "items": [{
55
+ "id": "worker-2cpu-4gb", "description": "Three active 2vCPU/4GB Kubernetes workers",
56
+ "quantity": "3", "unit": "instance-hour", "rateRub": "2.9768",
57
+ "tariff": { "url": "https://cdn.cloud.ru/docs/legal/tariffs/evolution/current-version/managed-kubernetes.pdf", "version": "260918", "asOf": "2026-10-21", "vatBasis": "included", "pageOrRow": "Worker 2vCPU/4GB row 6", "sha256": "5493f6da595b67482277ca420512db8f7f953375536a6169db8d1b282f24f345" }
58
+ }] },
59
+ "controlPlane": { "status": "priced", "items": [{
60
+ "id": "zonal-master", "description": "One billed zonal control-plane service instance",
61
+ "quantity": "1", "unit": "instance-hour", "rateRub": "8.601",
62
+ "tariff": { "url": "https://cdn.cloud.ru/docs/legal/tariffs/evolution/current-version/managed-kubernetes.pdf", "version": "260918", "asOf": "2026-10-21", "vatBasis": "included", "pageOrRow": "Zonal master 2vCPU/4GB row 42", "sha256": "5493f6da595b67482277ca420512db8f7f953375536a6169db8d1b282f24f345" }
63
+ }] },
64
+ "storage": { "status": "priced", "items": [{
65
+ "id": "ssd-80gb", "description": "Assumed 80GB billed SSD allocation across the Kubernetes scenario",
66
+ "quantity": "80", "unit": "GB-hour", "rateRub": "0.01586",
67
+ "tariff": { "url": "https://cdn.cloud.ru/docs/legal/tariffs/evolution/current-version/managed-kubernetes.pdf", "version": "260918", "asOf": "2026-10-21", "vatBasis": "included", "pageOrRow": "SSD row 39", "sha256": "5493f6da595b67482277ca420512db8f7f953375536a6169db8d1b282f24f345" }
68
+ }] },
69
+ "publicIp": { "status": "priced", "items": [{
70
+ "id": "k8s-public-ip", "description": "Two assumed active public IP allocations",
71
+ "quantity": "2", "unit": "IP-hour", "rateRub": "0.2074",
72
+ "tariff": { "url": "https://cdn.cloud.ru/docs/legal/tariffs/evolution/current-version/managed-kubernetes.pdf", "version": "260918", "asOf": "2026-10-21", "vatBasis": "included", "pageOrRow": "Public IP row 40", "sha256": "5493f6da595b67482277ca420512db8f7f953375536a6169db8d1b282f24f345" }
73
+ }] },
74
+ "snat": { "status": "priced", "items": [{
75
+ "id": "public-snat", "description": "One assumed active public SNAT gateway",
76
+ "quantity": "1", "unit": "gateway-hour", "rateRub": "0.2074",
77
+ "tariff": { "url": "https://cdn.cloud.ru/docs/legal/tariffs/evolution/current-version/evolution-compute.pdf", "version": "261014", "asOf": "2026-10-21", "vatBasis": "included", "pageOrRow": "Public SNAT row 3", "sha256": "a459226e73c8db4dc650307f3f07d99d9f17be31e0e22cd65c7a360dc1685dc5" }
78
+ }] },
79
+ "loadBalancer": { "status": "not-used", "reason": "No load balancer is declared; the assumed application architecture avoids it." },
80
+ "traffic": { "status": "unpriced", "reason": "Traffic quantity and applicable tariff are unknown; do not assume zero traffic cost." }
81
+ }
82
+ }
83
+ ]
84
+ }