@candledottv/cli 0.13.19 → 0.13.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -1
- package/dist/index.js +44110 -42808
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -135,9 +135,11 @@ chosen words from your saved copy. Clear your terminal's scrollback too: the CLI
|
|
|
135
135
|
| `candle tee signer remove --key <prefix\|label>` | Removes this machine's key signer once it owns no wallets, and tells the server the signer is gone. Refuses while a wallet is still owned by it. Uses the device token, or the key's own API key. |
|
|
136
136
|
| `candle tee rebind <wallet...> --to-key <prefix\|label>`, `candle tee rebinds [wallet]` | Move TEE wallets to another key on the same account (owner only, preview then `confirm`; funds and the relay signer do not move), and list the rebind history, filtered to one wallet by its id, address or exact label. |
|
|
137
137
|
| `candle tee rename <label\|address\|id> <new-label>`, `candle tee rename --pairs-from <file> [--dry-run]` | Rename one TEE wallet, or 1–256 from a pairs file: the label Candle holds and the vault entry when there is one (owner only; one server call, all or nothing, then one vault commit). |
|
|
138
|
+
| `candle tee check <address\|id\|label>... [--label-prefix <p>] [--sign] [--max <n>] [--rpc-url <url>]` | Check, without spending, that each named TEE wallet can really trade: payable membership, wallet record parity against the swap's own listing, and this machine's signer. `--label-prefix` selects wallets by label, `--json` prints one object per run with each wallet's `checks` and a `summary`, and the exit code is 1 when any check fails. `--sign` also builds a tiny SOL/USDC quote, checks its spend, requests a relay signature, verifies it locally and simulates; it never broadcasts, is capped at `--max` wallets (default 10) and needs `swap:write` |
|
|
138
139
|
| `candle tee new\|enable` | `new` adds a key to an existing `tee-wallets.enc` and refuses when that store is absent (`vault new-key --chain solana`, then `vault promote --from <label> --to-key <prefix>`). `--factor` does not apply. `enable <address> --vault <address>` delegates an existing key with a pinned sweep vault. `vault import-legacy --tee` migrates an existing store. |
|
|
139
|
-
| `candle swap <from> <to> --amount <n>\|--percent <n> --wallet <tee> [--to <tee>] [--wait]` | Quote, confirm and swap through the TEE wallet's bound key; the first buy after a launch is this command, unless `candle launch --buy` made it. The assets decide the chain (ETH, USDG or a 0x token is Hood; SOL, USDC, CNDL or a mint is Solana). SOL or USDC to ETH or USDG, or back, is a bridge through Relay into this key's own TEE wallet on the other chain (`--to` names it when there are several); `--wait` follows it for up to ten minutes. With `--json`, stdout is exactly one JSON value for swaps, token trades, replays and `swap status`: `kind`, `status`, `clientTradeId`, `signature` (the primary transaction, or `null`), `signatures` (a list) and `raw` (the original response). Every human line is on stderr. The keys older versions printed stay beside them. |
|
|
140
|
+
| `candle swap <from> <to> --amount <n>\|--percent <n> --wallet <tee> [--to <tee>] [--wait] [--dry-run]` | Quote, confirm and swap through the TEE wallet's bound key; the first buy after a launch is this command, unless `candle launch --buy` made it. The assets decide the chain (ETH, USDG or a 0x token is Hood; SOL, USDC, CNDL or a mint is Solana). SOL or USDC to ETH or USDG, or back, is a bridge through Relay into this key's own TEE wallet on the other chain (`--to` names it when there are several); `--wait` follows it for up to ten minutes. With `--json`, stdout is exactly one JSON value for swaps, token trades, replays and `swap status`: `kind`, `status`, `clientTradeId`, `signature` (the primary transaction, or `null`), `signatures` (a list) and `raw` (the original response). Every human line is on stderr. The keys older versions printed stay beside them. `--dry-run` (Solana TEE payer only) checks the wallet, builds the quote and checks its spend, then stops: it never signs, sends, prompts or saves an operation, refuses `--yes`, `--percent` and `--client-trade-id`, and refuses embedded, Hood and bridge payers. With `--json` stdout is the per-check results and the quote. |
|
|
140
141
|
| `candle swap status <id> [--kind trade\|swap\|launch] [--wait]` | Read an operation without resending it; `--wait` follows a bridge until it ends. |
|
|
142
|
+
| `candle swap receipt <hash>` / `candle swap receipt --client-swap-id <id>` | Re-read a one-shot swap's settlement from chain (a swap this key made through MCP or the SDK, not a `candle swap`); reads only, never resends. The `--client-swap-id` form reads the swap's row first and its receipt only when the row is `confirmed`. With `--json`, stdout is the hash form's `{ success, settlement }` or the id form's object with `receipt` (`read`, `no_hash`, `not_written`, `not_found`) and `next`. A human line on stderr says `settled <amount> <asset>` (the hash form prints raw units), or `Settlement: <state>` with `(refunded)`, `(refunded, Relay fallback)` or `(Relay failure)` when Relay failed the bridge. Exit 0 on any read answer, 1 on an API error (a hash this key did not broadcast is `RECEIPT_NOT_FOUND`), 2 on usage. Poll no faster than every 15 seconds. |
|
|
141
143
|
| `candle transfer --to <address\|wallet name\|allowlist label\|vault> --asset <SOL\|USDC\|CNDL\|ETH\|USDG>\|--mint <mint>\|--token <0x...> --amount <decimal\|max> [--wallet <tee>] [--client-id <id>] [--rpc-url <url>] [--yes]` | Move funds out of a TEE wallet through its bound Withdraw key, to the wallet's own pinned vault (`--to vault`, any token, `max` allowed, one SOL transfer at most the server's backstop ceiling, 50 SOL by default) or to another of the account's wallets you linked while signed in or marked trusted (a base asset, counted against the key's caps, which must include a per-asset cap and a USD `--tx-limit`). Where the server has `TEE_WITHDRAWALS_ENABLED` on (it ships off), also to an address on the account's withdrawal allowlist, named by its label, id or address, with the same base-asset rule. The asset decides the chain: ETH, USDG or `--token` moves from a Hood TEE wallet. The destination and its kind are shown before you confirm; Candle builds, the relay signs, Candle broadcasts. `--client-id <id>` (1 to 128 of letters, digits, `.` `_` `:` `-`) names the transfer yourself: reusing an id for a transfer already built or sent is `IDEMPOTENCY_CONFLICT` naming that transfer, so a retry never sends twice. |
|
|
142
144
|
| `candle transfer status <transfer id\|client id> [--json]` | Where a transfer stands, by the id the build returned or the `--client-id` it was sent under: `built` (signable until `expiresAt`), `expired`, `submitted` with its `signature`, `unconfirmed` (may still land; check the chain or `candle activity` before using a new client id), or `failed`. Candle keeps the answer for 24 hours; an older transfer is in `candle activity`. An unknown id is `JOB_NOT_FOUND`. |
|
|
143
145
|
| `candle launch --name <name> --symbol <symbol> --image <path>\|--image-url <url> --wallet <tee>\|embedded [--banner <file\|URL>] [--description <text>] [--website <url>] [--x <url>] [--telegram <url>] [--discord <url>] [--buy <amount>] [--quote-asset <asset>] [--dex-version v3\|v4] [--mode <mode>] [--curve-v <V> --curve-g <G>] [--creator-fee-bps 0\|100\|200] [--staker-allocation-bps <bps>] [--visibility production\|test\|local\|hidden] [--pool-fee 25\|50\|100] [--pool-fee-from <bps> --pool-fee-minutes <min>] [--pool-open legacy\|curve_price] [--exp-pool-shape floor\|full_range] [--fee-wallet <address>\|--fee-wallet-multisig <address> [--fee-wallet-multisig-vault-index <n>]] [--require-fee-wallet] [--open-in <duration>] [--max-buy-per-wallet <amount> --cap-window <duration>] [--allowlist <path> --allowlist-window <duration>] [--dev-buy-max <amount>] [--dry-run] [--check] [--client-trade-id <id>] [--yes]` | Create a token from the named wallet, with an optional first buy. `--wallet embedded` (or `main`) uses `/launch/headless` on Solana or Hood, with or without `--buy`; every plan can use it with `launch:write` and the key's embedded-wallet allowance, without `swap:write`. It previews through `/launch/headless/dry-run`, shows the quote for confirmation, then sends one headless request. A Solana buy is a creator bundle signed by Candle, preserving `bundleId` in the result; a Hood buy is best effort after creation. The server's slippage floor applies; there is no separate CLI build-floor comparison. TEE wallets use `/launch/self` and need Pro or Max, `launch:write`, the bound key and verified signing authority; a server with `TEE_LAUNCH_BY_SCOPE_ENABLED` off also asks for the owner's `allowLaunch` (deprecated). A TEE first buy needs `TEE_LAUNCH_BUYS_ENABLED` (off by default), and with `TEE_LAUNCH_BY_SCOPE_ENABLED` on it also needs `swap:write` (a key without it gets `SCOPE_MISSING`); Solana creator buys also need `AGENT_TRADING_ENABLED` and a configured Jito engine. No gate or plan default changes. `--buy` is a decimal in whole quote units (SOL/USDC/CNDL on Solana, ETH on Hood; USDG has no first buy); zero or empty means no buy. A Hood launch needs `--dex-version v3\|v4`. `--description` and the four absolute http(s) socials flags travel with every preview/build: `--x` maps to `socials.twitter`. `--staker-allocation-bps` accepts 50–1000; `--visibility` is production, test, local or hidden (test keys need test or hidden). `--mode exp-custom` needs `--curve-v` and `--curve-g` in whole quote units; ranges and common help come from the shared launch definition and appear in `candle launch --help`. `--pool-fee` sets the Solana graduated pool fee (default 50 bps); `--pool-fee-from` and `--pool-fee-minutes` add a fall to that rate. Preset `--pool-open curve_price` opens at the curve's last price and burns the rest; omitted it applies when allocations fit `graduation.maxStakerCarveBps`, otherwise falls back to legacy. Exp `--exp-pool-shape` is floor or full_range. `--image-url` is https; `--image` uploads a local PNG/JPEG/GIF/WebP up to 10MB. `--banner` takes a wide local file or https URL. Uploads are public and permanent before confirmation, even on a dry run or decline. `--dry-run` stops at the preview without claiming the launch id. Reuse `--client-trade-id` for recovery, and always pass `--json` in scripts. `--check` answers which launch path works before any of it, in one call (`GET /api/v1/launch/preflight`): the key's tier and embedded-wallet allowance, each bound TEE wallet's allowLaunch (served `true` where the server has `TEE_LAUNCH_BY_SCOPE_ENABLED` on) and verified-active state, and the server's `TEE_LAUNCH_BY_SCOPE_ENABLED`, `TEE_LAUNCH_BUYS_ENABLED` and `AGENT_TRADING_ENABLED` switches. No name, symbol or image is needed, nothing is uploaded or sent, `--wallet <name>` narrows the answer to one wallet, and it exits 1 when no launch path works. On Solana, where the server has `CURVE_LAUNCH_RULES_ENABLED` on, launch rules are fixed at launch and enforced by the curve program: `--open-in` delays the open (until then only the launching wallet may buy, up to `--dev-buy-max`, which defaults to `--buy`), `--max-buy-per-wallet` with `--cap-window` caps what each wallet spends on the curve after the open, and `--allowlist <path>` (one address per line, or comma separated, at most 4,096) with `--allowlist-window` lets only the listed wallets buy. Durations are seconds or `90m`, `6h`, `2d` (the open at most 7 days away, each window at most 24 hours); amounts are whole quote units. The CLI checks each value before any request with the API's bounds, sends the request's nested `launchRules` in raw units, and the preview prints a Launch rules block from the API's answer. Nobody can change the rules after the launch. |
|
|
@@ -146,6 +148,7 @@ chosen words from your saved copy. Clear your terminal's scrollback too: the CLI
|
|
|
146
148
|
| `candle pnl [--profile <name>]` | P&L: realized net, fees, unrealized and total, then open positions, the same figures the console shows. Without `--profile`, the account's books (every profile, the web app and the CLI, one ledger; needs the Read scope), with a By agent table (each key, then Manual, then the account total). With `--profile <name>`, that profile's key's share of the same P&L: realized on its sales and the open positions that belong to it, with a row per wallet that sums to the total. Each wallet is its own average-cost pool, and a recorded move between the account's wallets carries its cost. Both show a Solana block, a Hood block, then the combined figure, the closed positions as money made, minus money lost, plus partial sells, and a `CHAIN` column (and `WALLET`, where the API names it) on positions. Unpriced positions are never valued at zero; dust (worth under one cent) is marked and still counted. A bridge between Solana and Hood is not a trade, and bridge and Relay costs are not netted. DAMM v2 LP positions are included: realized (withdrawals against the cost basis at the add, plus claimed fees), unrealized (open positions at their share of the pool plus unclaimed fees, against that basis) and vs holding (what the deposited tokens would be worth held); `Total` stays the console's token figure and `Total with LP` covers tokens and LP. |
|
|
147
149
|
| `candle portfolio [<filter>] [--chain solana\|hood] [--rpc-url <url>] [--evm-rpc-url <url>] [--no-perps] [--no-vault]` | Vault, TEE and embedded wallets on Solana and Hood in one table with chain, amount, price and value, subtotals per group and per chain, and a total. Solana vault and external balances are read over your own Solana RPC; Candle is sent only the mints, for prices. EVM vault keys are read over your own Hood RPC (`--evm-rpc-url`, else `CANDLE_EVM_RPC_URL`, else the built-in Hood RPC) for ETH and USDG only, priced by asset, never by address; an RPC on another chain is refused. An unpriced Hood token shows why (`no-market-row`, `stale-mark`, ...). `--chain` shows one chain. Each TEE wallet's DAMM v2 LP positions follow the tokens, valued by Candle at the same marks, and count in the total; one whose pool could not be read is shown as not read and the total says it is partial. A Hyperliquid section follows (each EVM TEE wallet's account, read from Hyperliquid directly, never in the total); `--no-perps` skips it. It needs no terminal: without one, `--factor touch-id` or `passkey` still unlocks the vault, and otherwise the vault row says not read and the rest is shown, but the total is partial (exit 3); `--no-vault` leaves the vault out on purpose and may exit 0. |
|
|
148
150
|
| `candle scan <contract address> [--chain solana\|hood]` | The token card for one contract, as a Quant group gets it: market, all-time high since launch, bundles, snipers, insiders, fresh wallets, wallet age, tracked wallets in the last hour, the same-name leader, forensics coverage and the Candle page, with the source of each figure. Facts only; a field with no source prints a dash. The chain is read from the address unless `--chain` names it. No key needed and none sent. Served only where `TOKEN_CARD_ENABLED` is on, and `TOKEN_CARD_DISABLED` elsewhere. |
|
|
151
|
+
| `candle token forensics <mint> [--chain solana\|hood] [--wallet <vault key>] [--yes]` | The pre-buy forensics report: deployer history, deploy-window buyers, `coverage` and `safety`. No key needed; a configured API key is sent. On Hood that key also lets the report carry hacc's EVM contract safety (`safety.evm`), read and charged on the key's own hacc research plan; with only a device token a Hood report reads `no_key`. Past the free rate with x402 per-use on, Candle's per-use price is drawn from the key's account credit or paid from the vault, separately from hacc's research credits. |
|
|
149
152
|
| `candle token clusters <mint> [--chain solana\|hood]` | Optional third-party Solana cluster estimates, with fetched time and a linked-wallet caveat. Unavailable analysis prints a reason and exits 0; `--json` emits the availability union. No key. |
|
|
150
153
|
| `candle token edit <mint> [--chain solana\|hood] [--description <text>] [--website <url>] [--x <url>] [--telegram <url>] [--discord <url>] [--clear <field>]...` | As the token's creator, set Candle's copy of its description and links; `--clear` removes one. Name, symbol and image cannot be changed, and nothing is written on chain. Needs a `launch:write` key from the launching account. Served only where `TOKEN_METADATA_EDIT_ENABLED` is on, and `METADATA_EDIT_DISABLED` elsewhere. |
|
|
151
154
|
| `candle token history <mint> [--chain solana\|hood]` | The token's metadata edits, newest first. Public; no key sent. |
|
|
@@ -233,6 +236,17 @@ table above) runs the same check against the trusted root compiled into the bina
|
|
|
233
236
|
call required. It is also what `install.sh` uses on a machine with neither. Full walkthrough, including the installer script's own signature and the
|
|
234
237
|
transparency log: [Verify a Candle release](https://docs.candle.tv/developers/verify-a-candle-release).
|
|
235
238
|
|
|
239
|
+
## Browser confirm for owner steps
|
|
240
|
+
|
|
241
|
+
Where the API has `OWNER_CONFIRM_ENABLED` on, an owner step made with the device token that widens what the account's keys can do also needs one approval in your browser, signed in as the account owner. The API answers `403 OWNER_CONFIRM_REQUIRED` and changes nothing; the CLI then:
|
|
242
|
+
|
|
243
|
+
1. Prints what you are approving (a summary the server built), `Open <url>` and `Code: XXXX-XXXX` on stderr, with "Only approve if you just ran this command." It opens the browser only with `--open`. Under `--json` it writes one line to stderr instead, `{"ok":false,"pending":true,"code":"OWNER_CONFIRM_REQUIRED","ownerConfirm":{"userCode","verificationUriComplete","expiresIn","step","summary"}}`, and keeps stdout for the final result.
|
|
244
|
+
2. Waits, polling every few seconds. The code expires 5 minutes after it was issued.
|
|
245
|
+
3. When you approve at `/dev/agent/confirm`, sends the identical request again and prints its result. Deny it and the command exits 1 with `Denied in the browser; nothing changed.`; let it expire and it exits 1 with `The confirmation expired; nothing changed. Run the command again.`
|
|
246
|
+
4. With `--no-wait` it prints the code and exits 7 without waiting. The command does not resume later: run it again without `--no-wait`, or make the change in the console.
|
|
247
|
+
|
|
248
|
+
One approval covers exactly one request, from this device, for this account. The steps that ask for it: `keys create` (every key, a read-only one included), `keys rotate`, `keys access` when it widens, `keys update --embedded-wallet allow`, `auth login --embedded-wallet allow` when it allows the new key the embedded wallet, `keys signer approve` (not `--reject`), `tee rebind` (not the preview), `wallets allow-launch`, `vault promote --to-key` (one approval per wallet), `keys limit` when it raises, clears or changes the window of a transaction limit, `perps thresholds set` and `clear` when they loosen, and `perps reduce-only off`. The Candle Harness shows the same summary, URL and code when its core mints a key. Narrowing steps never ask: revoking or stopping a key, narrowing access, `rotate --finish`, tightening a limit, `reduce-only on`. An older CLI prints the server's message, which carries the URL and code, but cannot finish the step: update the CLI before this is on. A signed-in console session never sees the confirm.
|
|
249
|
+
|
|
236
250
|
## The `--json` contract
|
|
237
251
|
|
|
238
252
|
For agents and scripts, `--json` guarantees: **stdout carries exactly one JSON value** -- the
|
|
@@ -642,3 +656,61 @@ for the complete contract.
|
|
|
642
656
|
During the verifier upgrade, rotation and finish may return retryable 503 with reason
|
|
643
657
|
`rotation_verifier_not_ready` before changing any credential. Keep the existing secret
|
|
644
658
|
and retry after the service is ready; the API does not silently shorten the grace guarantee.
|
|
659
|
+
|
|
660
|
+
## Uncertain Hood legs (BE-3072)
|
|
661
|
+
|
|
662
|
+
On Hood, when a leg's receipt is not confirmed, the CLI reports `LEG_UNCONFIRMED` (exit 3), keeps the
|
|
663
|
+
hash it computed from its own signed bytes, and tells you not to repeat the trade and to read
|
|
664
|
+
`candle swap status <id> --kind trade`. A revert exits 1 before the trade leg succeeded and 3 after.
|
|
665
|
+
`No leg landed` is no longer printed on an empty list: it was never negative evidence; the CLI says
|
|
666
|
+
`No leg is confirmed yet`. JSON output keeps `legEvidence`, `reconciliation`, `recoveryRequired`,
|
|
667
|
+
`safeAction` and `pollAfterMs` from the server. Status makes no signing or send calls.
|
|
668
|
+
|
|
669
|
+
## Legacy Hood leg recovery and readable guards
|
|
670
|
+
|
|
671
|
+
A `WALLET_BUSY` refusal names the guarded `operationId`, rail (`operationKind`), client `refId`,
|
|
672
|
+
leg, fixed `reason`, `clearingCondition`, `statusPath` and `statusCommand`. An operation id is
|
|
673
|
+
separate from a rail's client id:
|
|
674
|
+
|
|
675
|
+
```sh
|
|
676
|
+
candle swap status --operation <operationId>
|
|
677
|
+
candle swap recover --operation <operationId> --hash <0x-transaction-hash>
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
`GET /api/v1/agent/hood-tee/operations/{operationId}` and
|
|
681
|
+
`POST /api/v1/agent/hood-tee/operations/{operationId}/recover` return
|
|
682
|
+
`{ success: true, operation: { ..., guard?, recovery? } }`. The POST body accepts only
|
|
683
|
+
`{ candidateHash?: string }`. A locator names a transaction to verify; it never proves identity.
|
|
684
|
+
Both paths use the account's owning rail scope (`swap:write`, `launch:read`, or `transfer:write`);
|
|
685
|
+
swap operations also require the key that placed them. An unauthorized lookup returns the same
|
|
686
|
+
404 `JOB_NOT_FOUND` as an unknown id. Recovery inside an active window returns 409
|
|
687
|
+
`OPERATION_ACTIVE`, retryable true. Reads and recovery work while the trading switch is off.
|
|
688
|
+
|
|
689
|
+
Legacy recovery reconstructs the exact signed type-2 envelope and verifies its hash, signer and
|
|
690
|
+
historical Candle stamp before recording an exact-hash receipt. It needs no client-held bytes.
|
|
691
|
+
It never signs, sends, rebroadcasts, restamps, returns a next leg, collects fees or revives the
|
|
692
|
+
operation. Failed/expired parents and unattempted planned legs keep their labels. Proving one
|
|
693
|
+
leg keeps every other unresolved leg held. A nonce count, elapsed time, missing transaction,
|
|
694
|
+
allowance or terminal job label cannot clear a hold. `not_sent` requires positive bound claim
|
|
695
|
+
proof that signing cannot have happened or happen later; pending/ambiguous claims remain held.
|
|
696
|
+
|
|
697
|
+
While `guard.recoveryRequired` is true, read status and follow `clearingCondition`. CLI status and
|
|
698
|
+
recover exit 3 while held. `legacy_identity_missing` can accept a locator; `nonce_conflict`,
|
|
699
|
+
`receipt_conflict`, `legacy_candidate_conflict` and `legacy_proof_incomplete` keep the wallet held
|
|
700
|
+
until the stated proof or a separately reviewed disposition exists. A landed leg stays landed.
|
|
701
|
+
No rebuild or repeat-trade instruction follows an uncertain result.
|
|
702
|
+
|
|
703
|
+
Every Hood rail job read carries its operation's `guard`, regardless of the job's terminal label.
|
|
704
|
+
`GET /api/v1/agent/wallets/{walletId}/hood-tee` is the read-only locator of last resort, even with
|
|
705
|
+
no job row: `guard: { held, incomplete, operations }` lists at most 10 held operations. A held
|
|
706
|
+
failed/expired operation also makes `activeOperation` non-null for installed custody clients.
|
|
707
|
+
Incomplete proof without a known holder omits `activeOperation`, so those clients fail closed.
|
|
708
|
+
Current custody commands refuse `WALLET_GUARDED`. Preserve that compatibility projection during
|
|
709
|
+
rollback. This endpoint performs no recovery writes.
|
|
710
|
+
|
|
711
|
+
SDK: `getHoodTeeOperation(operationId)` and
|
|
712
|
+
`recoverHoodTeeOperation(operationId, { candidateHash? })`; `GuardSummary` and `WalletBusyDetails`
|
|
713
|
+
are exported. MCP: `candle_get_operation` accepts `operationId` exclusively instead of
|
|
714
|
+
`clientId`/`kind`; `candle_recover_operation` accepts `operationId` and optional `candidateHash`.
|
|
715
|
+
An older API without explicit operation lookup requires reading the job by its client id.
|
|
716
|
+
These client source changes require a separate human package release; this repair bumps no version.
|