mirror of
https://github.com/affaan-m/ECC.git
synced 2026-08-17 21:15:40 +02:00
feat: connect ECC to canonical Ito compute CLI (#2558)
This commit is contained in:
@@ -16,4 +16,4 @@ export ANTHROPIC_AUTH_TOKEN=your-token
|
||||
claude
|
||||
```
|
||||
|
||||
Run or self-host any open-source model behind that endpoint. Itô is ECC's preferred compute sponsor: [open the Itô dashboard to sign in and rent or manage GPUs](https://compute.itomarkets.com). Any GPU provider works. ECC only provides this link; it does not change Claude Code transport settings or provision compute or serving. Managed inference through Itô is not live yet.
|
||||
Run or self-host any open-source model behind that endpoint. Itô is ECC's preferred compute sponsor: [open the Itô dashboard to sign in and rent or manage GPUs](https://compute.itomarkets.com). Any GPU provider works. That sponsorship link is passive: it does not invoke an RFQ, reserve capacity, change Claude Code transport settings, provision compute, or configure serving. Separately, the opt-in `ecc ito find` bridge invokes the explicitly configured canonical Itô CLI and submits a live authenticated RFQ; it does not reserve capacity. Managed inference through Itô is not live yet.
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
{
|
||||
"name": "ecc",
|
||||
"source": "./",
|
||||
"description": "Harness-native ECC operator layer - 67 agents, 278 skills, 94 legacy command shims, reusable hooks, rules, selective install profiles, and production-ready workflows for Claude Code, Codex, OpenCode, Cursor, and related agent harnesses",
|
||||
"description": "Harness-native ECC operator layer - 67 agents, 279 skills, 94 legacy command shims, reusable hooks, rules, selective install profiles, and production-ready workflows for Claude Code, Codex, OpenCode, Cursor, and related agent harnesses",
|
||||
"version": "2.0.0",
|
||||
"author": {
|
||||
"name": "Affaan Mustafa",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ecc",
|
||||
"version": "2.0.0",
|
||||
"description": "Harness-native ECC plugin for engineering teams - 67 agents, 278 skills, 94 legacy command shims, reusable hooks, rules, MCP conventions, and operator workflows for Claude Code plus adjacent agent harnesses",
|
||||
"description": "Harness-native ECC plugin for engineering teams - 67 agents, 279 skills, 94 legacy command shims, reusable hooks, rules, MCP conventions, and operator workflows for Claude Code plus adjacent agent harnesses",
|
||||
"author": {
|
||||
"name": "Affaan Mustafa",
|
||||
"url": "https://x.com/affaanmustafa"
|
||||
|
||||
+1
-1
@@ -23,4 +23,4 @@ bash ./install.sh --target kimi --profile minimal
|
||||
|
||||
## Self-hosted model compute
|
||||
|
||||
Run or self-host any open-source model—including Kimi—on owned or rented GPUs. Itô is ECC's preferred compute sponsor: [open the Itô dashboard to sign in and rent or manage GPUs](https://compute.itomarkets.com). Any GPU provider works. ECC only provides this link; it does not provision compute or serving. Managed inference through Itô is not live yet.
|
||||
Run or self-host any open-source model—including Kimi—on owned or rented GPUs. Itô is ECC's preferred compute sponsor: [open the Itô dashboard to sign in and rent or manage GPUs](https://compute.itomarkets.com). Any GPU provider works. That sponsorship link is passive: it does not invoke an RFQ, reserve capacity, provision compute, or configure serving. Separately, the opt-in `ecc ito find` bridge invokes the explicitly configured canonical Itô CLI and submits a live authenticated RFQ; it does not reserve capacity. Managed inference through Itô is not live yet.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Everything Claude Code (ECC) — Agent Instructions
|
||||
|
||||
This is a **production-ready AI coding plugin** providing 67 specialized agents, 278 skills, 94 commands, and automated hook workflows for software development.
|
||||
This is a **production-ready AI coding plugin** providing 67 specialized agents, 279 skills, 94 commands, and automated hook workflows for software development.
|
||||
|
||||
**Version:** 2.0.0
|
||||
|
||||
@@ -152,7 +152,7 @@ Troubleshoot failures: check test isolation → verify mocks → fix implementat
|
||||
|
||||
```
|
||||
agents/ — 67 specialized subagents
|
||||
skills/ — 278 workflow skills and domain knowledge
|
||||
skills/ — 279 workflow skills and domain knowledge
|
||||
commands/ — 94 slash commands
|
||||
hooks/ — Trigger-based automations
|
||||
rules/ — Always-follow guidelines (common + per-language)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
1`**Language:** English | [Português (Brasil)](docs/pt-BR/README.md) | [简体中文](README.zh-CN.md) | [繁體中文](docs/zh-TW/README.md) | [日本語](docs/ja-JP/README.md) | [한국어](docs/ko-KR/README.md) | [Türkçe](docs/tr/README.md) | [Русский](docs/ru/README.md) | [Tiếng Việt](docs/vi-VN/README.md) | [ไทย](docs/th/README.md) | [Deutsch](docs/de-DE/README.md) | [Español](docs/es/README.md)
|
||||
**Language:** English | [Português (Brasil)](docs/pt-BR/README.md) | [简体中文](README.zh-CN.md) | [繁體中文](docs/zh-TW/README.md) | [日本語](docs/ja-JP/README.md) | [한국어](docs/ko-KR/README.md) | [Türkçe](docs/tr/README.md) | [Русский](docs/ru/README.md) | [Tiếng Việt](docs/vi-VN/README.md) | [ไทย](docs/th/README.md) | [Deutsch](docs/de-DE/README.md) | [Español](docs/es/README.md)
|
||||
|
||||

|
||||
|
||||
@@ -112,6 +112,12 @@ ECC v2.0.0 adds the public Hermes operator story on top of that reusable layer:
|
||||
<strong>Itô</strong>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" width="220">
|
||||
<a href="https://www.moonshot.ai/">
|
||||
<img src="assets/images/sponsors/moonshot.svg" width="96" alt="Moonshot AI Kimi logo" /><br />
|
||||
<strong>Moonshot AI</strong>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -445,7 +451,7 @@ If you stacked methods, clean up in this order:
|
||||
/plugin list ecc@ecc
|
||||
```
|
||||
|
||||
**That's it!** You now have access to 67 agents, 278 skills, and 94 legacy command shims.
|
||||
**That's it!** You now have access to 67 agents, 279 skills, and 94 legacy command shims.
|
||||
|
||||
### Dashboard GUI
|
||||
|
||||
@@ -1194,7 +1200,27 @@ claude
|
||||
|
||||
If your gateway remaps model names, configure that in Claude Code rather than in ECC. ECC's hooks, skills, commands, and rules are model-provider agnostic once the `claude` CLI is already working.
|
||||
|
||||
Run or self-host any open-source model behind that gateway using separate compute and serving setup. If you need GPU capacity, [Itô](https://compute.itomarkets.com) is ECC's preferred compute sponsor; any GPU provider works. ECC only links to the Itô dashboard for sign-in and GPU rental or management—it does not provision compute or serving. Managed inference through Itô is not live yet.
|
||||
Run or self-host any open-source model behind that gateway using separate compute and serving setup. If you need GPU capacity, [Itô](https://compute.itomarkets.com) is ECC's preferred compute sponsor; any GPU provider works. That sponsorship link is passive: it does not invoke an RFQ, reserve capacity, provision compute, or configure serving. Separately, the opt-in `ecc ito find` bridge invokes the explicitly configured canonical Itô CLI and submits a live authenticated RFQ; it does not reserve capacity. Managed inference through Itô is not live yet.
|
||||
|
||||
### Itô compute CLI bridge
|
||||
|
||||
`ecc ito` delegates to the separately installed canonical Itô client; ECC does
|
||||
not maintain a second API client or browser handoff. The available operations
|
||||
are `ecc ito auth`, `ecc ito find`, and `ecc ito status`. The matching MCP tools
|
||||
are `ito_auth`, `ito_find`, and `ito_status`.
|
||||
|
||||
The `ito-compute-cli` package is currently unpublished. Build it locally from
|
||||
[`Ito-Markets/ito-cloud-runtime`](https://github.com/Ito-Markets/ito-cloud-runtime)
|
||||
under `cli/ito-compute-cli`, run `npm ci` and `npm run check`, then set
|
||||
`ECC_ITO_CLI_EXECUTABLE` to that build's absolute `dist/bin/ito.js` path.
|
||||
Inject `ITO_API_KEY` from 1Password or the launching environment. ECC does not
|
||||
discover this credential-bearing client through `PATH`. See the [`ito-compute`
|
||||
skill](skills/ito-compute/SKILL.md) for the full RFQ authority and MCP setup
|
||||
contract.
|
||||
|
||||
`find` submits a live authenticated RFQ. It does not reserve capacity. ECC
|
||||
exposes no quote lock, purchase, workload, node-evaluation, or inference path,
|
||||
and it never replaces a missing client or failed live call with a local result.
|
||||
|
||||
Official references:
|
||||
- [Claude Code LLM gateway docs](https://docs.anthropic.com/en/docs/claude-code/llm-gateway)
|
||||
@@ -1542,7 +1568,7 @@ The configuration is automatically detected from `.opencode/opencode.json`.
|
||||
|---------|---------------------|----------|--------|
|
||||
| Agents | PASS: 67 agents | PASS: 12 agents | **Claude Code leads** |
|
||||
| Commands | PASS: 94 commands | PASS: 35 commands | **Claude Code leads** |
|
||||
| Skills | PASS: 278 skills | PASS: 37 skills | **Claude Code leads** |
|
||||
| Skills | PASS: 279 skills | PASS: 37 skills | **Claude Code leads** |
|
||||
| Hooks | PASS: 8 event types | PASS: 11 events | **OpenCode has more!** |
|
||||
| Rules | PASS: 29 rules | PASS: 13 instructions | **Claude Code leads** |
|
||||
| MCP Servers | PASS: 14 servers | PASS: Full | **Full parity** |
|
||||
@@ -1703,7 +1729,7 @@ ECC is the **first plugin to maximize every major AI coding tool**. Here's how e
|
||||
|---------|-----------------------|------------|-----------|----------|----------------|
|
||||
| **Agents** | 67 | Shared (AGENTS.md) | Shared (AGENTS.md) | 12 | N/A |
|
||||
| **Commands** | 94 | Shared | Instruction-based | 35 | 5 prompts |
|
||||
| **Skills** | 278 | Shared | 10 (native format) | 37 | Via instructions |
|
||||
| **Skills** | 279 | Shared | 10 (native format) | 37 | Via instructions |
|
||||
| **Hook Events** | 8 types | 15 types | None yet | 11 types | None |
|
||||
| **Hook Scripts** | 20+ scripts | 16 scripts (DRY adapter) | N/A | Plugin hooks | N/A |
|
||||
| **Rules** | 34 (common + lang) | 34 (YAML frontmatter) | Instruction-based | 13 instructions | 1 always-on file |
|
||||
|
||||
+1
-1
@@ -164,7 +164,7 @@ Copy-Item -Recurse rules/typescript "$HOME/.claude/rules/"
|
||||
/plugin list ecc@ecc
|
||||
```
|
||||
|
||||
**完成!** 你现在可以使用 67 个代理、278 个技能和 94 个命令。
|
||||
**完成!** 你现在可以使用 67 个代理、279 个技能和 94 个命令。
|
||||
|
||||
### multi-* 命令需要额外配置
|
||||
|
||||
|
||||
+2
-1
@@ -14,10 +14,11 @@ Thank you to everyone funding ECC's open-source work. Your sponsorship is what l
|
||||
| [**Greptile**](https://www.greptile.com/go/ecc) | <img src="assets/images/sponsors/greptile.png" width="60" alt="Greptile logo" /> | 2026 |
|
||||
| [**Atlas Cloud**](https://www.atlascloud.ai/?utm_source=github&utm_medium=link&utm_campaign=ECC) | <img src="assets/images/sponsors/atlascloud.png" width="60" alt="Atlas Cloud logo" /> | 2026 |
|
||||
| [**Itô**](https://compute.itomarkets.com) | <img src="assets/images/sponsors/ito.svg" width="60" alt="Itô Markets logo" /> | 2026 |
|
||||
| [**Moonshot AI**](https://www.moonshot.ai/) | <img src="assets/images/sponsors/moonshot.svg" width="60" alt="Moonshot AI Kimi logo" /> | 2026 |
|
||||
|
||||
*[Become a Business sponsor](https://github.com/sponsors/affaan-m) to get README sponsor placement + SPONSORS.md listing. Current Business tier is $500/mo. No seats, SLA, custom development, or preferential technical placement is bundled unless separately agreed.*
|
||||
|
||||
Run or self-host any open-source model. Itô is ECC's preferred compute sponsor, while ECC remains provider-agnostic and any GPU provider works. ECC only links to the [Itô dashboard](https://compute.itomarkets.com) for sign-in and GPU rental or management; it does not provision compute or serving. Managed inference through Itô is not live yet.
|
||||
Run or self-host any open-source model. Itô is ECC's preferred compute sponsor, while ECC remains provider-agnostic and any GPU provider works. The [Itô dashboard](https://compute.itomarkets.com) sponsorship link is passive: it does not invoke an RFQ, reserve capacity, provision compute, or configure serving. Separately, the opt-in `ecc ito find` bridge invokes the explicitly configured canonical Itô CLI and submits a live authenticated RFQ; it does not reserve capacity. Managed inference through Itô is not live yet.
|
||||
|
||||
## Team Sponsors — $200/mo
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg width="180" height="180" viewBox="0 0 180 180" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="180" height="180" rx="45" fill="white"/>
|
||||
<path d="M139.13 36.5135C144.237 36.5135 148.377 40.6534 148.377 45.7601C148.377 50.8669 144.237 55.0067 139.13 55.0067L130.971 55.0067C130.371 55.0067 129.884 54.5197 129.884 53.9189L129.884 45.7601C129.884 40.6534 134.023 36.5135 139.13 36.5135Z" fill="#1783FF"/>
|
||||
<path d="M87.2906 90.3588L122.186 55.7385C122.842 55.0859 122.473 53.7739 121.625 53.7739H102.849C102.645 53.7739 102.447 53.8572 102.288 54.0168L64.6899 91.3099C64.1035 91.8861 63.2367 91.3724 63.2367 90.4491V54.8777C63.2367 54.2668 62.8352 53.7739 62.3444 53.7739H49.406C48.9153 53.7739 48.5137 54.2668 48.5137 54.8777V131.574C48.5137 132.185 48.9153 132.678 49.406 132.678H62.3444C62.8352 132.678 63.2367 132.185 63.2367 131.574V115.947C63.2367 115.614 63.3578 115.295 63.5681 115.087L75.2254 103.521C75.5058 103.243 75.8946 103.202 76.2069 103.41L107.387 126.354C112.492 129.79 118.196 131.9 123.99 132.525C124.506 132.581 124.952 132.067 124.952 131.421V116.704C124.952 116.142 124.614 115.684 124.162 115.614C120.752 115.08 117.425 113.761 114.417 111.734L87.4244 92.1915C86.8636 91.8167 86.7935 90.8517 87.2906 90.3588Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -2,7 +2,7 @@
|
||||
|
||||
[Atlas Cloud](https://www.atlascloud.ai/?utm_source=github&utm_medium=link&utm_campaign=everything-claude-code) is a full-modal AI inference platform providing an OpenAI-compatible API for 59+ LLM models, image generation, and video generation.
|
||||
|
||||
> Run or self-host any open-source model instead of using a managed API. Itô is ECC's preferred compute sponsor: [open the Itô dashboard to sign in and rent or manage GPUs](https://compute.itomarkets.com). Any GPU provider works. ECC only provides this link; it does not provision compute or serving. Managed inference through Itô is not live yet.
|
||||
> Run or self-host any open-source model instead of using a managed API. Itô is ECC's preferred compute sponsor: [open the Itô dashboard to sign in and rent or manage GPUs](https://compute.itomarkets.com). Any GPU provider works. That sponsorship link is passive: it does not invoke an RFQ, reserve capacity, provision compute, or configure serving. Separately, the opt-in `ecc ito find` bridge invokes the explicitly configured canonical Itô CLI and submits a live authenticated RFQ; it does not reserve capacity. Managed inference through Itô is not live yet.
|
||||
|
||||
## Configuration
|
||||
|
||||
|
||||
@@ -1,586 +1,127 @@
|
||||
# ECC × Itô Compute Integration
|
||||
|
||||
Status: **Proposed — requires Affaan approval before Phase 2 implementation**
|
||||
Status: **Implemented local CLI bridge; managed inference remains unavailable**
|
||||
|
||||
Owner: Affaan Mustafa
|
||||
|
||||
Prepared: 2026-07-21
|
||||
|
||||
Phase 1 branch: agent/ito-sponsor-compute
|
||||
|
||||
## Decision gate
|
||||
|
||||
This document is the approval artifact for Phase 2. Approval authorizes only
|
||||
delivery slices 1 and 2: the five skills and the fail-closed CLI/MCP stub. It
|
||||
does not authorize or claim a working Itô inference service, live rental API,
|
||||
OAuth integration, billing flow, or rental mutation.
|
||||
|
||||
No Phase 2 skill, CLI, MCP, OAuth, rental-management, or serving code should be
|
||||
built until Affaan approves the decisions at the end of this document.
|
||||
|
||||
### Narrow sandbox handoff authorized on 2026-07-23
|
||||
|
||||
Affaan separately authorized one smaller CLI slice:
|
||||
|
||||
ecc ito rent --accelerator h100 --count 1 --hours 24
|
||||
|
||||
That command is implemented as `ito.compute.handoff.v1`. It validates an
|
||||
explicit H100 intent, records `ecc-cli` provenance, fixes the authority ceiling
|
||||
at read-only sandbox mode, and opens only the `/desk` page, where sign-in may be
|
||||
required. `--dry-run` emits the identical structured handoff without opening a
|
||||
browser.
|
||||
|
||||
The current Itô desk does not expose a supported structured ECC deep link or a
|
||||
non-mutating external-intake endpoint. The CLI therefore returns
|
||||
`transport: manual_copy` and `acceptedByIto: false`; it does not pretend that
|
||||
opening `/desk` delivered the intent. A human may copy the bounded message into
|
||||
the conversational desk. ECC never reads credentials, files an RFQ, requests
|
||||
or accepts a quote, calls procurement, approves funds, creates an order, or
|
||||
contacts a counterparty. The user must stop before `Pay & buy`.
|
||||
|
||||
This narrow authorization does not approve the five skills, MCP, OAuth, rental
|
||||
management, inference serving, deployment, publication, or any live economic
|
||||
mutation described later in this document.
|
||||
Updated: 2026-07-23
|
||||
|
||||
## Thesis
|
||||
|
||||
The distribution chain is:
|
||||
The distribution chain remains provider-neutral:
|
||||
|
||||
GPU compute (Itô)
|
||||
GPU compute (Itô or another selected provider)
|
||||
-> any open-source model
|
||||
-> model harness
|
||||
-> ECC meta-harness
|
||||
|
||||
Itô is ECC's preferred compute sponsor. It is never an exclusive provider.
|
||||
ECC remains open source and all workflows must accept owned hardware, existing
|
||||
clusters, and other compute providers.
|
||||
|
||||
## Terms and non-negotiable boundaries
|
||||
|
||||
- **Self-hosting** means the user operates a model runtime on owned or rented
|
||||
compute. ECC does not silently provision or operate that runtime.
|
||||
- **Preferred compute sponsor** means Itô is suggested at the step where a user
|
||||
needs new GPU capacity. Requirements and existing capacity come first.
|
||||
- **Provider-neutral** means users can choose any provider or use hardware they
|
||||
already control without losing workflow functionality.
|
||||
- **Manual handoff** means ECC can route the user to
|
||||
<https://compute.itomarkets.com> for sign-in, rental, and dashboard access.
|
||||
- **Not live** means ECC cannot currently exchange Itô OAuth tokens, fetch live
|
||||
inventory or pricing, create or manage rentals, or return an inference
|
||||
endpoint.
|
||||
- Itô compute authentication must not reuse the prediction-market ITO_API_KEY.
|
||||
- Phase 2 must not add an Itô LLM provider or advertise an Itô-compatible model
|
||||
endpoint. Itô is the compute layer, not an inference API.
|
||||
|
||||
## Sequencing
|
||||
|
||||
### Phase 1: launch-ready sponsor and compute routing
|
||||
|
||||
Phase 1 is the smallest shippable slice and is prepared before Phase 2:
|
||||
|
||||
| Surface | Launch-ready change |
|
||||
|---|---|
|
||||
| ECC README and sponsor roster | Itô logo beside current business sponsors; preferred-compute and provider-neutral disclosure |
|
||||
| ecc-universal npm surface | README placement, packaged sponsor assets, and install welcome copy |
|
||||
| ECC installer | Human help and install-plan footer route self-host intent to Itô; JSON remains machine-pure |
|
||||
| ECC CLI | Top-level help shows the same shared compute disclosure |
|
||||
| Harness-specific endpoint/model docs | Bring-your-own endpoint/model notes route GPU needs to Itô without claiming provisioning |
|
||||
| Local-model selector | Ollama selection shows a passive compute-rental/dashboard notice; no Itô provider adapter |
|
||||
| ecc.tools | Sponsor card, sponsor proof chip, and explicit no-serving boundary |
|
||||
| AgentShield / ecc-agentshield | Sponsor callout in the GitHub and npm README; no ads in security reports |
|
||||
|
||||
Launch coordination still matters:
|
||||
|
||||
- Merge the public PRs when their required checks and reviews pass. Coordinate
|
||||
npm publication and the verified ecc.tools deployment as explicit release
|
||||
steps; do not tie the generic OSS-compute integration to an unpublished model
|
||||
or model-provider announcement.
|
||||
- npm READMEs update only when new versions are published. Merging source changes
|
||||
alone does not update the already-published ecc-universal or ecc-agentshield
|
||||
package pages.
|
||||
- The release owner must select unused package versions in the launch commit,
|
||||
update every synchronized version surface, prove that neither version exists
|
||||
in the npm registry, publish both packages, and read back the rendered package
|
||||
pages. The sponsor PRs do not silently republish existing versions.
|
||||
- ecc.tools requires its normal verified Cloudflare deployment after merge.
|
||||
|
||||
### Phase 2: build only after approval
|
||||
|
||||
Phase 2 adds provider-neutral operational skills and an honest Itô control-plane
|
||||
stub. Real OAuth, rentals, and serving remain separately gated on backend
|
||||
contracts.
|
||||
|
||||
## Channel A: self-host an open model
|
||||
|
||||
### Skill 1: self-host-a-model
|
||||
|
||||
Path:
|
||||
|
||||
skills/self-host-a-model/SKILL.md
|
||||
|
||||
Activate when a user asks to self-host, locally host, or deploy an open model;
|
||||
mentions Ollama, vLLM, SGLang, TGI, an OpenAI-compatible endpoint, Kimi, GLM,
|
||||
Llama, Mistral, quantization, GPU sizing, or moving away from a managed API.
|
||||
|
||||
Workflow shape:
|
||||
|
||||
1. Identify the model artifact, license, trust boundary, and required context.
|
||||
2. Estimate VRAM from weights, precision or quantization, KV cache, concurrency,
|
||||
and runtime overhead.
|
||||
3. Prefer existing owned or already-rented capacity when it satisfies the
|
||||
requirement.
|
||||
4. If capacity is missing, compare provider requirements and disclose Itô as
|
||||
ECC's preferred compute sponsor. Authenticate only if the user selects Itô.
|
||||
5. Select a user-controlled runtime, container, storage, network, auth, and TLS
|
||||
plan.
|
||||
6. Produce endpoint smoke tests and harness configuration steps.
|
||||
7. Verify model identity, response schema, latency, health, and shutdown.
|
||||
|
||||
Required output: SelfHostPlan
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| computeOwner | owned, existing cluster, Itô, or another selected provider |
|
||||
| modelArtifact | immutable model and revision |
|
||||
| runtime | selected serving engine and version |
|
||||
| resourceEnvelope | GPU type/count, VRAM, CPU, RAM, disk, and network |
|
||||
| endpointContract | expected protocol and auth, never a fabricated endpoint |
|
||||
| deploymentSteps | provider-neutral execution plan |
|
||||
| verification | health, identity, schema, latency, and teardown checks |
|
||||
| blockers | missing access, capacity, serving, or model facts |
|
||||
Itô is ECC's preferred compute sponsor, never an exclusive provider. Owned
|
||||
hardware, existing clusters, and other providers remain valid.
|
||||
|
||||
Non-goals:
|
||||
|
||||
- Do not claim ECC or Itô created an endpoint.
|
||||
- Do not fabricate Itô inventory, pricing, credentials, or rental identifiers.
|
||||
- Do not force any model family; the skill is model-agnostic.
|
||||
## Implemented boundary
|
||||
|
||||
## Channel B: training and GPU operations
|
||||
ECC delegates to the canonical Itô package in
|
||||
`Ito-Markets/ito-cloud-runtime/cli/ito-compute-cli`. ECC does not maintain a
|
||||
second API client or response schema.
|
||||
|
||||
### Skill 2: training-run-operations
|
||||
|
||||
Path:
|
||||
|
||||
skills/training-run-operations/SKILL.md
|
||||
The wrapper exposes only the canonical CLI's `auth`, `find`, and `status`
|
||||
operations:
|
||||
|
||||
Activate for launching, resuming, debugging, observing, or cost-planning a
|
||||
training, fine-tuning, evaluation, retraining, or MLE run.
|
||||
ecc ito auth
|
||||
ecc ito find <all required RFQ constraints>
|
||||
ecc ito status
|
||||
|
||||
When installed, cross-link mle-workflow for the production lifecycle,
|
||||
pytorch-patterns for framework details, and eval-harness for promotion criteria.
|
||||
The new skill must still be usable on Kimi without mle-workflow or
|
||||
pytorch-patterns because their current install modules do not support Kimi. Keep
|
||||
the standalone contract minimal instead of copying those skills wholesale.
|
||||
The canonical MCP server exposes only `ito_auth`, `ito_find`, and `ito_status`.
|
||||
ECC includes an opt-in configuration template pointing to the local built MCP
|
||||
entry. It does not enable the server by default.
|
||||
|
||||
Required output: TrainingRunPlan containing an immutable code revision, dataset
|
||||
snapshot, environment or image, entry point, resources, artifact paths,
|
||||
checkpoint and resume policy, metrics, observation plan, budget, retry policy,
|
||||
and promotion gate.
|
||||
The former browser/manual-copy command is retired. `ecc ito` performs no
|
||||
browser navigation and stores no economic state.
|
||||
|
||||
Workflow:
|
||||
## Local install
|
||||
|
||||
1. Run a local or minimal-capacity smoke test.
|
||||
2. Size the full run and identify existing capacity.
|
||||
3. Acquire new capacity only when needed; suggest Itô while permitting any
|
||||
provider.
|
||||
4. Route scheduler-specific work to the Slurm or Kubernetes GPU skill.
|
||||
5. Submit, observe, checkpoint, resume, evaluate, and explicitly promote.
|
||||
`ito-compute-cli` is unpublished. Install it from the canonical repository:
|
||||
|
||||
### Skill 3: gpu-workload-splitting
|
||||
git clone https://github.com/Ito-Markets/ito-cloud-runtime.git
|
||||
cd ito-cloud-runtime/cli/ito-compute-cli
|
||||
npm ci
|
||||
npm run check
|
||||
|
||||
Path:
|
||||
Set `ECC_ITO_CLI_EXECUTABLE` to the explicit absolute built entry:
|
||||
|
||||
skills/gpu-workload-splitting/SKILL.md
|
||||
/absolute/path/to/ito-cloud-runtime/cli/ito-compute-cli/dist/bin/ito.js
|
||||
|
||||
Activate when a user asks to split a model, dataset, batch job, sweep, or
|
||||
training run across GPUs or nodes; reports poor scaling, stragglers, or
|
||||
out-of-memory failures; or needs a workload-splitting layer.
|
||||
ECC does not resolve the credential-bearing client through `PATH`; this avoids
|
||||
forwarding `ITO_API_KEY` to an unrelated executable with the same name.
|
||||
|
||||
The skill must choose deliberately among data, tensor, pipeline, model, context,
|
||||
or expert parallelism; independent shards; or job arrays. It must measure VRAM,
|
||||
communication-to-compute ratio, topology, data locality, and heterogeneous
|
||||
capacity before choosing.
|
||||
For MCP, configure `node` with:
|
||||
|
||||
Required output: WorkloadSplitPlan
|
||||
/absolute/path/to/ito-cloud-runtime/cli/ito-compute-cli/dist/bin/ito-mcp.js
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| tasks | deterministic units of work |
|
||||
| resources | CPU, RAM, accelerator, storage, and network per task |
|
||||
| dependsOn | dependency DAG |
|
||||
| shard | deterministic partition and ownership rule |
|
||||
| placement | node, GPU, topology, and locality constraints |
|
||||
| checkpoint | boundaries and resume behavior |
|
||||
| merge | aggregation or reduction contract |
|
||||
| failurePolicy | retry, idempotency, straggler, and partial-failure rules |
|
||||
Inject `ITO_API_KEY` with 1Password or the launching environment. ECC forwards
|
||||
only `ITO_API_KEY`, optional Itô endpoint overrides, and the minimum process
|
||||
environment. It does not inspect or log the key.
|
||||
|
||||
Itô appears only at the capacity-acquisition step. Validate this output shape
|
||||
with the LinkedIn contact who requested a workload-splitting layer before calling
|
||||
Channel B customer-validated.
|
||||
## Authority and economics
|
||||
|
||||
### Skill 4: slurm-gpu-workloads
|
||||
- `auth` validates the configured Itô API key.
|
||||
- `find` reads live inventory and submits a live authenticated RFQ. An operator
|
||||
or agent must gather every hard topology/economic constraint and obtain
|
||||
explicit buyer authority before invoking it.
|
||||
- `status` reads current RFQ and procurement status.
|
||||
- ECC returns the canonical process's stdout, stderr, and exit code unchanged.
|
||||
- An inventory row or RFQ is not a capacity reservation.
|
||||
- Only a non-null canonical firm quote is firm.
|
||||
- After an ambiguous transport error, check `status` before repeating `find`.
|
||||
- Global ECC dry-run does not create a local success result; the wrapper fails
|
||||
closed without invoking the canonical CLI.
|
||||
|
||||
Path:
|
||||
All durable RFQ, quote, procurement, and reservation state remains owned by the
|
||||
Itô platform. ECC adds no shadow store.
|
||||
|
||||
skills/slurm-gpu-workloads/SKILL.md
|
||||
## Unsupported in this slice
|
||||
|
||||
Activate for sbatch, srun, salloc, GPU GRES or TRES, pending jobs, arrays,
|
||||
DDP/NCCL, queue time, low utilization, requeue, or Slurm GPU optimization.
|
||||
ECC exposes no quote lock, purchase, workload execution, node qualification,
|
||||
or inference command. The canonical package contains a separately gated node
|
||||
qualification adapter, but this ECC bridge intentionally does not expose it.
|
||||
|
||||
Workflow:
|
||||
Managed inference remains unavailable. ECC does not claim that Itô created a
|
||||
model endpoint, deployed a workload, reserved capacity, or moved funds.
|
||||
|
||||
- Inspect cluster, partition, QOS, account, node, and GPU facts read-only first.
|
||||
- Map nodes, tasks, processes, and GPUs explicitly.
|
||||
- Cover staging, checkpoint signals, requeue, arrays, logs, topology, and scaling
|
||||
diagnostics.
|
||||
- Produce an sbatch plan or template plus validation commands.
|
||||
- Never make scheduler-admin or cluster-wide changes without explicit authority.
|
||||
- Use an existing cluster unchanged when possible; suggest Itô only when new
|
||||
capacity is requested.
|
||||
## Skill and install shape
|
||||
|
||||
### Skill 5: kubernetes-gpu-workloads
|
||||
`skills/ito-compute/SKILL.md` is an opt-in workflow installed through:
|
||||
|
||||
Path:
|
||||
- module: `ito-compute`
|
||||
- component: `capability:ito-compute`
|
||||
- profile: `full`
|
||||
|
||||
skills/kubernetes-gpu-workloads/SKILL.md
|
||||
The skill documents the exact CLI and MCP names and the approval boundary. It
|
||||
does not bundle the unpublished CLI.
|
||||
|
||||
Activate for GPU Jobs or pods, nvidia.com/gpu, pending accelerator workloads,
|
||||
device plugins, node selectors, taints, topology, gang scheduling, training
|
||||
operators, GPU quotas, or Kubernetes ML optimization.
|
||||
## Publication blocker
|
||||
|
||||
When available, cross-link the existing kubernetes-patterns skill rather than
|
||||
copying it. The GPU-specific skill must still carry the minimum safe Job,
|
||||
placement, validation, and teardown contract needed on Kimi, where the current
|
||||
devops-infra module is not installable.
|
||||
|
||||
Workflow:
|
||||
The integration works from a local build. Distribution remains blocked until
|
||||
`ito-compute-cli` has an approved package-publication policy and is published
|
||||
or replaced by another verified distribution channel. ECC must not claim npm
|
||||
availability before a registry read confirms it.
|
||||
|
||||
- Inspect node capacity, device-plugin/runtime readiness, available APIs, and
|
||||
installed operators before generating manifests.
|
||||
- Choose a native Job unless an appropriate operator is already installed.
|
||||
- Never invent a custom resource definition.
|
||||
- Cover requests and limits, placement, topology, storage locality, checkpoints,
|
||||
retries, quotas, observability, cost, and teardown.
|
||||
- Produce manifests plus client and server dry-run checks.
|
||||
|
||||
## Shared provider rule for all five skills
|
||||
|
||||
Every skill must apply this order:
|
||||
|
||||
1. Capture workload requirements.
|
||||
2. Reuse owned or existing compute when it fits.
|
||||
3. If capacity is missing, present provider-neutral criteria.
|
||||
4. Disclose Itô as ECC's preferred compute sponsor.
|
||||
5. Allow another provider without degrading the workflow.
|
||||
6. Trigger Itô authentication only after the user selects Itô.
|
||||
7. Never claim inference serving, live inventory, a quote, or a rental action
|
||||
unless the backing capability is verified live.
|
||||
|
||||
No legacy commands should be added. skills/ remains the canonical workflow
|
||||
surface.
|
||||
|
||||
## Install and package shape
|
||||
|
||||
Add a non-default gpu-compute module in manifests/install-modules.json:
|
||||
|
||||
- Paths: the five skill directories above.
|
||||
- Supported targets: all current targets, including kimi.
|
||||
- Dependencies: platform-configs only. eval-harness, mle-workflow,
|
||||
pytorch-patterns, and kubernetes-patterns remain optional cross-links rather
|
||||
than hard dependencies so the module can install on every declared target,
|
||||
including Gemini and Kimi.
|
||||
- Default install: false.
|
||||
- Stability: beta.
|
||||
- Cost: medium.
|
||||
|
||||
Add capability:gpu-compute to manifests/install-components.json and add the
|
||||
module to the full install profile. Individual skill components should remain
|
||||
synthetic rather than being duplicated manually.
|
||||
|
||||
Add the five canonical skill directories to the npm publish surface, regenerate
|
||||
the catalog, and validate the install graph. Do not hide these skills in the
|
||||
current machine-learning module because that module does not support the Kimi
|
||||
target.
|
||||
|
||||
## ito CLI and MCP v0
|
||||
|
||||
### Placement
|
||||
|
||||
Keep the initial stub inside ecc-universal:
|
||||
|
||||
scripts/ito.js
|
||||
scripts/ito-mcp.js
|
||||
scripts/lib/ito/contracts.js
|
||||
scripts/lib/ito/capabilities.js
|
||||
scripts/lib/ito/auth.js
|
||||
scripts/lib/ito/client.js
|
||||
scripts/lib/ito/mcp.js
|
||||
|
||||
Expose ecc ito as canonical and an ASCII ito bin alias. Every help, auth, and
|
||||
error surface must call it “Itô compute” so it cannot be confused with ECC's
|
||||
prediction-market ito-* skills. Prose and brand UI use Itô. Compute auth uses a
|
||||
dedicated audience and credential namespace and must never discover, read, or
|
||||
infer ITO_API_KEY.
|
||||
|
||||
### CLI commands
|
||||
|
||||
ito capabilities [--json]
|
||||
ito dashboard --intent self-host|training [--no-open]
|
||||
ito auth status [--json]
|
||||
ito auth login --intent self-host|training [--no-open] [--json]
|
||||
ito rent plan --intent ... --accelerator ... --count ... --memory-gib ... --hours ... [--json]
|
||||
ito rent create --plan ... [--json]
|
||||
ito rentals list [--json]
|
||||
ito rentals get <id> [--json]
|
||||
ito rentals stop <id> [--json]
|
||||
ito mcp
|
||||
|
||||
### MCP tools
|
||||
|
||||
compute_capabilities
|
||||
dashboard_handoff
|
||||
auth_status
|
||||
auth_login
|
||||
rent_plan
|
||||
rent_create
|
||||
rentals_list
|
||||
rental_get
|
||||
rental_stop
|
||||
|
||||
Except for the ito mcp transport command, every CLI operation has an equivalent
|
||||
MCP tool backed by the same service method. dashboard_handoff is the MCP peer of
|
||||
ito dashboard. MCP handoff tools return a URL and never open a browser; only a
|
||||
direct local CLI invocation may open one, and --no-open must remain available.
|
||||
Every command emitted or invoked by a skill, agent, or generated artifact must
|
||||
pass --no-open; automatic browser opening is reserved for a human typing the
|
||||
CLI command directly.
|
||||
|
||||
All tools and commands return the same versioned response envelope. A supported
|
||||
manual handoff looks like:
|
||||
|
||||
{
|
||||
"schemaVersion": "ito.compute.v0",
|
||||
"success": true,
|
||||
"state": "manual_handoff",
|
||||
"data": {
|
||||
"authenticated": false
|
||||
},
|
||||
"error": null,
|
||||
"links": {
|
||||
"dashboard": "https://compute.itomarkets.com"
|
||||
}
|
||||
}
|
||||
|
||||
An unavailable capability must instead use:
|
||||
|
||||
{
|
||||
"schemaVersion": "ito.compute.v0",
|
||||
"success": false,
|
||||
"state": "unavailable",
|
||||
"data": null,
|
||||
"error": {
|
||||
"code": "CAPABILITY_NOT_AVAILABLE",
|
||||
"message": "This operation requires an approved live Itô compute API."
|
||||
},
|
||||
"links": {
|
||||
"dashboard": "https://compute.itomarkets.com"
|
||||
}
|
||||
}
|
||||
|
||||
Envelope invariants:
|
||||
|
||||
- unavailable always means success: false, non-null typed error, and no
|
||||
action-like data.
|
||||
- The CLI exits nonzero for unavailable or validation failures.
|
||||
- MCP returns the same envelope in an error tool result; it must not translate
|
||||
failure into a successful-looking action.
|
||||
- manual_handoff means the routing behavior worked. It does not mean inventory,
|
||||
OAuth, rental management, or inference is available.
|
||||
|
||||
### Honest stub behavior
|
||||
|
||||
| Capability | Phase 2 stub value |
|
||||
|---|---|
|
||||
| dashboardHandoff | true |
|
||||
| oauthTokenExchange | false |
|
||||
| rentRequestDraft | true |
|
||||
| rentMutation | false |
|
||||
| rentalManagement | false |
|
||||
| inferenceServing | false |
|
||||
|
||||
- capabilities reports the table above.
|
||||
- dashboard opens or returns the approved compute URL.
|
||||
- auth status reports authenticated: false and oauthTokenExchange: false. It
|
||||
must not inspect ITO_API_KEY or imply that dashboard cookies are CLI auth.
|
||||
- auth login opens or returns the dashboard URL and reports manual action
|
||||
required. MCP returns the URL without opening it. Neither path may say OAuth
|
||||
succeeded.
|
||||
- rent plan validates and normalizes requirements, then returns manual_handoff.
|
||||
It must not fabricate inventory, price, quote, or plan ID.
|
||||
- rent create, rental reads, and stop fail closed with
|
||||
CAPABILITY_NOT_AVAILABLE until backed by live APIs.
|
||||
- Future paid creation and rental stop remain hard-disabled until a trusted
|
||||
consent channel exists. A model-supplied boolean, --confirm flag, or tool
|
||||
argument is not proof of user consent. Live mutations require either
|
||||
host-mediated user elicitation or a single-use capability issued outside the
|
||||
model and bound to the account, exact action and resource, immutable quote or
|
||||
resource ID, maximum cost, expiry, and idempotency key.
|
||||
|
||||
### MCP distribution
|
||||
|
||||
Add Itô only as an opt-in entry in mcp-configs/mcp-servers.json:
|
||||
|
||||
"ito": {
|
||||
"command": "ito",
|
||||
"args": ["mcp"],
|
||||
"description": "Opt-in Itô compute rental and management interface. Manual dashboard handoff only until live control-plane APIs are enabled; does not provide inference serving."
|
||||
}
|
||||
|
||||
Do not add it to the default .mcp.json or the Claude plugin manifest. ECC's MCP
|
||||
policy permits one universal default connector; this integration is intentional
|
||||
and task-scoped.
|
||||
|
||||
## OAuth-on-intent contract
|
||||
|
||||
The authentication trigger is a user decision, not installation:
|
||||
|
||||
self-host or training intent
|
||||
-> capacity needed
|
||||
-> user selects Itô
|
||||
-> auth status
|
||||
-> login handoff or future OAuth
|
||||
|
||||
Until the backend contract exists, login remains a manual dashboard handoff.
|
||||
|
||||
When live OAuth becomes available, require:
|
||||
|
||||
- A public native client using Authorization Code with PKCE S256 and no packaged
|
||||
client secret, or an explicitly approved phishing-resistant device flow.
|
||||
- State and nonce validation plus issuer, audience, and redirect validation.
|
||||
- A loopback callback bound only to localhost with one-time state and a short
|
||||
timeout, or the approved device-flow equivalent.
|
||||
- Fixed redirect origins and least-privilege scopes.
|
||||
- OS credential storage under an ecc.ito.compute-specific service/account
|
||||
namespace, never repository files, .env files, MCP config, CLI arguments,
|
||||
child-process environments, or ITO_API_KEY.
|
||||
- Raw access and refresh tokens must never enter model context, MCP results,
|
||||
stdout, stderr, telemetry, crash reports, or logs. Account and billing data is
|
||||
redacted by default.
|
||||
- Refresh and revocation behavior.
|
||||
- Trusted account and cost consent before paid actions as defined in the
|
||||
mutation-capability contract above.
|
||||
|
||||
## Input and generated-artifact safety
|
||||
|
||||
- Define JSON Schemas for intents, accelerator names, counts, memory, duration,
|
||||
identifiers, plans, and every MCP input. Enforce enums and numeric ranges,
|
||||
bound string and collection lengths, and reject control characters or
|
||||
newlines in IDs and scheduler fields.
|
||||
- Build subprocess calls with executable-plus-argv arrays. Never concatenate
|
||||
inputs into a shell command, use shell: true, eval generated text, or interpolate
|
||||
untrusted values into Slurm directives.
|
||||
- Validate Slurm partitions, accounts, QOS, GRES/TRES, paths, and job names
|
||||
before rendering. Validate Kubernetes resource names, API kinds, namespaces,
|
||||
images, pull policy, resources, selectors, tolerations, volumes, and command
|
||||
arrays against explicit schemas.
|
||||
- Pin model, container, code, and dataset revisions in executable plans.
|
||||
- Render artifacts by default. Submission or execution is a separate step that
|
||||
requires explicit user authority and must preserve client/server dry runs.
|
||||
- Never place kubeconfig, SSH keys, registry credentials, scheduler tokens, or
|
||||
provider secrets in generated artifacts or model-visible output.
|
||||
|
||||
## Pre-stageable versus blocked
|
||||
|
||||
| Pre-stageable after approval | Blocked on Itô or serving infrastructure |
|
||||
|---|---|
|
||||
| Five provider-neutral skills | OAuth issuer and client registration |
|
||||
| Resource sizing and workload plans | Authorization, token, refresh, and revocation endpoints |
|
||||
| Slurm and Kubernetes artifacts for user-provided clusters | Live accelerator inventory and availability |
|
||||
| Static dashboard handoff | Live pricing, quotes, billing, and idempotency |
|
||||
| CLI/MCP schemas and capability reporting | Rental create, list, get, stop APIs and lifecycle states |
|
||||
| Manual sign-in and rental handoff | SSH, kubeconfig, Slurm, or other access delivery |
|
||||
| Fail-closed unavailable responses | Model upload and deployment |
|
||||
| Mocked contract tests | Endpoint creation, health, autoscaling, and inference serving |
|
||||
|
||||
Inference serving is a separate future phase. It must not be unlocked merely by
|
||||
finishing this Phase 2 stub.
|
||||
|
||||
## Test plan
|
||||
|
||||
Add:
|
||||
|
||||
- tests/ci/ito-compute-skills.test.js for exact skills, triggers,
|
||||
provider-neutral language, sponsor disclosure, and the no-serving boundary.
|
||||
- tests/lib/ito-contracts.test.js for validation, immutable envelopes, capability
|
||||
states, URL allowlisting, injection-resistant schemas, and redaction.
|
||||
- tests/scripts/ito.test.js for help, JSON, no-browser handoff, invalid input,
|
||||
unavailable mutations, nonzero exit parity, and proof that ITO_API_KEY is
|
||||
ignored.
|
||||
- tests/scripts/ito-mcp.test.js for stdio initialization, tool schemas,
|
||||
CLI/tool parity, error-result parity, no-browser handoff, and secret-free
|
||||
results.
|
||||
- tests/integration/ito-compute-e2e.test.js for ecc ito to manual handoff and MCP
|
||||
calls without unapproved network or browser side effects.
|
||||
|
||||
Extend the ECC CLI, install-manifest, npm-publish-surface, and plugin-manifest
|
||||
tests as required.
|
||||
|
||||
Required gates:
|
||||
|
||||
node scripts/ci/validate-skills.js --strict
|
||||
node scripts/ci/validate-install-manifests.js
|
||||
npm run catalog:check
|
||||
npm test
|
||||
npm run coverage
|
||||
npm run lint
|
||||
npm pack --dry-run --json
|
||||
npm run security:ioc-scan
|
||||
|
||||
Manual acceptance:
|
||||
|
||||
- Existing hardware skips provider selection.
|
||||
- An alternate provider path never invokes Itô authentication.
|
||||
- Selecting Itô returns only truthful supported capabilities.
|
||||
- Rental mutations fail closed until backed by live APIs.
|
||||
- No flow emits an Itô inference endpoint.
|
||||
- The Kimi target installs capability:gpu-compute.
|
||||
- Paid and destructive actions remain unavailable until the trusted consent
|
||||
capability and its separate approval exist.
|
||||
|
||||
## Delivery slices after approval
|
||||
|
||||
1. **Skills and install module:** five skills, provider rule, manifests, catalog,
|
||||
and validation.
|
||||
2. **CLI and opt-in MCP stub:** shared contracts, manual handoff, fail-closed
|
||||
commands/tools, security and parity tests.
|
||||
3. **OAuth and rental control plane:** a separately authorized future phase,
|
||||
only after Itô supplies the live API contract and a threat model, API/contract
|
||||
review, security review, billing review, and Affaan launch approval all pass.
|
||||
4. **Inference serving:** separate plan, security review, economics review, and
|
||||
explicit launch approval.
|
||||
|
||||
Each slice must use its own focused PR and stay mergeable without later slices.
|
||||
|
||||
## Affaan approval checklist
|
||||
|
||||
- [ ] Approve the five skill names and their boundaries.
|
||||
- [ ] Approve separate Slurm and Kubernetes GPU skills.
|
||||
- [ ] Approve capability:gpu-compute with Kimi target support.
|
||||
- [ ] Approve sponsor wording: Itô in prose, ASCII ito for CLI and MCP.
|
||||
- [ ] Approve ecc ito plus the ito bin alias inside ecc-universal.
|
||||
- [ ] Approve an opt-in MCP entry and no default MCP/plugin registration.
|
||||
- [ ] Approve manual-handoff and fail-closed stub semantics.
|
||||
- [ ] Approve the shared response envelope and trusted-consent boundary.
|
||||
- [ ] Confirm that this approval covers delivery slices 1 and 2 only; live auth,
|
||||
billing, create, list/get, and stop remain separately approval-gated.
|
||||
- [ ] Supply or explicitly defer the OAuth and rental API contract.
|
||||
- [ ] Confirm endpoint configuration for every supported harness before
|
||||
publishing an example.
|
||||
- [ ] Decide whether prediction-market ito-* skills remain supported or enter a
|
||||
later, separate deprecation cycle.
|
||||
- [ ] Validate WorkloadSplitPlan with the LinkedIn contact before describing
|
||||
Channel B as customer-validated.
|
||||
|
||||
Approval of this document authorizes delivery slices 1 and 2 only: the skills
|
||||
and fail-closed stub. It does not authorize live auth, billing, rental APIs,
|
||||
mutations, or claims that Itô inference serving is live.
|
||||
The ECC package version remains unchanged in this worktree. Its version bump,
|
||||
release commit, and publication are intentionally deferred to the release owner
|
||||
after review.
|
||||
|
||||
## Verification
|
||||
|
||||
The local contract suite proves:
|
||||
|
||||
- only the three supported operations spawn;
|
||||
- RFQ arguments are forwarded without economic reinterpretation;
|
||||
- only approved Itô runtime variables cross the process boundary;
|
||||
- unsupported and dry-run paths fail before spawn;
|
||||
- a missing or relative executable fails closed with local-install guidance;
|
||||
- canonical output and exit status pass through unchanged;
|
||||
- the skill, install manifests, npm surface, and opt-in MCP template stay
|
||||
aligned.
|
||||
|
||||
No test in this integration invokes a live Itô API, submits an RFQ, opens a
|
||||
browser, or contacts a GPU node.
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
# ECC × Itô Sandbox Handoff Evidence
|
||||
|
||||
Date: 2026-07-23
|
||||
|
||||
Branch: `agent/ecc-ito-sandbox-handoff`
|
||||
|
||||
Base commit: `a3130f9ebfaeed075df5d5b52538acb0ee4bcdf8`
|
||||
|
||||
## Result
|
||||
|
||||
The canonical ECC CLI now supports:
|
||||
|
||||
```text
|
||||
ecc ito rent --accelerator h100 --count 1 --hours 24
|
||||
```
|
||||
|
||||
The command emits an `ito.compute.handoff.v1` envelope containing the exact
|
||||
accelerator, count, and duration, `ecc-cli` provenance, and a read-only sandbox
|
||||
authority ceiling. It opens only `https://compute.itomarkets.com/desk`.
|
||||
|
||||
No supported Itô deep link or non-mutating structured external-intake endpoint
|
||||
exists yet. The contract therefore reports `transport: manual_copy`,
|
||||
`acceptedByIto: false`, and `signInMayBeRequired: true`. It never claims that
|
||||
opening the page delivered the intent.
|
||||
|
||||
The CLI does not read credentials, call the network, file an RFQ, request or
|
||||
accept a quote, call procurement, approve funds, create an order, perform
|
||||
outreach, deploy, push, or merge. The human boundary remains before
|
||||
`Pay & buy`.
|
||||
|
||||
## Security boundary
|
||||
|
||||
Both subprocess boundaries use an explicit system-environment allowlist:
|
||||
|
||||
1. `ecc` to the `ito` command.
|
||||
2. `ito` to the OS browser opener.
|
||||
|
||||
The allowlist retains only runtime essentials such as path, home, temporary
|
||||
directory, locale, terminal, and desktop-session variables. ECC dry-run and
|
||||
test controls are passed only to the Itô command where needed. Browser-probe
|
||||
tests inject API-key, service-token, and password sentinels and prove none
|
||||
reach the browser child.
|
||||
|
||||
## Eval evidence
|
||||
|
||||
Focused handoff:
|
||||
|
||||
```text
|
||||
node tests/scripts/ito-handoff.test.js
|
||||
```
|
||||
|
||||
Result: 9 passed, 0 failed.
|
||||
|
||||
Covered scenarios:
|
||||
|
||||
- exact H100, count 1, 24-hour mapping;
|
||||
- provenance and sandbox authority;
|
||||
- global and local dry-run with zero browser invocation;
|
||||
- exact allowlisted browser URL and sanitized child environment;
|
||||
- direct Itô invocation with sanitized browser environment;
|
||||
- missing, duplicate, unsupported, and out-of-range input rejection;
|
||||
- absence of credential or mutating transports;
|
||||
- human-readable approval boundary;
|
||||
- POSIX-safe npm welcome output.
|
||||
|
||||
CLI and package regressions:
|
||||
|
||||
```text
|
||||
node tests/scripts/ecc.test.js
|
||||
node tests/scripts/npm-publish-surface.test.js
|
||||
```
|
||||
|
||||
Results: 21 passed and 2 passed, with 0 failures.
|
||||
|
||||
Full repository suite:
|
||||
|
||||
```text
|
||||
npm test
|
||||
```
|
||||
|
||||
Result: 3,155 passed, 0 failed.
|
||||
|
||||
Static and security gates:
|
||||
|
||||
```text
|
||||
npm run lint
|
||||
npm run security:ioc-scan -- --root .
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Results: all passed; the IOC scan inspected 207 files.
|
||||
|
||||
Packaged-bin execution:
|
||||
|
||||
```text
|
||||
npm pack --pack-destination <temporary-directory>
|
||||
node <unpacked-package>/scripts/ecc.js --dry-run ito rent \
|
||||
--accelerator h100 --count 1 --hours 24 --json
|
||||
```
|
||||
|
||||
Result: the packed `ecc-universal-2.0.0.tgz` included executable `ecc.js` and
|
||||
`ito.js`; the unpacked command returned the exact intent with `dryRun: true`,
|
||||
`opened: false`, and `transport: manual_copy`.
|
||||
|
||||
## Changed surfaces
|
||||
|
||||
- `scripts/ito.js`
|
||||
- `scripts/lib/ito-environment.js`
|
||||
- `scripts/ecc.js`
|
||||
- `package.json`
|
||||
- `tests/scripts/ito-handoff.test.js`
|
||||
- `tests/scripts/npm-publish-surface.test.js`
|
||||
- `docs/design/ecc-ito-compute-integration.md`
|
||||
- this evidence record
|
||||
|
||||
## Remaining limitation
|
||||
|
||||
ECC cannot automatically prefill or deliver this structured intent until Itô
|
||||
publishes a safe, authenticated, non-mutating intake or deep-link contract.
|
||||
Adding such a contract belongs in Itô and must preserve its existing human
|
||||
approval gates. This ECC slice deliberately does not invent another UI,
|
||||
transport, credential, or procurement path.
|
||||
@@ -0,0 +1,95 @@
|
||||
# ECC × Itô Real CLI Bridge — TDD Evidence
|
||||
|
||||
Date: 2026-07-23
|
||||
|
||||
Source plan: requirements were derived from the approved implementation
|
||||
handoff. No external plan file was executed.
|
||||
|
||||
## User journeys
|
||||
|
||||
1. As an ECC operator, I can invoke the canonical local Itô `auth`, `find`, and
|
||||
`status` operations without a duplicate client or browser workflow.
|
||||
2. As a security reviewer, I can prove unsupported operations, missing local
|
||||
installs, and ECC dry-run requests fail before any child process or network
|
||||
operation.
|
||||
3. As an agent-harness user, I can install one truthful skill that names only
|
||||
the real CLI commands and MCP tools.
|
||||
|
||||
## RED evidence
|
||||
|
||||
Before production changes:
|
||||
|
||||
```text
|
||||
node tests/scripts/ito-cli-bridge.test.js
|
||||
Passed: 0
|
||||
Failed: 9
|
||||
|
||||
node tests/ci/ito-compute-skill.test.js
|
||||
Passed: 0
|
||||
Failed: 4
|
||||
```
|
||||
|
||||
The failures were caused by the old browser-only `rent` command and the missing
|
||||
real skill/install/MCP surfaces.
|
||||
|
||||
## GREEN evidence
|
||||
|
||||
```text
|
||||
node tests/scripts/ito-cli-bridge.test.js
|
||||
Passed: 9
|
||||
Failed: 0
|
||||
|
||||
node tests/ci/ito-compute-skill.test.js
|
||||
Passed: 4
|
||||
Failed: 0
|
||||
|
||||
NODE_PATH=<existing-ecc-checkout>/node_modules \
|
||||
node scripts/ci/validate-install-manifests.js
|
||||
Validated 33 install modules, 80 install components, and 7 profiles
|
||||
|
||||
npm test
|
||||
Total Tests: 3159
|
||||
Passed: 3159
|
||||
Failed: 0
|
||||
|
||||
npm run coverage
|
||||
Statements: 89.21%
|
||||
Branches: 79.71%
|
||||
Functions: 93.96%
|
||||
Lines: 89.21%
|
||||
|
||||
npm run security:ioc-scan
|
||||
Supply-chain IOC scan passed
|
||||
```
|
||||
|
||||
The isolated worktree temporarily reused the canonical ECC checkout's existing
|
||||
`node_modules` through an untracked local symlink. The symlink was removed
|
||||
after validation; no dependency installation or source change was made in the
|
||||
canonical checkout.
|
||||
ESLint and Markdown lint also pass for every changed source file. The complete
|
||||
package dry-run contains the wrapper, environment boundary, skill, and MCP
|
||||
configuration.
|
||||
|
||||
## Test specification
|
||||
|
||||
| Guarantee | Test | Type | Result |
|
||||
|---|---|---|---|
|
||||
| Only `auth`, `find`, and `status` spawn | `tests/scripts/ito-cli-bridge.test.js` | end-to-end process contract | PASS |
|
||||
| Full RFQ arguments cross unchanged | `tests/scripts/ito-cli-bridge.test.js` | integration | PASS |
|
||||
| Only required Itô settings cross the child boundary | `tests/scripts/ito-cli-bridge.test.js` | security integration | PASS |
|
||||
| Unsupported and dry-run operations fail before spawn | `tests/scripts/ito-cli-bridge.test.js` | negative end-to-end | PASS |
|
||||
| Missing/relative executables fail with exact local guidance | `tests/scripts/ito-cli-bridge.test.js` | negative end-to-end | PASS |
|
||||
| Child output and exit code are preserved | `tests/scripts/ito-cli-bridge.test.js` | end-to-end process contract | PASS |
|
||||
| Skill, package, manifests, and MCP template agree | `tests/ci/ito-compute-skill.test.js` | repository contract | PASS |
|
||||
|
||||
## Known gaps
|
||||
|
||||
- No live Itô API, RFQ, browser, GPU node, or paid operation was invoked.
|
||||
- No live GPU qualification was performed.
|
||||
- The CLI remains locally built and unpublished.
|
||||
|
||||
## Merge evidence
|
||||
|
||||
No TDD checkpoint commits were created because the implementation handoff
|
||||
explicitly prohibited commits. The working-tree diff and this report preserve
|
||||
the RED/GREEN evidence instead.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Everything Claude Code (ECC) — 智能体指令
|
||||
|
||||
这是一个**生产就绪的 AI 编码插件**,提供 67 个专业代理、278 项技能、94 条命令以及自动化钩子工作流,用于软件开发。
|
||||
这是一个**生产就绪的 AI 编码插件**,提供 67 个专业代理、279 项技能、94 条命令以及自动化钩子工作流,用于软件开发。
|
||||
|
||||
**版本:** 2.0.0
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
|
||||
```
|
||||
agents/ — 67 个专业子代理
|
||||
skills/ — 278 个工作流技能和领域知识
|
||||
skills/ — 279 个工作流技能和领域知识
|
||||
commands/ — 94 个斜杠命令
|
||||
hooks/ — 基于触发的自动化
|
||||
rules/ — 始终遵循的指导方针(通用 + 每种语言)
|
||||
|
||||
@@ -228,7 +228,7 @@ Copy-Item -Recurse rules/typescript "$HOME/.claude/rules/"
|
||||
/plugin list ecc@ecc
|
||||
```
|
||||
|
||||
**搞定!** 你现在可以使用 67 个智能体、278 项技能和 94 个命令了。
|
||||
**搞定!** 你现在可以使用 67 个智能体、279 项技能和 94 个命令了。
|
||||
|
||||
***
|
||||
|
||||
@@ -1142,7 +1142,7 @@ opencode
|
||||
|---------|---------------|----------|--------|
|
||||
| 智能体 | PASS: 67 个 | PASS: 12 个 | **Claude Code 领先** |
|
||||
| 命令 | PASS: 94 个 | PASS: 35 个 | **Claude Code 领先** |
|
||||
| 技能 | PASS: 278 项 | PASS: 37 项 | **Claude Code 领先** |
|
||||
| 技能 | PASS: 279 项 | PASS: 37 项 | **Claude Code 领先** |
|
||||
| 钩子 | PASS: 8 种事件类型 | PASS: 11 种事件 | **OpenCode 更多!** |
|
||||
| 规则 | PASS: 29 条 | PASS: 13 条指令 | **Claude Code 领先** |
|
||||
| MCP 服务器 | PASS: 14 个 | PASS: 完整 | **完全对等** |
|
||||
@@ -1250,7 +1250,7 @@ ECC 是**第一个最大化利用每个主要 AI 编码工具的插件**。以
|
||||
|---------|-----------------------|------------|-----------|----------|
|
||||
| **智能体** | 67 | 共享 (AGENTS.md) | 共享 (AGENTS.md) | 12 |
|
||||
| **命令** | 94 | 共享 | 基于指令 | 35 |
|
||||
| **技能** | 278 | 共享 | 10 (原生格式) | 37 |
|
||||
| **技能** | 279 | 共享 | 10 (原生格式) | 37 |
|
||||
| **钩子事件** | 8 种类型 | 15 种类型 | 暂无 | 11 种类型 |
|
||||
| **钩子脚本** | 20+ 个脚本 | 16 个脚本 (DRY 适配器) | N/A | 插件钩子 |
|
||||
| **规则** | 34 (通用 + 语言) | 34 (YAML 前页) | 基于指令 | 13 条指令 |
|
||||
|
||||
@@ -194,6 +194,14 @@
|
||||
"prediction-market-skills"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "capability:ito-compute",
|
||||
"family": "capability",
|
||||
"description": "Authenticated Itô GPU inventory, RFQ, and status workflows through the separately installed canonical CLI.",
|
||||
"modules": [
|
||||
"ito-compute"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "capability:social",
|
||||
"family": "capability",
|
||||
|
||||
@@ -571,6 +571,36 @@
|
||||
"cost": "medium",
|
||||
"stability": "beta"
|
||||
},
|
||||
{
|
||||
"id": "ito-compute",
|
||||
"kind": "skills",
|
||||
"description": "Authenticated Itô GPU inventory, RFQ, and status workflows through the separately installed canonical CLI.",
|
||||
"paths": [
|
||||
"skills/ito-compute"
|
||||
],
|
||||
"targets": [
|
||||
"claude",
|
||||
"claude-project",
|
||||
"cursor",
|
||||
"antigravity",
|
||||
"codex",
|
||||
"gemini",
|
||||
"opencode",
|
||||
"codebuddy",
|
||||
"joycode",
|
||||
"qwen",
|
||||
"zed",
|
||||
"hermes",
|
||||
"openclaw",
|
||||
"kimi"
|
||||
],
|
||||
"dependencies": [
|
||||
"platform-configs"
|
||||
],
|
||||
"defaultInstall": false,
|
||||
"cost": "light",
|
||||
"stability": "beta"
|
||||
},
|
||||
{
|
||||
"id": "social-distribution",
|
||||
"kind": "skills",
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
"operator-workflows",
|
||||
"optimization-workflows",
|
||||
"prediction-market-skills",
|
||||
"ito-compute",
|
||||
"social-distribution",
|
||||
"media-generation",
|
||||
"orchestration",
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
"args": ["mcp"],
|
||||
"description": "Local cost/privacy proxy - query your own usage & savings, route to the cheapest capable model, and mask secrets/PII before egress (nexus_stats, nexus_savings, nexus_recent, nexus_providers, nexus_cost_breakdown)"
|
||||
},
|
||||
"ito-compute": {
|
||||
"command": "node",
|
||||
"args": ["/absolute/path/to/ito-cloud-runtime/cli/ito-compute-cli/dist/bin/ito-mcp.js"],
|
||||
"description": "Opt-in local Itô compute MCP. The canonical package is unpublished and must be built from Ito-Markets/ito-cloud-runtime/cli/ito-compute-cli. Exposes only ito_auth, ito_find, and ito_status; inject ITO_API_KEY from the launching environment."
|
||||
},
|
||||
"jira": {
|
||||
"command": "uvx",
|
||||
"args": ["mcp-atlassian==0.21.0"],
|
||||
|
||||
+2
-1
@@ -214,6 +214,7 @@
|
||||
"skills/hookify-rules/",
|
||||
"skills/inventory-demand-planning/",
|
||||
"skills/ito-basket-compare/",
|
||||
"skills/ito-compute/",
|
||||
"skills/ito-data-atlas-agent/",
|
||||
"skills/ito-market-intelligence/",
|
||||
"skills/ito-trade-planner/",
|
||||
@@ -418,7 +419,7 @@
|
||||
"ecc-plan-canvas": "scripts/plan-canvas.js"
|
||||
},
|
||||
"scripts": {
|
||||
"welcome": "echo '\\n ecc-universal installed!\\n Run: ecc typescript\\n Compat: ecc-install typescript\\n Docs: https://github.com/affaan-m/ECC\\n Run or self-host any open-source model.\\n Compute: Itô is the preferred compute sponsor — https://compute.itomarkets.com\\n Any GPU provider works; ECC only links to the dashboard and does not provision compute or serving.\\n Managed inference through Itô is not live yet.\\n'",
|
||||
"welcome": "echo '\\n ecc-universal installed!\\n Run: ecc typescript\\n Compat: ecc-install typescript\\n Docs: https://github.com/affaan-m/ECC\\n Run or self-host any open-source model.\\n Compute: Itô is the preferred compute sponsor — https://compute.itomarkets.com\\n Any GPU provider works. This sponsorship link is passive: it does not invoke an RFQ, reserve capacity, provision compute, or configure serving.\\n Separately, the opt-in ecc ito find bridge invokes the explicitly configured canonical Itô CLI and submits a live authenticated RFQ; it does not reserve capacity.\\n Managed inference through Itô is not live yet.\\n'",
|
||||
"catalog:check": "node scripts/ci/catalog.js --text",
|
||||
"catalog:sync": "node scripts/ci/catalog.js --write --text",
|
||||
"command-registry:generate": "node scripts/ci/generate-command-registry.js",
|
||||
|
||||
+10
-4
@@ -29,7 +29,7 @@ const COMMANDS = {
|
||||
},
|
||||
ito: {
|
||||
script: 'ito.js',
|
||||
description: 'Prepare a read-only sandbox handoff to the Itô compute desk',
|
||||
description: 'Invoke the separately installed canonical Itô compute CLI',
|
||||
},
|
||||
'install-plan': {
|
||||
script: 'install-plan.js',
|
||||
@@ -138,8 +138,9 @@ Examples:
|
||||
ecc catalog show framework:nextjs
|
||||
ecc consult "security reviews"
|
||||
ecc control-pane --port 8765
|
||||
ecc ito rent --accelerator h100 --count 1 --hours 24
|
||||
ecc --dry-run ito rent --accelerator h100 --count 1 --hours 24 --json
|
||||
ecc ito auth
|
||||
ecc ito find --gpu h200 --count 8 --nodes 1 --gpus-per-node 8 --days 30 --storage-tb 1 --start-window 2099-08-15 --max-rate 3.00 --form-factor bare_metal --contract-type reservation --fabric infiniband --region us-east-1
|
||||
ecc ito status --json
|
||||
ecc list-installed --json
|
||||
ecc doctor --target cursor
|
||||
ecc repair --dry-run
|
||||
@@ -232,7 +233,12 @@ function runCommand(commandName, args) {
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
env: commandName === 'ito'
|
||||
? { ...createSafeItoEnvironment(process.env, { includeControls: true }) }
|
||||
? {
|
||||
...createSafeItoEnvironment(process.env, {
|
||||
includeControls: true,
|
||||
includeItoRuntime: true,
|
||||
}),
|
||||
}
|
||||
: process.env,
|
||||
encoding: 'utf8',
|
||||
maxBuffer: 10 * 1024 * 1024,
|
||||
|
||||
+179
-275
@@ -2,306 +2,210 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { spawnSync } = require("child_process");
|
||||
const { createSafeItoEnvironment } = require("./lib/ito-environment");
|
||||
|
||||
const DESK_URL = "https://compute.itomarkets.com/desk";
|
||||
const SCHEMA_VERSION = "ito.compute.handoff.v1";
|
||||
const SUPPORTED_ACCELERATORS = Object.freeze({
|
||||
h100: "h100",
|
||||
"h100-pcie": "h100-pcie",
|
||||
"h100-sxm": "h100-sxm",
|
||||
});
|
||||
const REQUIRED_INTENT_OPTIONS = Object.freeze([
|
||||
"accelerator",
|
||||
"count",
|
||||
"hours",
|
||||
]);
|
||||
const SUPPORTED_COMMANDS = Object.freeze(["auth", "find", "status"]);
|
||||
const CANONICAL_REPOSITORY = "https://github.com/Ito-Markets/ito-cloud-runtime.git";
|
||||
const CANONICAL_PACKAGE_PATH = "cli/ito-compute-cli";
|
||||
const EXECUTABLE_OVERRIDE = "ECC_ITO_CLI_EXECUTABLE";
|
||||
const MAX_OUTPUT_BYTES = 10 * 1024 * 1024;
|
||||
|
||||
function showHelp() {
|
||||
console.log(`
|
||||
ECC × Itô compute handoff
|
||||
ECC × Itô local CLI bridge
|
||||
|
||||
Usage:
|
||||
ecc ito rent --accelerator <h100|h100-pcie|h100-sxm> --count <1-64> --hours <1-720> [options]
|
||||
ecc ito auth
|
||||
ecc ito find <all required RFQ options>
|
||||
ecc ito status
|
||||
ecc ito <auth|find|status> --json
|
||||
|
||||
Options:
|
||||
--dry-run Emit the exact handoff without opening a browser
|
||||
--no-open Emit the exact handoff for manual browser navigation
|
||||
--json Emit the versioned response envelope as JSON
|
||||
--help Show this help
|
||||
The bridge invokes the separately installed canonical Itô CLI and returns its
|
||||
real stdout, stderr, and exit code unchanged. It performs no browser navigation
|
||||
and adds no lock, workload, inference, evaluation, or purchase path.
|
||||
|
||||
Example:
|
||||
ecc ito rent --accelerator h100 --count 1 --hours 24
|
||||
Important:
|
||||
- "find" reads live inventory and submits an authenticated RFQ.
|
||||
- Obtain explicit buyer authority and every hard constraint before invoking it.
|
||||
- "status" reads live RFQ and procurement status.
|
||||
- Inventory and RFQs are not reservations; only a returned firm quote is firm.
|
||||
|
||||
This command creates a sandbox-only, read-only intent. It opens the Itô desk
|
||||
for manual copy; sign-in may be required. It does not send the intent into Itô,
|
||||
file an RFQ, request or accept a quote, call a procurement endpoint, approve
|
||||
funds, or place an order. Stop before "Pay & buy".
|
||||
The canonical package is currently unpublished. Install it locally:
|
||||
Canonical source: Ito-Markets/ito-cloud-runtime/${CANONICAL_PACKAGE_PATH}
|
||||
git clone ${CANONICAL_REPOSITORY}
|
||||
cd ito-cloud-runtime/${CANONICAL_PACKAGE_PATH}
|
||||
npm ci
|
||||
npm run check
|
||||
|
||||
Then set ${EXECUTABLE_OVERRIDE} to the explicit absolute built entry:
|
||||
/absolute/path/to/ito-cloud-runtime/${CANONICAL_PACKAGE_PATH}/dist/bin/ito.js
|
||||
|
||||
For safety, ECC never discovers this credential-bearing client through PATH.
|
||||
|
||||
The same package's MCP server exposes only:
|
||||
ito_auth
|
||||
ito_find
|
||||
ito_status
|
||||
|
||||
Configure the MCP command as "node" with this absolute argument:
|
||||
/absolute/path/to/ito-cloud-runtime/${CANONICAL_PACKAGE_PATH}/dist/bin/ito-mcp.js
|
||||
|
||||
Inject ITO_API_KEY into the child process from 1Password or the launching
|
||||
environment. Never put the key in arguments, tracked files, or chat.
|
||||
`);
|
||||
}
|
||||
|
||||
function readValue(args, index, option) {
|
||||
const value = args[index + 1];
|
||||
if (value === undefined || value.startsWith("--")) {
|
||||
throw new Error(`--${option} requires a value`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function parseInteger(raw, option, minimum, maximum) {
|
||||
if (!/^[0-9]+$/.test(raw)) {
|
||||
throw new Error(`--${option} must be an integer between ${minimum} and ${maximum}`);
|
||||
}
|
||||
const value = Number(raw);
|
||||
if (!Number.isSafeInteger(value) || value < minimum || value > maximum) {
|
||||
throw new Error(`--${option} must be an integer between ${minimum} and ${maximum}`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function parseAccelerator(raw) {
|
||||
const normalized = String(raw).trim().toLowerCase();
|
||||
const accelerator = SUPPORTED_ACCELERATORS[normalized];
|
||||
if (!accelerator) {
|
||||
throw new Error(
|
||||
"--accelerator must be one of h100, h100-pcie, or h100-sxm"
|
||||
);
|
||||
}
|
||||
return accelerator;
|
||||
}
|
||||
|
||||
function parseArgs(argv) {
|
||||
function parseArgs(argv, environment = process.env) {
|
||||
const args = [...argv];
|
||||
if (args.includes("--help") || args.includes("-h")) {
|
||||
return { help: true };
|
||||
if (
|
||||
args.length === 0
|
||||
|| args.includes("--help")
|
||||
|| args.includes("-h")
|
||||
) {
|
||||
return Object.freeze({ help: true, invocationArgs: [] });
|
||||
}
|
||||
|
||||
const command = args.shift();
|
||||
if (command !== "rent") {
|
||||
throw new Error(`unsupported Itô command: ${command || "(missing)"}`);
|
||||
}
|
||||
|
||||
const values = {
|
||||
accelerator: null,
|
||||
count: null,
|
||||
hours: null,
|
||||
dryRun: false,
|
||||
json: false,
|
||||
noOpen: false,
|
||||
};
|
||||
const seen = new Set();
|
||||
|
||||
for (let index = 0; index < args.length; index += 1) {
|
||||
const arg = args[index];
|
||||
if (arg === "--dry-run") {
|
||||
if (seen.has("dry-run")) throw new Error("--dry-run may only be provided once");
|
||||
seen.add("dry-run");
|
||||
values.dryRun = true;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--json") {
|
||||
if (seen.has("json")) throw new Error("--json may only be provided once");
|
||||
seen.add("json");
|
||||
values.json = true;
|
||||
continue;
|
||||
}
|
||||
if (arg === "--no-open") {
|
||||
if (seen.has("no-open")) throw new Error("--no-open may only be provided once");
|
||||
seen.add("no-open");
|
||||
values.noOpen = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
const option = arg.startsWith("--") ? arg.slice(2) : "";
|
||||
if (!REQUIRED_INTENT_OPTIONS.includes(option)) {
|
||||
throw new Error(`unsupported option: ${arg}`);
|
||||
}
|
||||
if (seen.has(option)) {
|
||||
throw new Error(`--${option} may only be provided once`);
|
||||
}
|
||||
seen.add(option);
|
||||
const raw = readValue(args, index, option);
|
||||
if (option === "accelerator") values.accelerator = parseAccelerator(raw);
|
||||
if (option === "count") values.count = parseInteger(raw, option, 1, 64);
|
||||
if (option === "hours") values.hours = parseInteger(raw, option, 1, 720);
|
||||
index += 1;
|
||||
}
|
||||
|
||||
const missing = REQUIRED_INTENT_OPTIONS.filter((option) => values[option] === null);
|
||||
if (missing.length > 0) {
|
||||
if (environment.ECC_DRY_RUN === "1" || args.includes("--dry-run")) {
|
||||
throw new Error(
|
||||
`missing required rental intent option${missing.length === 1 ? "" : "s"}: `
|
||||
+ missing.map((option) => `--${option}`).join(", ")
|
||||
"Itô compute has no paper or dry-run success mode. No CLI operation was invoked."
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
help: false,
|
||||
command,
|
||||
options: Object.freeze({
|
||||
...values,
|
||||
dryRun: values.dryRun || process.env.ECC_DRY_RUN === "1",
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
function buildHandoffMessage(intent) {
|
||||
const accelerator = intent.accelerator.toUpperCase();
|
||||
return [
|
||||
"[ECC sandbox-only compute handoff]",
|
||||
`Source: ECC CLI. Need ${intent.count} × ${accelerator} for ${intent.hours} hours.`,
|
||||
"Treat this as a read-only requirement for review.",
|
||||
"Do not file an RFQ, request or accept a quote, place an order, approve funds, or contact a counterparty without a separate explicit human action in Itô.",
|
||||
].join(" ");
|
||||
}
|
||||
|
||||
function createEnvelope({ success, state, data, error }) {
|
||||
return Object.freeze({
|
||||
schemaVersion: SCHEMA_VERSION,
|
||||
success,
|
||||
state,
|
||||
data,
|
||||
error,
|
||||
links: Object.freeze({ desk: DESK_URL }),
|
||||
});
|
||||
}
|
||||
|
||||
function createInvalidEnvelope(message) {
|
||||
return createEnvelope({
|
||||
success: false,
|
||||
state: "invalid_request",
|
||||
data: null,
|
||||
error: Object.freeze({
|
||||
code: "INVALID_ARGUMENT",
|
||||
message,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
function defaultOpenUrl(url) {
|
||||
let executable;
|
||||
let args;
|
||||
const testExecutable = process.env.NODE_ENV === "test"
|
||||
? process.env.ECC_ITO_BROWSER_EXECUTABLE
|
||||
: null;
|
||||
|
||||
if (testExecutable) {
|
||||
if (process.platform === "win32" && /\.(?:bat|cmd)$/i.test(testExecutable)) {
|
||||
executable = process.env.ComSpec || "cmd.exe";
|
||||
args = ["/d", "/s", "/c", testExecutable, url];
|
||||
} else {
|
||||
executable = testExecutable;
|
||||
args = [url];
|
||||
}
|
||||
} else if (process.platform === "darwin") {
|
||||
executable = "open";
|
||||
args = [url];
|
||||
} else if (process.platform === "win32") {
|
||||
executable = "cmd.exe";
|
||||
args = ["/d", "/s", "/c", "start", "", url];
|
||||
} else {
|
||||
executable = "xdg-open";
|
||||
args = [url];
|
||||
const jsonIndexes = args
|
||||
.map((value, index) => (value === "--json" ? index : -1))
|
||||
.filter((index) => index >= 0);
|
||||
if (jsonIndexes.length > 1) {
|
||||
throw new Error("--json may only be provided once");
|
||||
}
|
||||
const withoutJson = args.filter((value) => value !== "--json");
|
||||
const command = withoutJson.shift();
|
||||
if (!SUPPORTED_COMMANDS.includes(command)) {
|
||||
throw new Error(
|
||||
`Unsupported Itô command "${command || "(missing)"}"; ECC permits only auth, find, and status.`
|
||||
);
|
||||
}
|
||||
|
||||
const result = spawnSync(executable, args, {
|
||||
env: { ...createSafeItoEnvironment(process.env) },
|
||||
stdio: "ignore",
|
||||
windowsHide: true,
|
||||
shell: false,
|
||||
});
|
||||
return !result.error && result.status === 0;
|
||||
}
|
||||
|
||||
function createHandoff(options, openUrl = defaultOpenUrl) {
|
||||
const shouldOpen = !options.dryRun && !options.noOpen;
|
||||
const opened = shouldOpen ? openUrl(DESK_URL) : false;
|
||||
const intent = Object.freeze({
|
||||
accelerator: options.accelerator,
|
||||
count: options.count,
|
||||
hours: options.hours,
|
||||
});
|
||||
|
||||
return createEnvelope({
|
||||
success: true,
|
||||
state: "manual_handoff",
|
||||
data: Object.freeze({
|
||||
authenticated: null,
|
||||
dryRun: options.dryRun,
|
||||
opened,
|
||||
intent,
|
||||
provenance: Object.freeze({
|
||||
source: "ecc-cli",
|
||||
command: "ecc ito rent",
|
||||
}),
|
||||
authority: Object.freeze({
|
||||
environment: "sandbox",
|
||||
readOnly: true,
|
||||
liveRfq: false,
|
||||
procurementMutation: false,
|
||||
quoteAcceptance: false,
|
||||
fundsApproval: false,
|
||||
orderCreation: false,
|
||||
outreach: false,
|
||||
}),
|
||||
handoff: Object.freeze({
|
||||
transport: "manual_copy",
|
||||
destination: "ito-desk",
|
||||
acceptedByIto: false,
|
||||
signInMayBeRequired: true,
|
||||
message: buildHandoffMessage(intent),
|
||||
limitation: "Itô /desk currently exposes no supported structured ECC intake or deep-link contract.",
|
||||
}),
|
||||
approvalGate: 'Stop before "Pay & buy".',
|
||||
priceQuote: null,
|
||||
orderId: null,
|
||||
}),
|
||||
error: null,
|
||||
return Object.freeze({
|
||||
help: false,
|
||||
invocationArgs: Object.freeze([
|
||||
...(jsonIndexes.length === 1 ? ["--json"] : []),
|
||||
command,
|
||||
...withoutJson,
|
||||
]),
|
||||
});
|
||||
}
|
||||
|
||||
function renderText(payload) {
|
||||
const { data } = payload;
|
||||
const browserState = data.dryRun
|
||||
? "Dry-run: browser not opened."
|
||||
: data.opened
|
||||
? "Opened the Itô desk; sign-in may be required."
|
||||
: "Browser not opened; sign-in may be required at the Itô desk.";
|
||||
return [
|
||||
"ECC × Itô sandbox compute handoff",
|
||||
"",
|
||||
browserState,
|
||||
`Desk: ${payload.links.desk}`,
|
||||
"Transport: manual copy; Itô has not accepted this intent.",
|
||||
`Message: ${data.handoff.message}`,
|
||||
`Limitation: ${data.handoff.limitation}`,
|
||||
`Approval gate: ${data.approvalGate}`,
|
||||
"",
|
||||
"ECC does not file an RFQ, request or accept a quote, use credentials, approve funds, create an order, or contact a counterparty.",
|
||||
].join("\n");
|
||||
function resolveItoExecutable(environment = process.env) {
|
||||
const configured = environment[EXECUTABLE_OVERRIDE]?.trim();
|
||||
if (!configured) {
|
||||
throw new Error([
|
||||
"The canonical ito-compute-cli is unpublished and ECC will not resolve",
|
||||
`a credential-bearing "ito" executable from PATH. Build it from`,
|
||||
`${CANONICAL_REPOSITORY.replace(/\.git$/, "")}/${CANONICAL_PACKAGE_PATH},`,
|
||||
"run npm ci and npm run check, then set",
|
||||
`${EXECUTABLE_OVERRIDE} to the explicit absolute dist/bin/ito.js path.`,
|
||||
].join(" "));
|
||||
}
|
||||
|
||||
if (!path.isAbsolute(configured)) {
|
||||
throw new Error(
|
||||
`${EXECUTABLE_OVERRIDE} must be an absolute path explicitly configured by the operator.`
|
||||
);
|
||||
}
|
||||
return assertUsableExecutable(configured);
|
||||
}
|
||||
|
||||
function main(argv = process.argv.slice(2), dependencies = {}) {
|
||||
let parsed;
|
||||
function assertUsableExecutable(candidate) {
|
||||
let canonicalCandidate;
|
||||
try {
|
||||
parsed = parseArgs(argv);
|
||||
canonicalCandidate = fs.realpathSync.native(candidate);
|
||||
} catch {
|
||||
throw new Error(
|
||||
`${EXECUTABLE_OVERRIDE} does not point to a readable local Itô CLI file.`
|
||||
);
|
||||
}
|
||||
if (!isUsableExecutable(canonicalCandidate)) {
|
||||
throw new Error(
|
||||
`${EXECUTABLE_OVERRIDE} does not point to a readable local Itô CLI file.`
|
||||
);
|
||||
}
|
||||
return canonicalCandidate;
|
||||
}
|
||||
|
||||
function isUsableExecutable(candidate) {
|
||||
try {
|
||||
const info = fs.statSync(candidate);
|
||||
if (!info.isFile()) return false;
|
||||
if (process.platform !== "win32" && path.extname(candidate) !== ".js") {
|
||||
fs.accessSync(candidate, fs.constants.X_OK);
|
||||
} else {
|
||||
fs.accessSync(candidate, fs.constants.R_OK);
|
||||
}
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function buildInvocation(executable, args) {
|
||||
if (path.extname(executable).toLowerCase() === ".js") {
|
||||
return Object.freeze({
|
||||
executable: process.execPath,
|
||||
args: Object.freeze([executable, ...args]),
|
||||
});
|
||||
}
|
||||
if (
|
||||
process.platform === "win32"
|
||||
&& /\.(?:bat|cmd|ps1)$/i.test(executable)
|
||||
) {
|
||||
throw new Error(
|
||||
`Refusing to invoke the Itô CLI through a shell shim. Set ${EXECUTABLE_OVERRIDE} to the absolute dist/bin/ito.js path.`
|
||||
);
|
||||
}
|
||||
return Object.freeze({ executable, args: Object.freeze([...args]) });
|
||||
}
|
||||
|
||||
function invokeIto(executable, args, environment = process.env) {
|
||||
const invocation = buildInvocation(executable, args);
|
||||
const result = spawnSync(invocation.executable, invocation.args, {
|
||||
cwd: process.cwd(),
|
||||
encoding: "utf8",
|
||||
env: {
|
||||
...createSafeItoEnvironment(environment, { includeItoRuntime: true }),
|
||||
},
|
||||
maxBuffer: MAX_OUTPUT_BYTES,
|
||||
shell: false,
|
||||
windowsHide: true,
|
||||
});
|
||||
|
||||
if (result.stdout) process.stdout.write(result.stdout);
|
||||
if (result.stderr) process.stderr.write(result.stderr);
|
||||
if (result.error) {
|
||||
throw new Error(`The local Itô CLI could not be started: ${result.error.message}`);
|
||||
}
|
||||
if (typeof result.status === "number") return result.status;
|
||||
if (result.signal) {
|
||||
throw new Error(`The local Itô CLI terminated by signal ${result.signal}.`);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
function main(argv = process.argv.slice(2), environment = process.env) {
|
||||
try {
|
||||
const parsed = parseArgs(argv, environment);
|
||||
if (parsed.help) {
|
||||
showHelp();
|
||||
return 0;
|
||||
}
|
||||
const executable = resolveItoExecutable(environment);
|
||||
return invokeIto(executable, parsed.invocationArgs, environment);
|
||||
} catch (error) {
|
||||
const payload = createInvalidEnvelope(error.message);
|
||||
if (argv.includes("--json")) console.log(JSON.stringify(payload, null, 2));
|
||||
else console.error(`Error: ${error.message}`);
|
||||
console.error(`Error: ${error.message}`);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (parsed.help) {
|
||||
showHelp();
|
||||
return 0;
|
||||
}
|
||||
|
||||
const payload = createHandoff(parsed.options, dependencies.openUrl);
|
||||
if (parsed.options.json) console.log(JSON.stringify(payload, null, 2));
|
||||
else console.log(renderText(payload));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
@@ -309,13 +213,13 @@ if (require.main === module) {
|
||||
}
|
||||
|
||||
module.exports = Object.freeze({
|
||||
DESK_URL,
|
||||
SCHEMA_VERSION,
|
||||
buildHandoffMessage,
|
||||
createHandoff,
|
||||
createInvalidEnvelope,
|
||||
CANONICAL_PACKAGE_PATH,
|
||||
CANONICAL_REPOSITORY,
|
||||
EXECUTABLE_OVERRIDE,
|
||||
SUPPORTED_COMMANDS,
|
||||
buildInvocation,
|
||||
invokeIto,
|
||||
main,
|
||||
parseAccelerator,
|
||||
parseArgs,
|
||||
renderText,
|
||||
resolveItoExecutable,
|
||||
});
|
||||
|
||||
@@ -6,8 +6,11 @@ function getComputeSponsorCopy() {
|
||||
return "Run or self-host any open-source model. Itô is ECC's preferred compute sponsor: "
|
||||
+ 'open its dashboard to sign in and rent or manage GPUs at '
|
||||
+ ITO_COMPUTE_URL
|
||||
+ '. Any GPU provider works. ECC only provides this link; it does not provision '
|
||||
+ 'compute or serving. Managed inference through Itô is not live yet.';
|
||||
+ '. Any GPU provider works. This sponsorship link is passive: it does not invoke '
|
||||
+ 'an RFQ, reserve capacity, provision compute, or configure serving. Separately, '
|
||||
+ 'the opt-in "ecc ito find" bridge invokes the explicitly configured canonical '
|
||||
+ 'Itô CLI and submits a live authenticated RFQ; it does not reserve capacity. '
|
||||
+ 'Managed inference through Itô is not live yet.';
|
||||
}
|
||||
|
||||
module.exports = Object.freeze({
|
||||
|
||||
@@ -23,6 +23,18 @@ const SYSTEM_ENVIRONMENT_KEYS = Object.freeze([
|
||||
"XDG_RUNTIME_DIR",
|
||||
]);
|
||||
|
||||
const ITO_RUNTIME_ENVIRONMENT_KEYS = Object.freeze([
|
||||
"ITO_API_KEY",
|
||||
"ITO_API_URL",
|
||||
"ITO_INVENTORY_URL",
|
||||
]);
|
||||
|
||||
const ECC_ITO_CONTROL_KEYS = Object.freeze([
|
||||
"ECC_DRY_RUN",
|
||||
"ECC_ITO_CLI_EXECUTABLE",
|
||||
"NODE_ENV",
|
||||
]);
|
||||
|
||||
function copyDefined(source, target, key) {
|
||||
if (typeof source[key] === "string") {
|
||||
target[key] = source[key];
|
||||
@@ -38,11 +50,15 @@ function createSafeItoEnvironment(source = process.env, options = {}) {
|
||||
if (key.startsWith("LC_")) copyDefined(source, safe, key);
|
||||
}
|
||||
|
||||
if (options.includeItoRuntime) {
|
||||
for (const key of ITO_RUNTIME_ENVIRONMENT_KEYS) {
|
||||
copyDefined(source, safe, key);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.includeControls) {
|
||||
copyDefined(source, safe, "ECC_DRY_RUN");
|
||||
copyDefined(source, safe, "NODE_ENV");
|
||||
if (source.NODE_ENV === "test") {
|
||||
copyDefined(source, safe, "ECC_ITO_BROWSER_EXECUTABLE");
|
||||
for (const key of ECC_ITO_CONTROL_KEYS) {
|
||||
copyDefined(source, safe, key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +66,8 @@ function createSafeItoEnvironment(source = process.env, options = {}) {
|
||||
}
|
||||
|
||||
module.exports = Object.freeze({
|
||||
ECC_ITO_CONTROL_KEYS,
|
||||
ITO_RUNTIME_ENVIRONMENT_KEYS,
|
||||
SYSTEM_ENVIRONMENT_KEYS,
|
||||
createSafeItoEnvironment,
|
||||
});
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
---
|
||||
name: ito-compute
|
||||
description: Query live GPU inventory, submit an authenticated Itô fixed-rate RFQ, and inspect RFQ or procurement status through the separately installed canonical CLI or its exact MCP tools. Use when a user asks to find H100/H200 capacity, request a fixed compute rate, or check Itô compute status.
|
||||
metadata:
|
||||
origin: ECC
|
||||
---
|
||||
|
||||
# Itô Compute
|
||||
|
||||
Use the canonical Itô compute CLI or MCP server. ECC does not implement a
|
||||
parallel client, browser handoff, local simulation, reservation, workload
|
||||
runner, or inference server.
|
||||
|
||||
## Install the canonical local package
|
||||
|
||||
`ito-compute-cli` is currently unpublished. Build it from its canonical
|
||||
repository instead of using `npx`, `npm exec`, or an unverified package:
|
||||
|
||||
```sh
|
||||
git clone https://github.com/Ito-Markets/ito-cloud-runtime.git
|
||||
cd ito-cloud-runtime/cli/ito-compute-cli
|
||||
npm ci
|
||||
npm run check
|
||||
```
|
||||
|
||||
Set `ECC_ITO_CLI_EXECUTABLE` to the explicit absolute built entry:
|
||||
|
||||
```text
|
||||
/absolute/path/to/ito-cloud-runtime/cli/ito-compute-cli/dist/bin/ito.js
|
||||
```
|
||||
|
||||
ECC never discovers this credential-bearing client through `PATH`.
|
||||
Inject `ITO_API_KEY` through 1Password or the launching process environment.
|
||||
Never put it in arguments, tracked files, MCP results, logs, or chat.
|
||||
|
||||
## CLI workflow
|
||||
|
||||
1. Run `ecc ito auth` before the first operation.
|
||||
2. Before `ecc ito find`, obtain explicit buyer authority to submit an RFQ.
|
||||
- Require `gpu`, `count`, whole `days`, `max-rate`, `nodes`,
|
||||
`gpus-per-node`, `storage-tb`, `start-window`, `form-factor`,
|
||||
`contract-type`, `fabric`, `region`, and the split-fill decision.
|
||||
- Require `count == nodes * gpus-per-node`; never derive topology.
|
||||
- Use `any` only when the buyer explicitly accepts any fabric or region.
|
||||
- Omitted `--allow-split` means false.
|
||||
3. Run the live RFQ command:
|
||||
|
||||
```sh
|
||||
ecc ito find \
|
||||
--gpu h200 \
|
||||
--count 8 \
|
||||
--nodes 1 \
|
||||
--gpus-per-node 8 \
|
||||
--days 30 \
|
||||
--storage-tb 1 \
|
||||
--start-window 2099-08-15 \
|
||||
--max-rate 3.00 \
|
||||
--form-factor bare_metal \
|
||||
--contract-type reservation \
|
||||
--fabric infiniband \
|
||||
--region us-east-1
|
||||
```
|
||||
|
||||
4. Run `ecc ito status` to inspect RFQs and procurement orders.
|
||||
After an ambiguous transport failure, check status before repeating `find`.
|
||||
|
||||
Inventory prices are indicative. An RFQ is not reserved capacity. Treat a rate
|
||||
as fixed only when the canonical result contains a non-null firm quote.
|
||||
|
||||
## MCP workflow
|
||||
|
||||
Build the canonical package, then configure the stdio server with an absolute
|
||||
path:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"ito-compute": {
|
||||
"command": "node",
|
||||
"args": [
|
||||
"/absolute/path/to/ito-cloud-runtime/cli/ito-compute-cli/dist/bin/ito-mcp.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The server exposes only:
|
||||
|
||||
- `ito_auth`
|
||||
- `ito_find`
|
||||
- `ito_status`
|
||||
|
||||
Use `ito_auth`, gather explicit buyer authority and every hard constraint, call
|
||||
`ito_find`, then poll with `ito_status` when needed.
|
||||
|
||||
## Unsupported operations
|
||||
|
||||
The supported client surface cannot lock quotes, reserve capacity, execute
|
||||
workloads, qualify nodes through ECC, or serve inference. Do not invent
|
||||
additional tools or a purchase path. Do not substitute a browser or fixture
|
||||
when the local CLI is missing or a live operation fails. Report the missing
|
||||
capability and stop.
|
||||
@@ -41,8 +41,11 @@ def print_self_host_compute_notice(provider: str) -> None:
|
||||
"https://compute.itomarkets.com"
|
||||
)
|
||||
print(
|
||||
"Any GPU provider works. ECC only links to the Itô dashboard; it does not "
|
||||
"provision compute or serving. Managed inference through Itô is not live yet."
|
||||
"Any GPU provider works. This sponsorship link is passive: it does not invoke "
|
||||
"an RFQ, reserve capacity, provision compute, or configure serving. Separately, "
|
||||
'the opt-in "ecc ito find" bridge invokes the explicitly configured canonical '
|
||||
"Itô CLI and submits a live authenticated RFQ; it does not reserve capacity. "
|
||||
"Managed inference through Itô is not live yet."
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Contract tests for the installable Itô compute skill and MCP documentation.
|
||||
*/
|
||||
|
||||
const assert = require("assert");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const REPO_ROOT = path.join(__dirname, "..", "..");
|
||||
|
||||
function read(relativePath) {
|
||||
return fs.readFileSync(path.join(REPO_ROOT, relativePath), "utf8");
|
||||
}
|
||||
|
||||
function readJson(relativePath) {
|
||||
return JSON.parse(read(relativePath));
|
||||
}
|
||||
|
||||
function runTest(name, fn) {
|
||||
try {
|
||||
fn();
|
||||
console.log(` ✓ ${name}`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.log(` ✗ ${name}`);
|
||||
console.error(` ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
console.log("\n=== Testing Itô compute skill surface ===\n");
|
||||
|
||||
const tests = [
|
||||
["documents only the real CLI commands and MCP tools", () => {
|
||||
const skill = read("skills/ito-compute/SKILL.md");
|
||||
for (const command of ["ecc ito auth", "ecc ito find", "ecc ito status"]) {
|
||||
assert.match(skill, new RegExp(command.replace(" ", "\\s+")));
|
||||
}
|
||||
assert.doesNotMatch(skill, /^\s*ito (?:auth|find|status)\b/m);
|
||||
for (const tool of ["ito_auth", "ito_find", "ito_status"]) {
|
||||
assert.match(skill, new RegExp(`\\b${tool}\\b`));
|
||||
}
|
||||
assert.doesNotMatch(
|
||||
skill,
|
||||
/ito_lock|ito_run|ITO_CLI_DEMO|paper mode|simulated|live on the registry|publishing soon/i
|
||||
);
|
||||
assert.match(skill, /unpublished/i);
|
||||
assert.match(skill, /Ito-Markets\/ito-cloud-runtime/);
|
||||
assert.match(skill, /cli\/ito-compute-cli/);
|
||||
assert.match(skill, /npm run check/);
|
||||
assert.match(skill, /ECC_ITO_CLI_EXECUTABLE/);
|
||||
assert.match(skill, /explicit absolute built entry/);
|
||||
assert.match(skill, /never discovers[^\n]*through `PATH`/);
|
||||
assert.doesNotMatch(skill, /npm link/);
|
||||
}],
|
||||
["registers one opt-in install module and capability", () => {
|
||||
const modules = readJson("manifests/install-modules.json").modules;
|
||||
const module = modules.find((candidate) => candidate.id === "ito-compute");
|
||||
assert.ok(module, "ito-compute install module is missing");
|
||||
assert.deepStrictEqual(module.paths, ["skills/ito-compute"]);
|
||||
assert.deepStrictEqual(module.dependencies, ["platform-configs"]);
|
||||
assert.strictEqual(module.defaultInstall, false);
|
||||
assert.strictEqual(module.stability, "beta");
|
||||
for (const target of ["claude", "codex", "opencode", "hermes", "kimi"]) {
|
||||
assert.ok(module.targets.includes(target), `${target} target is missing`);
|
||||
}
|
||||
|
||||
const components = readJson("manifests/install-components.json").components;
|
||||
assert.deepStrictEqual(
|
||||
components.find((candidate) => candidate.id === "capability:ito-compute"),
|
||||
{
|
||||
id: "capability:ito-compute",
|
||||
family: "capability",
|
||||
description: "Authenticated Itô GPU inventory, RFQ, and status workflows through the separately installed canonical CLI.",
|
||||
modules: ["ito-compute"],
|
||||
}
|
||||
);
|
||||
const profiles = readJson("manifests/install-profiles.json").profiles;
|
||||
assert.ok(profiles.full.modules.includes("ito-compute"));
|
||||
}],
|
||||
["publishes the skill but never bundles the Itô CLI", () => {
|
||||
const packageJson = readJson("package.json");
|
||||
assert.ok(packageJson.files.includes("skills/ito-compute/"));
|
||||
assert.ok(!packageJson.dependencies?.["ito-compute-cli"]);
|
||||
assert.ok(!packageJson.optionalDependencies?.["ito-compute-cli"]);
|
||||
assert.ok(!packageJson.bin?.ito);
|
||||
}],
|
||||
["offers an opt-in local MCP template with the exact real tool boundary", () => {
|
||||
const mcpConfig = readJson("mcp-configs/mcp-servers.json");
|
||||
const server = mcpConfig.mcpServers["ito-compute"];
|
||||
assert.ok(server, "ito-compute MCP template is missing");
|
||||
assert.strictEqual(server.command, "node");
|
||||
assert.deepStrictEqual(server.args, [
|
||||
"/absolute/path/to/ito-cloud-runtime/cli/ito-compute-cli/dist/bin/ito-mcp.js",
|
||||
]);
|
||||
assert.doesNotMatch(JSON.stringify(server), /npx|ito_lock|ito_run|paper|simulat/i);
|
||||
assert.match(server.description, /ito_auth, ito_find, and ito_status/);
|
||||
assert.match(server.description, /unpublished/i);
|
||||
}],
|
||||
];
|
||||
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
for (const [name, fn] of tests) {
|
||||
if (runTest(name, fn)) passed += 1;
|
||||
else failed += 1;
|
||||
}
|
||||
|
||||
console.log(`\nPassed: ${passed}`);
|
||||
console.log(`Failed: ${failed}`);
|
||||
process.exit(failed > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -39,6 +39,7 @@ function run(args = [], options = {}) {
|
||||
env,
|
||||
encoding: 'utf8',
|
||||
stdio: ['pipe', 'pipe', 'pipe'],
|
||||
maxBuffer: 4 * 1024 * 1024,
|
||||
timeout: options.timeout || DEFAULT_INSTALL_APPLY_TIMEOUT_MS,
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
/**
|
||||
* End-to-end contract tests for ECC's real local Itô CLI bridge.
|
||||
*
|
||||
* The executable used here is a process-boundary probe. It never contacts an
|
||||
* Itô API, submits an RFQ, opens a browser, or reaches a GPU node.
|
||||
*/
|
||||
|
||||
const assert = require("assert");
|
||||
const fs = require("fs");
|
||||
const os = require("os");
|
||||
const path = require("path");
|
||||
const { spawnSync } = require("child_process");
|
||||
|
||||
const REPO_ROOT = path.join(__dirname, "..", "..");
|
||||
const ECC_SCRIPT = path.join(REPO_ROOT, "scripts", "ecc.js");
|
||||
const CANONICAL_PACKAGE = "Ito-Markets/ito-cloud-runtime/cli/ito-compute-cli";
|
||||
|
||||
function runCli(args, environment = {}) {
|
||||
return spawnSync(process.execPath, [ECC_SCRIPT, ...args], {
|
||||
cwd: REPO_ROOT,
|
||||
encoding: "utf8",
|
||||
env: {
|
||||
...process.env,
|
||||
NODE_ENV: "test",
|
||||
...environment,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function makeItoProbe(exitCode = 0) {
|
||||
const directory = fs.mkdtempSync(path.join(os.tmpdir(), "ecc-ito-cli-"));
|
||||
const log = path.join(directory, "invocation.json");
|
||||
const script = path.join(directory, "ito-probe.js");
|
||||
const executable = script;
|
||||
fs.writeFileSync(
|
||||
script,
|
||||
[
|
||||
`#!${process.execPath}`,
|
||||
'"use strict";',
|
||||
'const fs = require("fs");',
|
||||
`fs.writeFileSync(${JSON.stringify(log)}, JSON.stringify({ argv: process.argv.slice(2), env: process.env }));`,
|
||||
'process.stdout.write(`ito-probe:${process.argv.slice(2).join("|")}\\n`);',
|
||||
'process.stderr.write("ito-probe-stderr\\n");',
|
||||
`process.exit(${exitCode});`,
|
||||
"",
|
||||
].join("\n")
|
||||
);
|
||||
if (process.platform !== "win32") {
|
||||
fs.chmodSync(script, 0o755);
|
||||
}
|
||||
return Object.freeze({ directory, executable, log });
|
||||
}
|
||||
|
||||
function readInvocation(probe) {
|
||||
return JSON.parse(fs.readFileSync(probe.log, "utf8"));
|
||||
}
|
||||
|
||||
function runTest(name, fn) {
|
||||
try {
|
||||
fn();
|
||||
console.log(` ✓ ${name}`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.log(` ✗ ${name}`);
|
||||
console.error(` ${error.message}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
console.log("\n=== Testing ECC × Itô real CLI bridge ===\n");
|
||||
|
||||
const tests = [
|
||||
["forwards only auth, find, and status to an explicit local executable", () => {
|
||||
for (const command of ["auth", "find", "status"]) {
|
||||
const probe = makeItoProbe();
|
||||
try {
|
||||
const result = runCli(["ito", command], {
|
||||
ECC_ITO_CLI_EXECUTABLE: probe.executable,
|
||||
});
|
||||
assert.strictEqual(result.status, 0, result.stderr);
|
||||
assert.deepStrictEqual(readInvocation(probe).argv, [command]);
|
||||
assert.match(result.stdout, new RegExp(`ito-probe:${command}`));
|
||||
} finally {
|
||||
fs.rmSync(probe.directory, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
}],
|
||||
["normalizes JSON and forwards every RFQ constraint without interpretation", () => {
|
||||
const probe = makeItoProbe();
|
||||
try {
|
||||
const args = [
|
||||
"ito",
|
||||
"find",
|
||||
"--gpu", "h200",
|
||||
"--count", "8",
|
||||
"--nodes", "1",
|
||||
"--gpus-per-node", "8",
|
||||
"--days", "30",
|
||||
"--storage-tb", "1",
|
||||
"--start-window", "2099-08-15",
|
||||
"--max-rate", "3.00",
|
||||
"--form-factor", "bare_metal",
|
||||
"--contract-type", "reservation",
|
||||
"--fabric", "infiniband",
|
||||
"--region", "us-east-1",
|
||||
"--json",
|
||||
];
|
||||
const result = runCli(args, {
|
||||
ECC_ITO_CLI_EXECUTABLE: probe.executable,
|
||||
});
|
||||
assert.strictEqual(result.status, 0, result.stderr);
|
||||
assert.deepStrictEqual(readInvocation(probe).argv, [
|
||||
"--json",
|
||||
...args.slice(1, -1),
|
||||
]);
|
||||
} finally {
|
||||
fs.rmSync(probe.directory, { recursive: true, force: true });
|
||||
}
|
||||
}],
|
||||
["passes only the required Itô runtime settings across the process boundary", () => {
|
||||
const probe = makeItoProbe();
|
||||
try {
|
||||
const result = runCli(["ito", "auth"], {
|
||||
ECC_ITO_CLI_EXECUTABLE: probe.executable,
|
||||
ITO_API_KEY: "ito_test_key",
|
||||
ITO_API_URL: "https://compute.example.test",
|
||||
ITO_INVENTORY_URL: "https://edge.example.test",
|
||||
AWS_SECRET_ACCESS_KEY: "must-not-cross",
|
||||
OPENAI_API_KEY: "must-not-cross",
|
||||
TEST_PASSWORD: "must-not-cross",
|
||||
});
|
||||
assert.strictEqual(result.status, 0, result.stderr);
|
||||
const childEnvironment = readInvocation(probe).env;
|
||||
assert.strictEqual(childEnvironment.ITO_API_KEY, "ito_test_key");
|
||||
assert.strictEqual(childEnvironment.ITO_API_URL, "https://compute.example.test");
|
||||
assert.strictEqual(childEnvironment.ITO_INVENTORY_URL, "https://edge.example.test");
|
||||
assert.strictEqual(childEnvironment.AWS_SECRET_ACCESS_KEY, undefined);
|
||||
assert.strictEqual(childEnvironment.OPENAI_API_KEY, undefined);
|
||||
assert.strictEqual(childEnvironment.TEST_PASSWORD, undefined);
|
||||
assert.strictEqual(childEnvironment.ECC_ITO_CLI_EXECUTABLE, undefined);
|
||||
} finally {
|
||||
fs.rmSync(probe.directory, { recursive: true, force: true });
|
||||
}
|
||||
}],
|
||||
["rejects unsupported, browser, simulated, and node operations before spawning", () => {
|
||||
for (const command of ["rent", "lock", "run", "inference", "evals", "mcp"]) {
|
||||
const probe = makeItoProbe();
|
||||
try {
|
||||
const result = runCli(["ito", command], {
|
||||
ECC_ITO_CLI_EXECUTABLE: probe.executable,
|
||||
});
|
||||
assert.notStrictEqual(result.status, 0, command);
|
||||
assert.match(result.stderr, /only auth, find, and status/i);
|
||||
assert.ok(!fs.existsSync(probe.log), `${command} must not spawn the Itô CLI`);
|
||||
} finally {
|
||||
fs.rmSync(probe.directory, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
}],
|
||||
["fails closed rather than simulating a dry-run RFQ", () => {
|
||||
const probe = makeItoProbe();
|
||||
try {
|
||||
const result = runCli(["--dry-run", "ito", "find"], {
|
||||
ECC_ITO_CLI_EXECUTABLE: probe.executable,
|
||||
});
|
||||
assert.notStrictEqual(result.status, 0);
|
||||
assert.match(result.stderr, /no paper or dry-run success mode/i);
|
||||
assert.ok(!fs.existsSync(probe.log));
|
||||
} finally {
|
||||
fs.rmSync(probe.directory, { recursive: true, force: true });
|
||||
}
|
||||
}],
|
||||
["fails closed with exact local install guidance when the explicit CLI is absent", () => {
|
||||
const emptyPath = fs.mkdtempSync(path.join(os.tmpdir(), "ecc-empty-path-"));
|
||||
try {
|
||||
const result = runCli(["ito", "status"], {
|
||||
ECC_ITO_CLI_EXECUTABLE: "",
|
||||
PATH: emptyPath,
|
||||
});
|
||||
assert.notStrictEqual(result.status, 0);
|
||||
assert.match(result.stderr, /canonical ito-compute-cli is unpublished/i);
|
||||
assert.match(result.stderr, new RegExp(CANONICAL_PACKAGE.replaceAll("/", "\\/")));
|
||||
assert.match(result.stderr, /npm run check/);
|
||||
assert.match(result.stderr, /ECC_ITO_CLI_EXECUTABLE/);
|
||||
assert.match(result.stderr, /explicit absolute/i);
|
||||
assert.match(result.stderr, /unpublished/i);
|
||||
assert.doesNotMatch(result.stderr, /npx|npm exec|npm link|install -g/i);
|
||||
} finally {
|
||||
fs.rmSync(emptyPath, { recursive: true, force: true });
|
||||
}
|
||||
}],
|
||||
["never forwards Itô credentials to an unverified PATH collision", () => {
|
||||
const collisionDirectory = fs.mkdtempSync(
|
||||
path.join(os.tmpdir(), "ecc-hostile-ito-path-")
|
||||
);
|
||||
const stolenEnvironment = path.join(collisionDirectory, "stolen.json");
|
||||
const executable = path.join(
|
||||
collisionDirectory,
|
||||
process.platform === "win32" ? "ito.exe" : "ito"
|
||||
);
|
||||
try {
|
||||
fs.writeFileSync(
|
||||
executable,
|
||||
[
|
||||
`#!${process.execPath}`,
|
||||
'"use strict";',
|
||||
'const fs = require("fs");',
|
||||
`fs.writeFileSync(${JSON.stringify(stolenEnvironment)}, JSON.stringify(process.env));`,
|
||||
"",
|
||||
].join("\n")
|
||||
);
|
||||
if (process.platform !== "win32") {
|
||||
fs.chmodSync(executable, 0o755);
|
||||
}
|
||||
|
||||
const result = runCli(["ito", "auth"], {
|
||||
ECC_ITO_CLI_EXECUTABLE: "",
|
||||
ITO_API_KEY: "must-never-reach-path-collision",
|
||||
PATH: collisionDirectory,
|
||||
});
|
||||
|
||||
assert.notStrictEqual(result.status, 0);
|
||||
assert.match(result.stderr, /explicit absolute|ECC_ITO_CLI_EXECUTABLE/i);
|
||||
assert.ok(
|
||||
!fs.existsSync(stolenEnvironment),
|
||||
"an unverified PATH executable must never receive the Itô credential"
|
||||
);
|
||||
} finally {
|
||||
fs.rmSync(collisionDirectory, { recursive: true, force: true });
|
||||
}
|
||||
}],
|
||||
["rejects a relative executable override instead of searching or guessing", () => {
|
||||
const result = runCli(["ito", "status"], {
|
||||
ECC_ITO_CLI_EXECUTABLE: "ito",
|
||||
});
|
||||
assert.notStrictEqual(result.status, 0);
|
||||
assert.match(result.stderr, /must be an absolute path/i);
|
||||
}],
|
||||
["preserves the real CLI exit code and output without a success wrapper", () => {
|
||||
const probe = makeItoProbe(7);
|
||||
try {
|
||||
const result = runCli(["ito", "status"], {
|
||||
ECC_ITO_CLI_EXECUTABLE: probe.executable,
|
||||
});
|
||||
assert.strictEqual(result.status, 7);
|
||||
assert.match(result.stdout, /ito-probe:status/);
|
||||
assert.match(result.stderr, /ito-probe-stderr/);
|
||||
assert.doesNotMatch(result.stdout, /manual_handoff|simulated|paper/i);
|
||||
} finally {
|
||||
fs.rmSync(probe.directory, { recursive: true, force: true });
|
||||
}
|
||||
}],
|
||||
["help exposes the truthful CLI and MCP surface without a browser path", () => {
|
||||
const probe = makeItoProbe();
|
||||
try {
|
||||
const result = runCli(["ito", "--help"], {
|
||||
ECC_ITO_CLI_EXECUTABLE: probe.executable,
|
||||
});
|
||||
assert.strictEqual(result.status, 0, result.stderr);
|
||||
assert.match(result.stdout, /ecc ito auth/);
|
||||
assert.match(result.stdout, /ecc ito find/);
|
||||
assert.match(result.stdout, /ecc ito status/);
|
||||
assert.match(result.stdout, /ito_auth/);
|
||||
assert.match(result.stdout, /ito_find/);
|
||||
assert.match(result.stdout, /ito_status/);
|
||||
assert.match(result.stdout, new RegExp(CANONICAL_PACKAGE.replaceAll("/", "\\/")));
|
||||
assert.match(result.stdout, /unpublished/i);
|
||||
assert.match(result.stdout, /never discovers[^\n]*through PATH/i);
|
||||
assert.doesNotMatch(
|
||||
result.stdout,
|
||||
/manual copy|open(?:s)? (?:a )?browser|ito_lock|ito_run|npm link|paper|simulat/i
|
||||
);
|
||||
assert.ok(!fs.existsSync(probe.log));
|
||||
} finally {
|
||||
fs.rmSync(probe.directory, { recursive: true, force: true });
|
||||
}
|
||||
}],
|
||||
];
|
||||
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
for (const [name, fn] of tests) {
|
||||
if (runTest(name, fn)) passed += 1;
|
||||
else failed += 1;
|
||||
}
|
||||
|
||||
console.log(`\nPassed: ${passed}`);
|
||||
console.log(`Failed: ${failed}`);
|
||||
process.exit(failed > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -61,7 +61,13 @@ function assertHonestComputeCopy(content) {
|
||||
assert.match(content, /preferred compute sponsor/i);
|
||||
assert.match(content, /run or self-host any open-source model/i);
|
||||
assert.match(content, /any GPU provider/i);
|
||||
assert.match(content, /sponsorship link is passive/i);
|
||||
assert.match(content, /ecc ito find/i);
|
||||
assert.match(content, /explicitly configured canonical Itô CLI/i);
|
||||
assert.match(content, /submits a live authenticated RFQ/i);
|
||||
assert.match(content, /does not reserve capacity/i);
|
||||
assert.match(content, /managed inference[^\n.]*not live/i);
|
||||
assert.doesNotMatch(content, /ECC only (?:links|provides this link)/i);
|
||||
}
|
||||
|
||||
function main() {
|
||||
@@ -90,7 +96,7 @@ function main() {
|
||||
assertHonestComputeCopy(readme);
|
||||
assert.match(
|
||||
readme,
|
||||
/custom API endpoint or model gateway[\s\S]*Run or self-host any open-source model behind that gateway[\s\S]*ECC only links to the Itô dashboard/
|
||||
/custom API endpoint or model gateway[\s\S]*Run or self-host any open-source model behind that gateway[\s\S]*sponsorship link is passive/
|
||||
);
|
||||
const sponsorMark = read('assets/images/sponsors/ito.svg');
|
||||
assert.match(sponsorMark, /<path\b/);
|
||||
@@ -100,10 +106,13 @@ function main() {
|
||||
/@import|<script|<foreignObject|\son[a-z]+=|(?:href|xlink:href)=/i
|
||||
);
|
||||
}],
|
||||
['sponsor roster lists Ito alongside business sponsors', () => {
|
||||
['sponsor roster keeps Itô and Moonshot distinct from node tooling', () => {
|
||||
const sponsors = read('SPONSORS.md');
|
||||
assert.ok(sponsors.includes('[**Itô**]'));
|
||||
assert.ok(sponsors.includes('assets/images/sponsors/ito.svg'));
|
||||
assert.ok(sponsors.includes('[**Moonshot AI**]'));
|
||||
assert.ok(sponsors.includes('assets/images/sponsors/moonshot.svg'));
|
||||
assert.doesNotMatch(sponsors, /sixtytwo|sixty.?two/i);
|
||||
assertExactComputeRoute(sponsors);
|
||||
}],
|
||||
['inference guide distinguishes rental compute from managed serving', () => {
|
||||
@@ -113,11 +122,17 @@ function main() {
|
||||
assertHonestComputeCopy(read('.claude-plugin/README.md'));
|
||||
assertHonestComputeCopy(read('.kimi/README.md'));
|
||||
}],
|
||||
['Phase 2 plan keeps its thesis and release framing generic', () => {
|
||||
const plan = read('docs/design/ecc-ito-compute-integration.md');
|
||||
assert.match(plan, /-> any open-source model/);
|
||||
assert.doesNotMatch(plan, /public Kimi|Moonshot|video and sponsorship/i);
|
||||
assert.match(plan, /Status: \*\*Proposed/);
|
||||
['integration record keeps the thesis and real client boundary honest', () => {
|
||||
const record = read('docs/design/ecc-ito-compute-integration.md');
|
||||
assert.match(record, /-> any open-source model/);
|
||||
assert.doesNotMatch(record, /public Kimi|Moonshot|video and sponsorship/i);
|
||||
assert.match(record, /Status: \*\*Implemented local CLI bridge/i);
|
||||
assert.match(record, /auth`, `find`, and `status/);
|
||||
assert.match(record, /ito_auth`, `ito_find`, and `ito_status/);
|
||||
assert.match(record, /unpublished/i);
|
||||
assert.match(record, /managed inference remains unavailable/i);
|
||||
assert.match(record, /version bump[\s\S]*intentionally deferred/i);
|
||||
assert.doesNotMatch(record, /manual_copy|ito\.compute\.handoff|ecc ito rent/i);
|
||||
}],
|
||||
['top-level CLI help exposes the provider-neutral compute route', () => {
|
||||
const result = spawnSync('node', ['scripts/ecc.js', '--help'], {
|
||||
@@ -159,7 +174,12 @@ function main() {
|
||||
assert.ok(packageJson.files.includes('assets/images/sponsors/'));
|
||||
assertExactComputeRoute(packageJson.scripts.welcome);
|
||||
assert.match(packageJson.scripts.welcome, /run or self-host any open-source model/i);
|
||||
assert.match(packageJson.scripts.welcome, /sponsorship link is passive/i);
|
||||
assert.match(packageJson.scripts.welcome, /ecc ito find/i);
|
||||
assert.match(packageJson.scripts.welcome, /submits a live authenticated RFQ/i);
|
||||
assert.match(packageJson.scripts.welcome, /does not reserve capacity/i);
|
||||
assert.ok(fs.existsSync(path.join(REPO_ROOT, 'assets', 'images', 'sponsors', 'ito.svg')));
|
||||
assert.ok(fs.existsSync(path.join(REPO_ROOT, 'assets', 'images', 'sponsors', 'moonshot.svg')));
|
||||
}],
|
||||
];
|
||||
|
||||
|
||||
@@ -1,294 +0,0 @@
|
||||
/**
|
||||
* End-to-end contract tests for ECC's read-only Itô compute handoff.
|
||||
*/
|
||||
|
||||
const assert = require("assert")
|
||||
const fs = require("fs")
|
||||
const os = require("os")
|
||||
const path = require("path")
|
||||
const { spawnSync } = require("child_process")
|
||||
|
||||
const REPO_ROOT = path.join(__dirname, "..", "..")
|
||||
const ECC_SCRIPT = path.join(REPO_ROOT, "scripts", "ecc.js")
|
||||
const ITO_SCRIPT = path.join(REPO_ROOT, "scripts", "ito.js")
|
||||
const DESK_URL = "https://compute.itomarkets.com/desk"
|
||||
|
||||
function runCli(args, options = {}) {
|
||||
return spawnSync(process.execPath, [ECC_SCRIPT, ...args], {
|
||||
cwd: REPO_ROOT,
|
||||
encoding: "utf8",
|
||||
env: {
|
||||
...process.env,
|
||||
NODE_ENV: "test",
|
||||
...(options.env || {}),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
function parseJson(result, expectedStatus = 0) {
|
||||
assert.strictEqual(result.status, expectedStatus, result.stderr)
|
||||
return JSON.parse(result.stdout)
|
||||
}
|
||||
|
||||
function runTest(name, fn) {
|
||||
try {
|
||||
fn()
|
||||
console.log(` ✓ ${name}`)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.log(` ✗ ${name}`)
|
||||
console.error(` ${error.message}`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
function makeBrowserProbe() {
|
||||
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "ecc-ito-browser-"))
|
||||
const log = path.join(dir, "opened-url.txt")
|
||||
const envLog = path.join(dir, "browser-env.txt")
|
||||
const executable = path.join(dir, process.platform === "win32" ? "browser-probe.cmd" : "browser-probe")
|
||||
if (process.platform === "win32") {
|
||||
fs.writeFileSync(executable, `@echo off\r\n<nul set /p =%1>"${log}"\r\nset >"${envLog}"\r\n`)
|
||||
} else {
|
||||
fs.writeFileSync(executable, `#!/bin/sh\nprintf '%s' "$1" > "${log}"\nenv > "${envLog}"\n`)
|
||||
fs.chmodSync(executable, 0o755)
|
||||
}
|
||||
return { dir, envLog, executable, log }
|
||||
}
|
||||
|
||||
function main() {
|
||||
console.log("\n=== Testing ECC × Itô sandbox handoff ===\n")
|
||||
|
||||
const tests = [
|
||||
["maps the exact CLI request into a structured sandbox intent", () => {
|
||||
const payload = parseJson(runCli([
|
||||
"ito",
|
||||
"rent",
|
||||
"--accelerator", "h100",
|
||||
"--count", "1",
|
||||
"--hours", "24",
|
||||
"--no-open",
|
||||
"--json",
|
||||
]))
|
||||
|
||||
assert.strictEqual(payload.schemaVersion, "ito.compute.handoff.v1")
|
||||
assert.strictEqual(payload.success, true)
|
||||
assert.strictEqual(payload.state, "manual_handoff")
|
||||
assert.deepStrictEqual(payload.data.intent, {
|
||||
accelerator: "h100",
|
||||
count: 1,
|
||||
hours: 24,
|
||||
})
|
||||
assert.deepStrictEqual(payload.data.provenance, {
|
||||
source: "ecc-cli",
|
||||
command: "ecc ito rent",
|
||||
})
|
||||
assert.strictEqual(payload.data.authority.environment, "sandbox")
|
||||
assert.strictEqual(payload.data.authority.readOnly, true)
|
||||
assert.strictEqual(payload.data.authority.liveRfq, false)
|
||||
assert.strictEqual(payload.data.authority.procurementMutation, false)
|
||||
assert.strictEqual(payload.data.authority.quoteAcceptance, false)
|
||||
assert.strictEqual(payload.data.authority.fundsApproval, false)
|
||||
assert.strictEqual(payload.data.authority.orderCreation, false)
|
||||
assert.strictEqual(payload.data.handoff.transport, "manual_copy")
|
||||
assert.strictEqual(payload.data.handoff.destination, "ito-desk")
|
||||
assert.strictEqual(payload.data.handoff.acceptedByIto, false)
|
||||
assert.strictEqual(payload.data.handoff.signInMayBeRequired, true)
|
||||
assert.match(payload.data.handoff.message, /1 × H100/)
|
||||
assert.match(payload.data.handoff.message, /24 hours/)
|
||||
assert.match(payload.data.handoff.message, /ECC CLI/)
|
||||
assert.match(payload.data.handoff.message, /sandbox-only/)
|
||||
assert.strictEqual(payload.links.desk, DESK_URL)
|
||||
assert.strictEqual(payload.data.opened, false)
|
||||
assert.strictEqual(payload.data.priceQuote, null)
|
||||
assert.strictEqual(payload.data.orderId, null)
|
||||
}],
|
||||
["global dry-run emits the same handoff and never opens a browser", () => {
|
||||
const probe = makeBrowserProbe()
|
||||
try {
|
||||
const payload = parseJson(runCli([
|
||||
"--dry-run",
|
||||
"ito",
|
||||
"rent",
|
||||
"--accelerator", "h100",
|
||||
"--count", "1",
|
||||
"--hours", "24",
|
||||
"--json",
|
||||
], {
|
||||
env: { ECC_ITO_BROWSER_EXECUTABLE: probe.executable },
|
||||
}))
|
||||
|
||||
assert.strictEqual(payload.data.dryRun, true)
|
||||
assert.strictEqual(payload.data.opened, false)
|
||||
assert.ok(!fs.existsSync(probe.log), "dry-run must not invoke the browser executable")
|
||||
} finally {
|
||||
fs.rmSync(probe.dir, { recursive: true, force: true })
|
||||
}
|
||||
}],
|
||||
["local dry-run is equivalent and rejects an open request", () => {
|
||||
const probe = makeBrowserProbe()
|
||||
try {
|
||||
const payload = parseJson(runCli([
|
||||
"ito",
|
||||
"rent",
|
||||
"--accelerator", "h100",
|
||||
"--count", "1",
|
||||
"--hours", "24",
|
||||
"--dry-run",
|
||||
"--json",
|
||||
], {
|
||||
env: { ECC_ITO_BROWSER_EXECUTABLE: probe.executable },
|
||||
}))
|
||||
|
||||
assert.strictEqual(payload.data.dryRun, true)
|
||||
assert.strictEqual(payload.data.opened, false)
|
||||
assert.ok(!fs.existsSync(probe.log), "local dry-run must not invoke the browser executable")
|
||||
} finally {
|
||||
fs.rmSync(probe.dir, { recursive: true, force: true })
|
||||
}
|
||||
}],
|
||||
["browser handoff opens only the allowlisted desk URL without inherited secrets", () => {
|
||||
const probe = makeBrowserProbe()
|
||||
try {
|
||||
const payload = parseJson(runCli([
|
||||
"ito",
|
||||
"rent",
|
||||
"--accelerator", "h100",
|
||||
"--count", "1",
|
||||
"--hours", "24",
|
||||
"--json",
|
||||
], {
|
||||
env: {
|
||||
ECC_ITO_BROWSER_EXECUTABLE: probe.executable,
|
||||
ITO_API_KEY: "parent-api-key-must-not-cross",
|
||||
ITO_SERVICE_TOKEN: "parent-token-must-not-cross",
|
||||
TEST_PASSWORD: "parent-password-must-not-cross",
|
||||
},
|
||||
}))
|
||||
|
||||
assert.strictEqual(payload.data.opened, true)
|
||||
assert.strictEqual(fs.readFileSync(probe.log, "utf8"), DESK_URL)
|
||||
assert.strictEqual(payload.links.desk, DESK_URL)
|
||||
const childEnvironment = fs.readFileSync(probe.envLog, "utf8")
|
||||
assert.doesNotMatch(childEnvironment, /parent-api-key-must-not-cross/)
|
||||
assert.doesNotMatch(childEnvironment, /parent-token-must-not-cross/)
|
||||
assert.doesNotMatch(childEnvironment, /parent-password-must-not-cross/)
|
||||
} finally {
|
||||
fs.rmSync(probe.dir, { recursive: true, force: true })
|
||||
}
|
||||
}],
|
||||
["direct Ito execution strips secrets from the browser child", () => {
|
||||
const probe = makeBrowserProbe()
|
||||
try {
|
||||
const result = spawnSync(process.execPath, [
|
||||
ITO_SCRIPT,
|
||||
"rent",
|
||||
"--accelerator", "h100",
|
||||
"--count", "1",
|
||||
"--hours", "24",
|
||||
"--json",
|
||||
], {
|
||||
cwd: REPO_ROOT,
|
||||
encoding: "utf8",
|
||||
env: {
|
||||
...process.env,
|
||||
NODE_ENV: "test",
|
||||
ECC_ITO_BROWSER_EXECUTABLE: probe.executable,
|
||||
ITO_API_KEY: "direct-api-key-must-not-cross",
|
||||
ITO_SERVICE_TOKEN: "direct-token-must-not-cross",
|
||||
TEST_PASSWORD: "direct-password-must-not-cross",
|
||||
},
|
||||
})
|
||||
const payload = parseJson(result)
|
||||
assert.strictEqual(payload.data.opened, true)
|
||||
const childEnvironment = fs.readFileSync(probe.envLog, "utf8")
|
||||
assert.doesNotMatch(childEnvironment, /direct-api-key-must-not-cross/)
|
||||
assert.doesNotMatch(childEnvironment, /direct-token-must-not-cross/)
|
||||
assert.doesNotMatch(childEnvironment, /direct-password-must-not-cross/)
|
||||
} finally {
|
||||
fs.rmSync(probe.dir, { recursive: true, force: true })
|
||||
}
|
||||
}],
|
||||
["fails closed on missing, unsupported, duplicate, and out-of-range intent", () => {
|
||||
for (const args of [
|
||||
["ito", "rent", "--count", "1", "--hours", "24", "--no-open", "--json"],
|
||||
["ito", "rent", "--accelerator", "a100", "--count", "1", "--hours", "24", "--no-open", "--json"],
|
||||
["ito", "rent", "--accelerator", "h100", "--count", "0", "--hours", "24", "--no-open", "--json"],
|
||||
["ito", "rent", "--accelerator", "h100", "--count", "1", "--hours", "721", "--no-open", "--json"],
|
||||
["ito", "rent", "--accelerator", "h100", "--accelerator", "h100-sxm", "--count", "1", "--hours", "24", "--no-open", "--json"],
|
||||
["ito", "dashboard", "--accelerator", "h100", "--count", "1", "--hours", "24", "--no-open", "--json"],
|
||||
]) {
|
||||
const result = runCli(args)
|
||||
assert.notStrictEqual(result.status, 0, args.join(" "))
|
||||
const payload = JSON.parse(result.stdout)
|
||||
assert.strictEqual(payload.success, false)
|
||||
assert.strictEqual(payload.state, "invalid_request")
|
||||
assert.strictEqual(payload.data, null)
|
||||
assert.strictEqual(payload.error.code, "INVALID_ARGUMENT")
|
||||
}
|
||||
}],
|
||||
["does not inspect credentials or contain a mutating transport", () => {
|
||||
const payload = parseJson(runCli([
|
||||
"ito",
|
||||
"rent",
|
||||
"--accelerator", "h100",
|
||||
"--count", "1",
|
||||
"--hours", "24",
|
||||
"--no-open",
|
||||
"--json",
|
||||
], {
|
||||
env: {
|
||||
ITO_API_KEY: "must-not-be-read",
|
||||
ITO_SERVICE_TOKEN: "must-not-be-read",
|
||||
},
|
||||
}))
|
||||
|
||||
assert.strictEqual(payload.data.authenticated, null)
|
||||
const source = fs.readFileSync(path.join(REPO_ROOT, "scripts", "ito.js"), "utf8")
|
||||
assert.doesNotMatch(source, /ITO_API_KEY|ITO_SERVICE_TOKEN|procurement\/orders|authorization/i)
|
||||
assert.doesNotMatch(source, /\bfetch\s*\(|https?\.request|child_process\.exec\b/)
|
||||
}],
|
||||
["human output stops before the economic boundary", () => {
|
||||
const result = runCli([
|
||||
"ito",
|
||||
"rent",
|
||||
"--accelerator", "h100",
|
||||
"--count", "1",
|
||||
"--hours", "24",
|
||||
"--no-open",
|
||||
])
|
||||
|
||||
assert.strictEqual(result.status, 0, result.stderr)
|
||||
assert.match(result.stdout, /manual copy/i)
|
||||
assert.match(result.stdout, /sandbox-only/i)
|
||||
assert.match(result.stdout, /sign-in may be required/i)
|
||||
assert.doesNotMatch(result.stdout, /signed-in/i)
|
||||
assert.match(result.stdout, /does not file an RFQ/i)
|
||||
assert.match(result.stdout, /Stop before ["“]Pay & buy["”]/i)
|
||||
assert.match(result.stdout, /no supported structured ECC intake/i)
|
||||
}],
|
||||
["npm welcome remains POSIX-safe around apostrophes", () => {
|
||||
const npmExecutable = process.platform === "win32" ? "npm.cmd" : "npm"
|
||||
const result = spawnSync(npmExecutable, ["run", "welcome"], {
|
||||
cwd: REPO_ROOT,
|
||||
encoding: "utf8",
|
||||
shell: process.platform === "win32",
|
||||
})
|
||||
assert.strictEqual(result.status, 0, result.stderr)
|
||||
assert.match(result.stdout, /Itô/)
|
||||
}],
|
||||
]
|
||||
|
||||
let passed = 0
|
||||
let failed = 0
|
||||
for (const [name, fn] of tests) {
|
||||
if (runTest(name, fn)) passed += 1
|
||||
else failed += 1
|
||||
}
|
||||
|
||||
console.log(`\nPassed: ${passed}`)
|
||||
console.log(`Failed: ${failed}`)
|
||||
process.exit(failed > 0 ? 1 : 0)
|
||||
}
|
||||
|
||||
main()
|
||||
@@ -50,6 +50,11 @@ def test_ollama_notice_routes_to_ito_without_claiming_serving(capsys):
|
||||
assert_exact_compute_route(output)
|
||||
assert "preferred compute sponsor" in output
|
||||
assert "Any GPU provider works" in output
|
||||
assert "sponsorship link is passive" in output
|
||||
assert "ecc ito find" in output
|
||||
assert "explicitly configured canonical Itô CLI" in output
|
||||
assert "submits a live authenticated RFQ" in output
|
||||
assert "does not reserve capacity" in output
|
||||
assert "Managed inference through Itô is not live yet" in output
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user