@candledottv/cli 0.13.16 → 0.13.17
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 +21 -9
- package/dist/index.js +266 -96
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -53,6 +53,12 @@ or with Homebrew:
|
|
|
53
53
|
Then: candle setup
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
The installer checks the download's SHA-256 and its Sigstore signature before it writes anything,
|
|
57
|
+
and needs nothing beyond `curl` and `sha256sum` or `shasum`. It checks the signature with `cosign` or
|
|
58
|
+
a signed-in `gh` when one is installed, and otherwise with Candle's own `candle verify`, offline, from
|
|
59
|
+
a CLI release whose SHA-256 the script carries (it downloads that `candle` and checks it against the
|
|
60
|
+
SHA-256 before running it). If no check can run, it installs nothing.
|
|
61
|
+
|
|
56
62
|
`candle setup` authorizes this device from your browser, shows the agent wallets as funding
|
|
57
63
|
destinations, prints the skill and MCP install lines, and runs a full health check. `candle auth
|
|
58
64
|
login` on its own does just the authorization step.
|
|
@@ -85,6 +91,10 @@ vault key with `candle tee sweep` or `candle vault demote`. Promoting, moving fu
|
|
|
85
91
|
emergency procedure, rebinding, trusted wallets and API key access levels are all in
|
|
86
92
|
[Custody tiers: the vault and TEE wallets](https://docs.candle.tv/developers/cli-custody).
|
|
87
93
|
|
|
94
|
+
The recovery phrase ceremony (`vault init`'s offer or `vault phrase show`) waits for you to save
|
|
95
|
+
all 24 words offline and press Enter, then clears the screen before asking for three randomly
|
|
96
|
+
chosen words from your saved copy. Clear your terminal's scrollback too: the CLI cannot erase it.
|
|
97
|
+
|
|
88
98
|
## Commands
|
|
89
99
|
|
|
90
100
|
| Command | What it does |
|
|
@@ -94,8 +104,9 @@ emergency procedure, rebinding, trusted wallets and API key access levels are al
|
|
|
94
104
|
| `candle auth status` | Shows which storage backend is in use, both credential prefixes, the config file path, and a live validity check for each credential. |
|
|
95
105
|
| `candle auth logout [--keep-key]` | Revokes the stored API key (skipped with `--keep-key`), clears local credentials and config, and prints the portal URL for revoking the device itself. |
|
|
96
106
|
| `candle keys list [--scopes]` | Lists this account's API keys: prefix, name, Read, Write or Withdraw access, environment, timestamps, and which device minted each one. `--scopes` adds the raw scopes, sorted. |
|
|
97
|
-
| `candle keys create [--access read\|write\|withdraw \| --scopes <a,b,c>] [--label <name>] [--expires-in <days>] [--tx-limit <usd> [--reset daily\|weekly\|monthly\|never]] [--embedded-wallet deny\|allow]` | Creates a new API key and prints the plaintext exactly once, with the same optional name, expiration, and USD transaction limit the portal's create form takes. `--access` mints one of the portal's three levels (`write` trades and launches and cannot move funds; `withdraw` is Write plus `transfer:write` and `transfer:bound`: the key can move funds between your own wallets and to addresses you approved, and out of the wallet it runs to wallets you linked while signed in or marked trusted and to that wallet's vault); `--scopes` names raw scopes instead, never both. `--embedded-wallet` defaults to `deny`; `allow` lets the key spend the account's embedded wallet and is confirmed at a terminal. Stored locally only if the CLI does not already hold a working key. An account holds at most 25 active keys. |
|
|
107
|
+
| `candle keys create [--access read\|write\|withdraw \| --scopes <a,b,c>] [--label <name>] [--expires-in <days>] [--tx-limit <usd> [--reset daily\|weekly\|monthly\|never]] [--embedded-wallet deny\|allow] [--no-store]` | Creates a new API key and prints the plaintext exactly once, with the same optional name, expiration, and USD transaction limit the portal's create form takes. `--access` mints one of the portal's three levels (`write` trades and launches and cannot move funds; `withdraw` is Write plus `transfer:write` and `transfer:bound`: the key can move funds between your own wallets and to addresses you approved, and out of the wallet it runs to wallets you linked while signed in or marked trusted and to that wallet's vault); `--scopes` names raw scopes instead, never both. `--embedded-wallet` defaults to `deny`; `allow` lets the key spend the account's embedded wallet and is confirmed at a terminal. Stored locally only if the CLI does not already hold a working key. `--no-store` prints the new key without saving it or changing the profile's working key or metadata; `--json` reports `stored: false`. An account holds at most 25 active keys. |
|
|
98
108
|
| `candle keys access <prefix\|label\|self> (--access read\|write\|withdraw [--yes] \| --history)` | Changes an existing key's level in place (same key, wallets and caps). Widening needs the device token and the prefix typed back at a terminal; `--yes` skips the prompt when narrowing; `self` narrows the profile's own key and can never widen it. `--history` lists the key's changes and who made them. |
|
|
109
|
+
| `candle keys limits <prefix> <asset>=<raw> [<asset>=<raw> ...]` | Sets a key's per-asset caps (`sol`, `usdc`, `cndl`, `eth`, `usdg`, in base units per transaction) with the profile's own API key. It can only tighten; raising or removing a cap is `LOOSEN_REQUIRES_SESSION`, and the owner does that in the web key manager. A device token cannot set these caps. |
|
|
99
110
|
| `candle keys update <prefix\|label> --embedded-wallet allow\|deny [--yes]`, `candle keys self embedded-wallet deny` | Allow or deny a key the account's embedded wallet, with the device token (allowing needs the prefix typed back at a terminal). `self embedded-wallet deny` lets the profile's own key give it up with no prompt; a key can never allow itself. |
|
|
100
111
|
| `candle keys signer approve <code> --key <prefix\|label> [--reject]`, `candle keys signer move <prefix\|label> [--to-key <prefix\|label>]` | Key signers for bots on a different machine from the vault. `approve` accepts (or rejects) a key's signer request with the device token, after you type the full fingerprint the trading machine printed. `move`, on the machine holding a wallet's current signer, moves every wallet on the key onto its active signer; `--to-key` moves a revoked key's wallets to a live key. |
|
|
101
112
|
| `candle keys stop <prefix>` | Pause one key using the device token. Its requests are refused with `PROFILE_PAUSED` until resumed; the key and its local credential are kept. Repeating the command succeeds. |
|
|
@@ -109,9 +120,9 @@ emergency procedure, rebinding, trusted wallets and API key access levels are al
|
|
|
109
120
|
| `candle wallets trust\|untrust <label\|address\|id\|prefix*>...` | Mark linked wallets as yours so an agent's Withdraw key can move funds into them, or clear the mark. Owner only, over the device token, with a typed confirm; a trailing `*`, as in `'tr-*'`, selects by prefix. |
|
|
110
121
|
| `candle wallets allow-launch\|disallow-launch <label\|address\|id\|prefix*>...` | Deprecated. Where the server has `TEE_LAUNCH_BY_SCOPE_ENABLED` on, a key's `launch:write` decides TEE launches: `allow-launch` saves the value and exits 0, and `disallow-launch` saves it, prints the server's `ALLOW_LAUNCH_NOT_ENFORCED` message and exits 1, because no launch is stopped. A server with the switch off still lets TEE wallets pay for a launch (`candle launch`) only after `allow-launch`. Owner only, over the device token; the screen shows each wallet's label, address and bound key before a typed confirm. `disallow-launch --yes` skips the confirm. |
|
|
111
122
|
| `candle wallets close-empty [--wallet embedded\|<tee address\|label>] [--keep <mint>]... [--client-trade-id <id>] [--preview] [--yes]` | Closes a wallet's empty token accounts and returns their rent to it, after a preview: the embedded wallet (`transfer:write`), or a Solana TEE wallet bound to the key (`swap:write`), whose close transactions Candle builds, this machine checks and the key signer approves. `--preview` prints what would close — the whole preview as one JSON document on stdout under `--json` — and closes, signs and prompts nothing; headless without `--yes`, the `CONFIRMATION_REQUIRED` refusal carries that same preview under `details`. |
|
|
112
|
-
| `candle vault init\|status\|list\|new-key\|rename\|phrase show\|restore\|reconcile-exposure` | The encrypted local vault, `vault.enc` (Tier 1). `init` creates it with a passphrase factor and a 24-word recovery phrase (and no key), `new-key` derives a key inside it (`--count`, `--labels-from <file>` for many under one unlock), `list [filter] [--balances]` shows one line per key, `rename` changes a label only, `phrase show` displays the phrase on a terminal (never in `--json`, a log or a pipe), and `restore --phrase` rebuilds the derived keys on another machine with a new passphrase (`--count`, `--tee-count`, `--external-count`, `--evm-count` and `--evm-tee-count` for EVM keys and Hood TEE wallets, or a Solana gap scan with `--rpc-url`); a restored vault never allocates new keys. `reconcile-exposure` re-reads the account and adds exposure records, clearing nothing. No key ever leaves the vault to reach Candle. See [CLI custody](https://docs.candle.tv/developers/cli-custody). |
|
|
123
|
+
| `candle vault init\|status\|list\|new-key\|rename\|phrase show\|restore\|reconcile-exposure` | The encrypted local vault, `vault.enc` (Tier 1). `init` creates it with a passphrase factor and a 24-word recovery phrase (and no key), labels its read-back derivation as verification, and leaves security-key enrollment to the separate optional `candle vault enroll security-key` command; `new-key` derives a key inside it (`--count`, `--labels-from <file>` for many under one unlock), `list [filter] [--balances]` shows one line per key, `rename` changes a label only, `phrase show` displays the phrase on a terminal (never in `--json`, a log or a pipe), and `restore --phrase` rebuilds the derived keys on another machine with a new passphrase (`--count`, `--tee-count`, `--external-count`, `--evm-count` and `--evm-tee-count` for EVM keys and Hood TEE wallets, or a Solana gap scan with `--rpc-url`); a restored vault never allocates new keys. `reconcile-exposure` re-reads the account and adds exposure records, clearing nothing. No key ever leaves the vault to reach Candle. See [CLI custody](https://docs.candle.tv/developers/cli-custody). |
|
|
113
124
|
| `candle vault factor list\|add passphrase\|add security-key\|add touch-id\|add passkey\|remove` (or `vault enroll <kind>`), `vault backup --to <path>\|icloud`, `vault verify-backup <path>` | What can open the vault, and proving a copy of it works: `backup` verifies the copy in full before reporting (a copy is sealed, keeping only the passphrase and security-key envelopes, unless it goes to a recognised local disk or removable drive, so a cloud folder and any path the CLI cannot place are both sealed unless `--accept-shared-domain` is passed), and `verify-backup` re-checks an existing one against this vault's key and address set. `add security-key` enrolls a FIDO2 security key (CTAP2 `hmac-secret`, user-verified with the key's PIN or biometric) through the bundled `candle-fido2` helper (`--install-helper` fetches and verifies this release's helper first); one key is not a recoverable factor, two keys are a pair, an enrolled key can authorize adding another, and the passphrase stays the recovery floor. `add touch-id` and `add passkey` are refused with `VAULT_FACTOR_UNSUPPORTED_ON_PLATFORM` until the Apple-signed helper ships. Every vault command then takes `--factor <id\|passphrase\|security-key>` to say which envelope opens it and `--device <id>` to name the key when several are attached. |
|
|
114
|
-
| `candle vault transfer\|promote\|promote-batch\|fund\|demote\|export-key` | Moving value and authority. `transfer` and `fund` sign locally after showing the decoded transaction (`transfer` from a vault key or a promoted TEE wallet, which warns when an agent may be trading it and reports the finalized transfer to Candle's history; `fund` reaches a TEE wallet from its pinned vault key, or an external wallet, with no `--yes`; both verify once, at the unlock, which names the send, then show the destination grouped in fours and take a typed `confirm`); `promote --from <cold label>` derives a fresh TEE wallet pinned to that key (an EVM vault key becomes a Hood TEE wallet), `promote --in-place <label> --sweep-to <cold label>` promotes a key at its own address after a typed warning, `promote-batch --pairs-from <file>` does many in place under one unlock, `--to-key` binds the result to another of your keys, and `demote` (disable then sweep; `--emergency` sweeps even when the stop request fails) sends it back to its pinned vault; `export-key` is the one ceremony that writes a single private key to a file you name. `demote` takes several addresses, or `--all --empty` for every Solana TEE wallet with nothing left to sweep, under one unlock and one typed `confirm` (`--yes` skips it), with a result line per wallet and one `--json` document. |
|
|
125
|
+
| `candle vault transfer\|promote\|promote-batch\|fund\|demote\|export-key` | Moving value and authority. `transfer` and `fund` sign locally after showing the decoded transaction (`transfer` from a vault key or a promoted TEE wallet, which warns when an agent may be trading it and reports the finalized transfer to Candle's history; `fund` reaches a TEE wallet from its pinned vault key, or an external wallet, with no `--yes`; both verify once, at the unlock, which names the send, then show the destination grouped in fours and take a typed `confirm`); `promote --from <cold label>` derives a fresh TEE wallet pinned to that key (an EVM vault key becomes a Hood TEE wallet), shows the pinned vault address and asks you to type `confirm` to promote the new wallet (promotion moves no funds), `promote --in-place <label> --sweep-to <cold label>` promotes a key at its own address after a typed warning, `promote-batch --pairs-from <file>` does many in place under one unlock, `--to-key` binds the result to another of your keys, and `demote` (disable then sweep; `--emergency` sweeps even when the stop request fails) sends it back to its pinned vault; `export-key` is the one ceremony that writes a single private key to a file you name. `demote` takes several addresses, or `--all --empty` for every Solana TEE wallet with nothing left to sweep, under one unlock and one typed `confirm` (`--yes` skips it), with a result line per wallet and one `--json` document. |
|
|
115
126
|
| `candle external new\|list\|sweep` | External wallets for outside tools: keys on the vault's third branch (`m/44'/501'/n'/2'`), never delegated to Privy and never registered with Candle. `new` allocates one (and moves the vault to format version 3; refused in a restored vault), `list` shows them, and `sweep <external> --to <vault>` sends everything back to a named vault key, signed locally, confirmed by a typed `confirm` after the vault key's address is shown. See [Bring your own services](https://docs.candle.tv/developers/cli#bring-your-own-services). |
|
|
116
127
|
| `candle sign [--file <path>] --wallet <external>... [--broadcast] [--yes]`, `candle sign message --wallet <external> [--file <path>] [--yes]` | The generic signer: a base64 transaction any tool built, legacy or v0, decoded (lookup tables resolved) and simulated over your own RPC before it is displayed and signed with an external wallet only. A vault key, a TEE wallet or an unnamed signer is refused; a failing simulation is refused with no override; `--yes` skips the confirmation prompt and nothing else. `sign message` signs the exact bytes of a file or of stdin. |
|
|
117
128
|
| `candle secrets set\|list\|remove <name>` | Your own third-party API keys, in a keychain namespace separate from Candle's credentials (`tv.candle.cli.secrets`, or `secrets.enc` on the encrypted-file fallback). Typed on a hidden prompt, never sent to Candle, never printed after `set`; `list` shows names only. A plug-in receives one as `CANDLE_SECRET_<NAME>` only when named with `--secret`. |
|
|
@@ -121,7 +132,7 @@ emergency procedure, rebinding, trusted wallets and API key access levels are al
|
|
|
121
132
|
| `candle tee signer new --key <prefix\|label> [--out <pem>] [--force] [--no-wait]` | On the trading machine, with that key's API key: generates the key's signer here and waits for the owner to approve it with `keys signer approve`. The key's wallets then trade from this machine. `--out` also writes a plaintext P-256 authorization key for Privy wallet RPC; it cannot sign Solana transactions (the TEE signs them). `--no-wait` exits 0 once the request exists. With `--json`, stdout is newline-delimited JSON: a pending event (`state`, `userCode`, `verificationUriComplete`, `expiresAt`, `fingerprint`) immediately, then an active result or error when waiting. A retry re-attaches to the same live request without changing its code or deadline. |
|
|
122
133
|
| `candle tee signer status --key <prefix\|label> [--json]` | Read the current server signer state without generating a key, requesting a code or waiting. On the requesting machine, also shows the cached approval URL and code while the same request is live. |
|
|
123
134
|
| `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. |
|
|
124
|
-
| `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. |
|
|
135
|
+
| `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. |
|
|
125
136
|
| `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). |
|
|
126
137
|
| `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. |
|
|
127
138
|
| `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. |
|
|
@@ -213,7 +224,7 @@ which `candle verify` cannot read.
|
|
|
213
224
|
|
|
214
225
|
No cosign or gh installed? `candle verify <file> --bundle <path>` (this CLI's own command, see the
|
|
215
226
|
table above) runs the same check against the trusted root compiled into the binary, no network
|
|
216
|
-
call required. Full walkthrough, including the installer script's own signature and the
|
|
227
|
+
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
|
|
217
228
|
transparency log: [Verify a Candle release](https://docs.candle.tv/developers/verify-a-candle-release).
|
|
218
229
|
|
|
219
230
|
## The `--json` contract
|
|
@@ -411,10 +422,11 @@ key; Candle builds the transaction and Privy signs it through the relay. See TEE
|
|
|
411
422
|
below. Limit orders are a REST surface only (`/api/v1/trade/agent/orders`), not in this CLI, the
|
|
412
423
|
SDK or the MCP server.
|
|
413
424
|
|
|
414
|
-
**`keys limits`.**
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
425
|
+
**`keys limits`.** The API route that sets per-key spend limits (`PUT /keys/:prefix/limits`)
|
|
426
|
+
structurally rejects a device token: a spend limit is fund-movement authority, and this CLI's
|
|
427
|
+
device token is scoped narrowly to key management. So `candle keys limits` sends the profile's own
|
|
428
|
+
API key, and an agent key may only tighten (lower a cap, or add one where none was set). Raising
|
|
429
|
+
or removing a cap is refused with `LOOSEN_REQUIRES_SESSION`; the owner does that from the portal.
|
|
418
430
|
|
|
419
431
|
**`devices list` / `devices revoke`.** The device-token endpoints (`GET`/`DELETE
|
|
420
432
|
/device/tokens`) are session-only by design: this is the self-renewal guard that keeps a stolen
|
package/dist/index.js
CHANGED
|
@@ -532,7 +532,7 @@ var init_terminal_theme = __esm(() => {
|
|
|
532
532
|
});
|
|
533
533
|
|
|
534
534
|
// src/version.ts
|
|
535
|
-
var CLI_VERSION = "0.13.
|
|
535
|
+
var CLI_VERSION = "0.13.17";
|
|
536
536
|
|
|
537
537
|
// src/presentation.ts
|
|
538
538
|
function terminalStyle(deps, stream, machine = false) {
|
|
@@ -12603,9 +12603,9 @@ function kekReuseKey(passphrase, kdf) {
|
|
|
12603
12603
|
const inputs = JSON.stringify([passphrase, kdf.salt, kdf.m, kdf.t, kdf.p, kdf.version]);
|
|
12604
12604
|
return b64u(sha2562(new TextEncoder().encode(inputs)));
|
|
12605
12605
|
}
|
|
12606
|
-
async function derivePassphraseKek(passphrase, kdf, notice2) {
|
|
12606
|
+
async function derivePassphraseKek(passphrase, kdf, notice2, derivationLabel = "Deriving the vault key") {
|
|
12607
12607
|
assertKdfInBounds(kdf);
|
|
12608
|
-
notice2?.(
|
|
12608
|
+
notice2?.(`${derivationLabel} (Argon2id, ${Math.round(kdf.m / 1024)} MiB)
|
|
12609
12609
|
`);
|
|
12610
12610
|
const reuseKey = testKekReuse ? kekReuseKey(passphrase, kdf) : null;
|
|
12611
12611
|
const reused = reuseKey ? testKekReuse?.get(reuseKey) : undefined;
|
|
@@ -13990,7 +13990,7 @@ function closeVault(vault) {
|
|
|
13990
13990
|
async function unlockVault(path, raw, request, opts = {}) {
|
|
13991
13991
|
const file = parseVaultFile(raw);
|
|
13992
13992
|
const envelope = pickEnvelope(file, request);
|
|
13993
|
-
const dek = await unwrapDek(file, envelope, request, opts.notice);
|
|
13993
|
+
const dek = await unwrapDek(file, envelope, request, opts.notice, opts.derivationLabel);
|
|
13994
13994
|
if (dek.length !== DEK_BYTES) {
|
|
13995
13995
|
wipe(dek);
|
|
13996
13996
|
throw new VaultError("VAULT_UNLOCK_FAILED", "The unwrapped key is the wrong length; this file is corrupt.");
|
|
@@ -14030,9 +14030,9 @@ async function openWithDek(path, raw, file, envelope, dek) {
|
|
|
14030
14030
|
throw error;
|
|
14031
14031
|
}
|
|
14032
14032
|
}
|
|
14033
|
-
async function unwrapDek(file, envelope, request, notice2) {
|
|
14033
|
+
async function unwrapDek(file, envelope, request, notice2, derivationLabel) {
|
|
14034
14034
|
if (request.factor === "passphrase") {
|
|
14035
|
-
const kek = await derivePassphraseKek(request.passphrase, passphraseKdf(envelope), notice2);
|
|
14035
|
+
const kek = await derivePassphraseKek(request.passphrase, passphraseKdf(envelope), notice2, derivationLabel);
|
|
14036
14036
|
return withSecret(kek, async (kekBytes) => {
|
|
14037
14037
|
const kekKey2 = await importAesKey(kekBytes);
|
|
14038
14038
|
return open(kekKey2, envelope.wrap, envelopeAad(file, envelope), {
|
|
@@ -38135,6 +38135,7 @@ async function keysList(args, ctx) {
|
|
|
38135
38135
|
async function keysCreate(args, ctx) {
|
|
38136
38136
|
const { deps, apiUrl, json } = ctx;
|
|
38137
38137
|
const parsed = parseArgs(args, {
|
|
38138
|
+
booleanFlags: ["--no-store"],
|
|
38138
38139
|
valueFlags: [
|
|
38139
38140
|
"--scopes",
|
|
38140
38141
|
"--access",
|
|
@@ -38239,11 +38240,12 @@ async function keysCreate(args, ctx) {
|
|
|
38239
38240
|
return 1;
|
|
38240
38241
|
}
|
|
38241
38242
|
const body = result.body;
|
|
38243
|
+
const noStore = parsed.booleans.has("--no-store");
|
|
38242
38244
|
const apiKeyRef = ctx.profile ? profileSecretRef(ctx.profile, "apiKey") : SECRET_REFS.apiKey;
|
|
38243
38245
|
let stored = false;
|
|
38244
38246
|
let storeError;
|
|
38245
38247
|
try {
|
|
38246
|
-
if (!await deps.store.get(apiKeyRef)) {
|
|
38248
|
+
if (!noStore && !await deps.store.get(apiKeyRef)) {
|
|
38247
38249
|
await deps.store.set(apiKeyRef, body.key);
|
|
38248
38250
|
if (ctx.profile) {
|
|
38249
38251
|
await deps.updateProfile(ctx.profile, { keyPrefix: body.keyPrefix, scopes: body.scopes });
|
|
@@ -38277,7 +38279,7 @@ Or mint it that way: candle keys create --access withdraw --embedded-wallet allo
|
|
|
38277
38279
|
...body.embeddedWallet === "allowed" || body.embeddedWallet === "denied" ? [["Embedded wallet", embeddedWalletSummary(body.embeddedWallet)]] : [],
|
|
38278
38280
|
[
|
|
38279
38281
|
"Stored",
|
|
38280
|
-
storeError !== undefined ? "no (store failed)" : stored ? `${deps.backend}, as this CLI's working key` : "no (the CLI already manages a different working key)"
|
|
38282
|
+
storeError !== undefined ? "no (store failed)" : stored ? `${deps.backend}, as this CLI's working key` : noStore ? "no (--no-store)" : "no (the CLI already manages a different working key)"
|
|
38281
38283
|
]
|
|
38282
38284
|
], style).join(`
|
|
38283
38285
|
`)}
|
|
@@ -40791,32 +40793,38 @@ async function executionStatus(cfg, doFetch) {
|
|
|
40791
40793
|
}
|
|
40792
40794
|
return { ok: res.ok, status: res.status, body };
|
|
40793
40795
|
};
|
|
40794
|
-
const [wallets2, tier, limits] = await Promise.all([
|
|
40796
|
+
const [wallets2, tier, limits, risk] = await Promise.all([
|
|
40795
40797
|
get("/api/v1/agent/wallets/embedded"),
|
|
40796
40798
|
get("/api/v1/agent/tier"),
|
|
40797
|
-
get("/api/v1/agent/keys/self/limits")
|
|
40799
|
+
get("/api/v1/agent/keys/self/limits"),
|
|
40800
|
+
get("/api/v1/agent/keys/self/risk")
|
|
40798
40801
|
]);
|
|
40799
40802
|
const unreadable2 = [
|
|
40800
40803
|
["wallets", wallets2],
|
|
40801
40804
|
["tier", tier],
|
|
40802
|
-
["limits", limits]
|
|
40805
|
+
["limits", limits],
|
|
40806
|
+
["risk", risk]
|
|
40803
40807
|
].filter(([, r]) => !r.ok);
|
|
40804
40808
|
const tierBody = tier.ok ? tier.body : undefined;
|
|
40809
|
+
const riskBody = risk.ok ? risk.body : undefined;
|
|
40810
|
+
const stopped = riskBody?.stopped === true;
|
|
40805
40811
|
return {
|
|
40806
40812
|
text: JSON.stringify({
|
|
40807
40813
|
success: true,
|
|
40808
|
-
ready: unreadable2.length === 0 ? true : undefined,
|
|
40814
|
+
ready: stopped ? false : unreadable2.length === 0 ? true : undefined,
|
|
40815
|
+
stopped: stopped ? { tripped: riskBody?.tripped ?? null, clearedBy: STOP_CLEARED_BY } : undefined,
|
|
40809
40816
|
notice: tierBody?.maxExpired ? tierBody.maxExpiredNotice : undefined,
|
|
40810
40817
|
updateAvailable: updateAvailable() ?? undefined,
|
|
40811
40818
|
unreadable: unreadable2.length > 0 ? unreadable2.map(([name]) => name) : undefined,
|
|
40812
40819
|
wallets: wallets2.body,
|
|
40813
40820
|
tier: tier.body,
|
|
40814
|
-
limits: limits.body
|
|
40821
|
+
limits: limits.body,
|
|
40822
|
+
risk: risk.body
|
|
40815
40823
|
}, null, 2),
|
|
40816
40824
|
...unreadable2.length > 0 ? { isError: true } : {}
|
|
40817
40825
|
};
|
|
40818
40826
|
}
|
|
40819
|
-
var SOLANA_SEED_CEILINGS, MAIN_PAYER, SWEEP_BASE_ASSETS;
|
|
40827
|
+
var SOLANA_SEED_CEILINGS, MAIN_PAYER, SWEEP_BASE_ASSETS, STOP_CLEARED_BY = "An account owner reviews the profile and resumes it from the agent console; an API key cannot resume it.";
|
|
40820
40828
|
var init_orchestrate = __esm(() => {
|
|
40821
40829
|
init_convert();
|
|
40822
40830
|
init_image();
|
|
@@ -45246,13 +45254,40 @@ function buildRequest(name, args, cfg) {
|
|
|
45246
45254
|
}
|
|
45247
45255
|
case "candle_get_profile_trades": {
|
|
45248
45256
|
const apiKey = requireApiKey2(cfg);
|
|
45249
|
-
const { keyPrefix, limit } = args;
|
|
45250
|
-
const
|
|
45257
|
+
const { keyPrefix, limit, since, until, cursor } = args;
|
|
45258
|
+
const params = new URLSearchParams;
|
|
45259
|
+
if (limit !== undefined)
|
|
45260
|
+
params.set("limit", String(limit));
|
|
45261
|
+
if (since !== undefined)
|
|
45262
|
+
params.set("since", since);
|
|
45263
|
+
if (until !== undefined)
|
|
45264
|
+
params.set("until", until);
|
|
45265
|
+
if (cursor !== undefined)
|
|
45266
|
+
params.set("cursor", cursor);
|
|
45251
45267
|
return {
|
|
45252
|
-
url: `${base2}/api/v1/agent/keys/${encodeURIComponent(keyPrefix)}/trades${
|
|
45268
|
+
url: `${base2}/api/v1/agent/keys/${encodeURIComponent(keyPrefix)}/trades${params.size ? `?${params}` : ""}`,
|
|
45253
45269
|
init: { method: "GET", headers: jsonHeaders(apiKey) }
|
|
45254
45270
|
};
|
|
45255
45271
|
}
|
|
45272
|
+
case "candle_get_paper_inventory": {
|
|
45273
|
+
return {
|
|
45274
|
+
url: `${base2}/api/v1/trade/agent/paper/inventory`,
|
|
45275
|
+
init: { method: "GET", headers: jsonHeaders(requireApiKey2(cfg)) }
|
|
45276
|
+
};
|
|
45277
|
+
}
|
|
45278
|
+
case "candle_get_profile_paper": {
|
|
45279
|
+
const { keyPrefix } = args;
|
|
45280
|
+
return {
|
|
45281
|
+
url: `${base2}/api/v1/agent/keys/${encodeURIComponent(keyPrefix)}/paper`,
|
|
45282
|
+
init: { method: "GET", headers: jsonHeaders(requireApiKey2(cfg)) }
|
|
45283
|
+
};
|
|
45284
|
+
}
|
|
45285
|
+
case "candle_get_account_pnl": {
|
|
45286
|
+
return {
|
|
45287
|
+
url: `${base2}/api/v1/agent/keys/pnl`,
|
|
45288
|
+
init: { method: "GET", headers: jsonHeaders(requireApiKey2(cfg)) }
|
|
45289
|
+
};
|
|
45290
|
+
}
|
|
45256
45291
|
case "candle_transfer": {
|
|
45257
45292
|
const apiKey = requireApiKey2(cfg);
|
|
45258
45293
|
return {
|
|
@@ -45697,9 +45732,24 @@ function registerToolSubset(server, options) {
|
|
|
45697
45732
|
}, async (args) => callAndRelay("candle_get_profile_pnl", args, getConfig(), doFetch));
|
|
45698
45733
|
register("candle_get_profile_trades", {
|
|
45699
45734
|
title: "Read an agent profile's trade history",
|
|
45700
|
-
description: "Orders, actual fills, fees, timestamps and transaction hashes for this profile. Includes FAILED " + "trades, with an errorCode saying why each did not go through, so this answers 'what happened to " + "my order' as well as 'what did I trade'. Reads only; moves nothing.",
|
|
45735
|
+
description: "Orders, actual fills, fees, timestamps and transaction hashes for this profile. Page by time with " + "`since`, `until` and `cursor` (continue with the response's `nextCursor`). Includes FAILED " + "trades, with an errorCode saying why each did not go through, so this answers 'what happened to " + "my order' as well as 'what did I trade'. Reads only; moves nothing.",
|
|
45701
45736
|
inputSchema: profileTradesShape
|
|
45702
45737
|
}, async (args) => callAndRelay("candle_get_profile_trades", args, getConfig(), doFetch));
|
|
45738
|
+
register("candle_get_paper_inventory", {
|
|
45739
|
+
title: "Read this key's paper inventory",
|
|
45740
|
+
description: "This key's PAPER book in raw units: the positions that paper buys have credited and a paper " + "percent sell sizes itself from. Derived from admitted quotes; no money moved and the live " + "wallet is untouched. Never mix it with live holdings (candle_get_portfolio). Fails retryably " + "when the book cannot be read completely. Needs swap:write on the key. Reads only.",
|
|
45741
|
+
inputSchema: noArgsShape
|
|
45742
|
+
}, async (args) => callAndRelay("candle_get_paper_inventory", args, getConfig(), doFetch));
|
|
45743
|
+
register("candle_get_profile_paper", {
|
|
45744
|
+
title: "Read an agent profile's paper P&L",
|
|
45745
|
+
description: "One profile's PAPER results: the same accounting as candle_get_profile_pnl, from trades that " + "never happened. `pnl` is the paper P&L and `trades` its 50 most recent paper trades. Carries " + '`basis: "quote"`: the figures come from quotes at admission and are optimistic by the ' + "slippage and fees real execution pays. Never add them to live P&L. Reads only.",
|
|
45746
|
+
inputSchema: profilePnlShape
|
|
45747
|
+
}, async (args) => callAndRelay("candle_get_profile_paper", args, getConfig(), doFetch));
|
|
45748
|
+
register("candle_get_account_pnl", {
|
|
45749
|
+
title: "Read P&L across all of an account's agent keys",
|
|
45750
|
+
description: "The account's P&L split by agent profile in one read, as `candle pnl` without `--profile` " + "does: one row per profile with its ledger figures and, where it has a board entry, `board` " + "(all-time public total with creator-fee claims credited to the launching agent, so a profile's " + "board total can differ from its per-key ledger P&L). A wallet shared by several keys books a " + "round to its bound key, else the key whose buy opened it. Use candle_get_profile_pnl for one " + "profile's positions. Reads only.",
|
|
45751
|
+
inputSchema: noArgsShape
|
|
45752
|
+
}, async (args) => callAndRelay("candle_get_account_pnl", args, getConfig(), doFetch));
|
|
45703
45753
|
register("candle_get_portfolio", {
|
|
45704
45754
|
title: "Read what the account holds, on Solana and Hood",
|
|
45705
45755
|
description: "Balances and prices for the wallets Candle already knows on this account, on both chains: the " + "embedded wallet and every TEE wallet. Solana wallets are in `embedded` and `tee` (SOL as raw " + "`lamports`, tokens as raw `amountRaw` with `decimals`). Hood wallets are in `hood.embedded` and " + "`hood.tee` (ETH as raw `wei`, ERC-20s including USDG), never in the top-level arrays. Every " + "wallet and holding carries `chain`. Prices are in `prices`: a Solana mint under its own " + "address, Hood ETH under `hood:native`, and a Hood token under `hood:<contract lowercased>`, so " + "lowercase the address before looking it up. An unpriced entry is `priceUsd: null`, never zero; " + "a Hood one says why in `unpricedReason` (no-market-row, unusable-price, stale-mark, " + "source-unavailable), and `hood.unpriced` / `hood.unpricedByReason` count them. A Hood token " + "mark older than six hours is not used, so many Hood tokens read unpriced. A wallet whose read " + "failed has null balances, never zero, and is listed in `unavailable` (Solana) or " + "`hood.unavailable`; check `complete` before quoting a total. `walletsComplete` is false only " + "when the wallet list itself was cut off, and is absent on a server that predates it: then " + "`complete: false` may be a cut-off list or a failed read. Vault and external wallets are " + "not included: Candle does not know their addresses (the Candle CLI's `candle portfolio` reads " + "them over your own RPC). Needs a key with the account:read scope; without it the answer is " + "SCOPE_MISSING. A server that predates Hood in the portfolio omits `hood` and `chain`. Reads " + "only; moves nothing." + (options.localHyperliquid ? " This local server adds `hyperliquid`: each Hood TEE wallet's Hyperliquid account (account value, " + "unrealized P&L, positions, risk level at the default thresholds) read live from Hyperliquid, with a " + "subtotal. It is not in the ledger and is never part of any total. `read: false` with a reason, or " + "entries in `unread`, means those accounts are unknown, not empty." : ""),
|
|
@@ -45721,7 +45771,7 @@ function registerToolSubset(server, options) {
|
|
|
45721
45771
|
});
|
|
45722
45772
|
register("candle_execution_status", {
|
|
45723
45773
|
title: "Can this key execute right now",
|
|
45724
|
-
description: "One call before trading: the embedded wallets to spend from, the tier that decides what " + "may be traded,
|
|
45774
|
+
description: "One call before trading: the embedded wallets to spend from, the tier that decides what " + "may be traded, this key's own spend limits, and its loss limits and stop state (risk: " + "lossLimits, state, stopped, tripped). A stopped key reports ready: false and a top-level " + "stopped naming the bound that broke; every trade answers RISK_LIMIT_REACHED until an " + "account owner resumes it, so stop trading and say why rather than retrying. Any scope " + "can read its own. Reads only; moves nothing. Call it when " + "a run starts, or after an authorization error, rather than inferring readiness from a " + "failed trade. If a read could not be completed the tool says which one and does NOT " + "claim the account is unready: an unreachable endpoint and a missing tier are different " + "problems with different fixes.",
|
|
45725
45775
|
inputSchema: {}
|
|
45726
45776
|
}, async () => {
|
|
45727
45777
|
const result = await executionStatus(getConfig(), doFetch);
|
|
@@ -45988,7 +46038,7 @@ async function registerEligibleProfileTool(server, env = process.env, doFetch =
|
|
|
45988
46038
|
}
|
|
45989
46039
|
return eligible;
|
|
45990
46040
|
}
|
|
45991
|
-
var VAMP_CANDIDATES_DESCRIPTION, localProfileTools, STAKING_DISCLOSURE = "No instant unstake. Read pool.withdrawalTimelockSeconds for the wait. Solana rewards accrue to the holding wallet. sCNDL in any eligible account wallet counts toward Pro and earns the account's Hood staking reward, except a wallet another account also claims, wallets past the 200-wallet cap, and an account with no EVM wallet. CNDL in a pending withdrawal counts toward nothing for Pro.", stakingWriteShape, TOOL_NAMES, LAB_TOOL_NAMES, PROFILE_EDIT_TOOL_NAMES, isProfileEditTool = (name) => PROFILE_EDIT_TOOL_NAMES.includes(name), OPERATION_NOT_FOUND_RULE, getMarketShape, priceHistoryShape, TOKEN_EVENTS_LIMIT_MESSAGE = "limit must be a whole number from 1 to 1000", tokenEventsLimit, TOKEN_EVENTS_KIND_NOTE = "kept back from the request and applied to the returned page by this server, so a filtered page can be shorter than limit while older events of other kinds remain: page with nextCursor as before until it is null", tokenCardShape, tokenEventsShape, tokenForensicsShape, FEED_LIMIT_MESSAGE = "limit must be a whole number from 1 to 200", feedLimit, getFeedShape, reportActivityShape, getAgentProfileShape, listAgentsShape, createPostShape, deletePostShape, listAgentPostsShape, getAgentPositionsShape, getOperationShape, vampCandidatesShape, getFeesShape, atomicPayerShape, atomicLaunchDryRunShape, claimFeesShape, resolveTokenShape, profileWalletsShape, profilePnlShape, profileTradesShape, setProfileWalletsShape, swapShape, tradeShape, tokenImageUrl, tokenBannerUrl, localImageShape, localLaunchTokenShape, localLaunchAndSeedShape, IMAGE_PATH_DISCLOSURE, transferShape, sweepShape, PROFILE_PNL_HYPERLIQUID;
|
|
46041
|
+
var VAMP_CANDIDATES_DESCRIPTION, localProfileTools, STAKING_DISCLOSURE = "No instant unstake. Read pool.withdrawalTimelockSeconds for the wait. Solana rewards accrue to the holding wallet. sCNDL in any eligible account wallet counts toward Pro and earns the account's Hood staking reward, except a wallet another account also claims, wallets past the 200-wallet cap, and an account with no EVM wallet. CNDL in a pending withdrawal counts toward nothing for Pro.", stakingWriteShape, TOOL_NAMES, LAB_TOOL_NAMES, PROFILE_EDIT_TOOL_NAMES, isProfileEditTool = (name) => PROFILE_EDIT_TOOL_NAMES.includes(name), OPERATION_NOT_FOUND_RULE, getMarketShape, priceHistoryShape, TOKEN_EVENTS_LIMIT_MESSAGE = "limit must be a whole number from 1 to 1000", tokenEventsLimit, TOKEN_EVENTS_KIND_NOTE = "kept back from the request and applied to the returned page by this server, so a filtered page can be shorter than limit while older events of other kinds remain: page with nextCursor as before until it is null", tokenCardShape, tokenEventsShape, tokenForensicsShape, FEED_LIMIT_MESSAGE = "limit must be a whole number from 1 to 200", feedLimit, getFeedShape, reportActivityShape, getAgentProfileShape, listAgentsShape, createPostShape, deletePostShape, listAgentPostsShape, getAgentPositionsShape, getOperationShape, vampCandidatesShape, getFeesShape, atomicPayerShape, atomicLaunchDryRunShape, claimFeesShape, resolveTokenShape, profileWalletsShape, profilePnlShape, profileTradesShape, noArgsShape, setProfileWalletsShape, swapShape, tradeShape, tokenImageUrl, tokenBannerUrl, localImageShape, localLaunchTokenShape, localLaunchAndSeedShape, IMAGE_PATH_DISCLOSURE, transferShape, sweepShape, PROFILE_PNL_HYPERLIQUID;
|
|
45992
46042
|
var init_tools = __esm(() => {
|
|
45993
46043
|
init_zod();
|
|
45994
46044
|
init_client2();
|
|
@@ -46063,6 +46113,9 @@ var init_tools = __esm(() => {
|
|
|
46063
46113
|
"candle_set_profile_wallets",
|
|
46064
46114
|
"candle_get_profile_pnl",
|
|
46065
46115
|
"candle_get_profile_trades",
|
|
46116
|
+
"candle_get_paper_inventory",
|
|
46117
|
+
"candle_get_profile_paper",
|
|
46118
|
+
"candle_get_account_pnl",
|
|
46066
46119
|
"candle_get_portfolio",
|
|
46067
46120
|
"candle_resolve_token",
|
|
46068
46121
|
"candle_execution_status",
|
|
@@ -46245,8 +46298,12 @@ var init_tools = __esm(() => {
|
|
|
46245
46298
|
};
|
|
46246
46299
|
profileTradesShape = {
|
|
46247
46300
|
keyPrefix: exports_external.string().describe("The profile's API key prefix"),
|
|
46248
|
-
limit: exports_external.number().optional().describe("How many of the most recent trades to return. Default 200, max 1000.")
|
|
46301
|
+
limit: exports_external.number().optional().describe("How many of the most recent trades to return. Default 200, max 1000."),
|
|
46302
|
+
since: exports_external.string().optional().describe("Inclusive lower bound on the trade's createdAt: an ISO 8601 time or epoch milliseconds."),
|
|
46303
|
+
until: exports_external.string().optional().describe("Exclusive upper bound on createdAt, in the same forms as `since`."),
|
|
46304
|
+
cursor: exports_external.string().optional().describe("The `nextCursor` of the previous page, to continue the same window.")
|
|
46249
46305
|
};
|
|
46306
|
+
noArgsShape = {};
|
|
46250
46307
|
setProfileWalletsShape = {
|
|
46251
46308
|
keyPrefix: exports_external.string().describe("The profile's API key prefix"),
|
|
46252
46309
|
walletIds: exports_external.array(exports_external.string()).describe("The linked-wallet ids the profile may spend from -- ids, not addresses. This REPLACES the " + "whole set: any wallet omitted loses access. An empty array assigns none.")
|
|
@@ -76895,8 +76952,8 @@ var HELP = {
|
|
|
76895
76952
|
description: "List live API keys: name and Read, Write or Withdraw access; --all includes revoked keys; --scopes adds the raw scopes"
|
|
76896
76953
|
},
|
|
76897
76954
|
{
|
|
76898
|
-
invocation: "create [--access read|write|withdraw|trade-perps | --scopes <a,b,c>] [--label <name>] [--expires-in <days>] [--tx-limit <usd> [--reset daily|weekly|monthly|never]] [--embedded-wallet deny|allow]",
|
|
76899
|
-
description: "Create an API key; --access mints one of the levels (write trades and launches; only withdraw can move funds; trade-perps is exactly account:read and perps:write, for Hyperliquid perps setup and orders, and it cannot fund its own Hyperliquid account: a Relay deposit needs swap:write and a withdrawal needs perps:withdraw, each a separate grant through --scopes). A trade-perps key trades from an EVM TEE wallet promoted onto it (candle vault new-key --chain evm, then candle vault promote --from <cold> --to-key <prefix>; candle tee new is Solana only) and a signer on the trading machine (candle tee signer new --key <prefix>). --embedded-wallet defaults to deny; allow lets the key spend the account's embedded wallet and is confirmed at a terminal"
|
|
76955
|
+
invocation: "create [--access read|write|withdraw|trade-perps | --scopes <a,b,c>] [--label <name>] [--expires-in <days>] [--tx-limit <usd> [--reset daily|weekly|monthly|never]] [--embedded-wallet deny|allow] [--no-store]",
|
|
76956
|
+
description: "Create an API key; --no-store prints it without saving it as the profile's working key (default: store only if no working key exists). --access mints one of the levels (write trades and launches; only withdraw can move funds; trade-perps is exactly account:read and perps:write, for Hyperliquid perps setup and orders, and it cannot fund its own Hyperliquid account: a Relay deposit needs swap:write and a withdrawal needs perps:withdraw, each a separate grant through --scopes). A trade-perps key trades from an EVM TEE wallet promoted onto it (candle vault new-key --chain evm, then candle vault promote --from <cold> --to-key <prefix>; candle tee new is Solana only) and a signer on the trading machine (candle tee signer new --key <prefix>). --embedded-wallet defaults to deny; allow lets the key spend the account's embedded wallet and is confirmed at a terminal"
|
|
76900
76957
|
},
|
|
76901
76958
|
{
|
|
76902
76959
|
invocation: "access <prefix|label|self> (--access read|write|withdraw [--yes] | --history)",
|
|
@@ -76910,6 +76967,10 @@ var HELP = {
|
|
|
76910
76967
|
invocation: "limit <prefix|label> (--tx-limit <usd> [--reset daily|weekly|monthly|never] | --clear)",
|
|
76911
76968
|
description: "Set or clear the USD transaction cap on an existing key, with the device token. --reset defaults to daily"
|
|
76912
76969
|
},
|
|
76970
|
+
{
|
|
76971
|
+
invocation: "limits <prefix> <asset>=<raw> [<asset>=<raw> ...]",
|
|
76972
|
+
description: "Set a key's per-asset caps (sol, usdc, cndl, eth, usdg; a whole number of base units per transaction) with the profile's own API key. It can only lower a cap or add one; raising or removing one is refused (LOOSEN_REQUIRES_SESSION) and is the owner's, in the web key manager. The list replaces the key's caps"
|
|
76973
|
+
},
|
|
76913
76974
|
{
|
|
76914
76975
|
invocation: "self embedded-wallet deny",
|
|
76915
76976
|
description: "The profile's own key gives up the embedded wallet, with no prompt. A key can never allow itself: the owner does that with keys update"
|
|
@@ -76946,11 +77007,12 @@ var HELP = {
|
|
|
76946
77007
|
"candle keys list",
|
|
76947
77008
|
"candle keys create --access withdraw --label rebalancer",
|
|
76948
77009
|
"candle keys create --access trade-perps --label perps-bot",
|
|
76949
|
-
"candle keys create --scopes trade:write --label agent-one",
|
|
77010
|
+
"candle keys create --scopes trade:write --label agent-one --no-store",
|
|
76950
77011
|
"candle keys access cndl --access withdraw",
|
|
76951
77012
|
"candle keys access self --access read --yes",
|
|
76952
77013
|
"candle keys update agent-one --embedded-wallet deny --yes",
|
|
76953
77014
|
"candle keys self embedded-wallet deny",
|
|
77015
|
+
"candle keys limits Ab3dEf9h sol=1000000000 usdc=50000000",
|
|
76954
77016
|
"candle keys wallets ck_live_ab12",
|
|
76955
77017
|
"candle tee rebind --label-prefix dest- --to-key Ab3dEf9h",
|
|
76956
77018
|
"candle keys signer approve ABCD-EFGH --key tr-2",
|
|
@@ -77872,6 +77934,9 @@ var TOOL_CLASSES = {
|
|
|
77872
77934
|
candle_get_profile_wallets: READ,
|
|
77873
77935
|
candle_get_profile_pnl: READ,
|
|
77874
77936
|
candle_get_profile_trades: READ,
|
|
77937
|
+
candle_get_paper_inventory: READ,
|
|
77938
|
+
candle_get_profile_paper: READ,
|
|
77939
|
+
candle_get_account_pnl: READ,
|
|
77875
77940
|
candle_get_portfolio: READ,
|
|
77876
77941
|
candle_resolve_token: READ,
|
|
77877
77942
|
candle_execution_status: READ,
|
|
@@ -90263,6 +90328,100 @@ ${fields(rows, style).join(`
|
|
|
90263
90328
|
return 0;
|
|
90264
90329
|
}
|
|
90265
90330
|
|
|
90331
|
+
// src/commands/keys-limits.ts
|
|
90332
|
+
init_args();
|
|
90333
|
+
init_client();
|
|
90334
|
+
init_deps();
|
|
90335
|
+
init_presentation();
|
|
90336
|
+
init_profiles();
|
|
90337
|
+
init_key_output();
|
|
90338
|
+
var USAGE8 = "Usage: candle keys limits <prefix> <asset>=<raw-amount> [<asset>=<raw-amount> ...]";
|
|
90339
|
+
var KEY_LIMIT_ASSETS = { sol: 9, usdc: 6, cndl: 6, eth: 18, usdg: 6 };
|
|
90340
|
+
var RAW_AMOUNT = /^[1-9][0-9]*$/;
|
|
90341
|
+
var NO_API_KEY3 = {
|
|
90342
|
+
code: "API_KEY_REQUIRED",
|
|
90343
|
+
message: "candle keys limits changes caps with an API key, and this profile holds none.",
|
|
90344
|
+
suggestion: "Select the profile holding the key with --profile. A device token cannot set per-asset caps."
|
|
90345
|
+
};
|
|
90346
|
+
var LOOSEN_HINT = "This command can only lower a cap. Raising or removing one needs the owner's session: use the web key manager.";
|
|
90347
|
+
async function keysLimits(args, ctx) {
|
|
90348
|
+
const { deps, apiUrl, json } = ctx;
|
|
90349
|
+
const parsed = parseArgs(args, { keyPrefixPositional: true });
|
|
90350
|
+
if ("error" in parsed) {
|
|
90351
|
+
writeScreenUsageFailure(deps, parsed.error, json);
|
|
90352
|
+
return 2;
|
|
90353
|
+
}
|
|
90354
|
+
const target = parsed.positionals[0];
|
|
90355
|
+
const caps = parsed.positionals.slice(1);
|
|
90356
|
+
if (!target || caps.length === 0) {
|
|
90357
|
+
writeScreenUsageFailure(deps, USAGE8, json);
|
|
90358
|
+
return 2;
|
|
90359
|
+
}
|
|
90360
|
+
const limits = [];
|
|
90361
|
+
for (const cap of caps) {
|
|
90362
|
+
const eq = cap.indexOf("=");
|
|
90363
|
+
const asset = (eq < 0 ? cap : cap.slice(0, eq)).toLowerCase();
|
|
90364
|
+
const raw = eq < 0 ? "" : cap.slice(eq + 1);
|
|
90365
|
+
if (!(asset in KEY_LIMIT_ASSETS)) {
|
|
90366
|
+
writeScreenUsageFailure(deps, `The asset must be one of: ${Object.keys(KEY_LIMIT_ASSETS).join(", ")}.`, json);
|
|
90367
|
+
return 2;
|
|
90368
|
+
}
|
|
90369
|
+
if (!RAW_AMOUNT.test(raw)) {
|
|
90370
|
+
writeScreenUsageFailure(deps, `${asset}=<raw> takes a positive whole number of base units (${asset} has ${KEY_LIMIT_ASSETS[asset]} decimals), with no sign, decimal point or leading zero.`, json);
|
|
90371
|
+
return 2;
|
|
90372
|
+
}
|
|
90373
|
+
if (limits.some((limit) => limit.asset === asset)) {
|
|
90374
|
+
writeScreenUsageFailure(deps, `${asset} is named twice.`, json);
|
|
90375
|
+
return 2;
|
|
90376
|
+
}
|
|
90377
|
+
limits.push({ asset, maxPerTxRaw: raw });
|
|
90378
|
+
}
|
|
90379
|
+
await printIdentity(ctx);
|
|
90380
|
+
const apiKey = await resolveApiKey(deps, ctx.profile);
|
|
90381
|
+
if (!apiKey) {
|
|
90382
|
+
writeScreenLocalFailure(deps, NO_API_KEY3, json);
|
|
90383
|
+
return 1;
|
|
90384
|
+
}
|
|
90385
|
+
const result = await apiRequest(`/api/v1/agent/keys/${encodeURIComponent(target)}/limits`, {
|
|
90386
|
+
method: "PUT",
|
|
90387
|
+
auth: "key",
|
|
90388
|
+
credentials: { apiKey },
|
|
90389
|
+
apiUrl,
|
|
90390
|
+
fetch: deps.fetch,
|
|
90391
|
+
env: deps.env,
|
|
90392
|
+
body: { limits }
|
|
90393
|
+
});
|
|
90394
|
+
if (!result.ok) {
|
|
90395
|
+
if (!json && result.code === "LOOSEN_REQUIRES_SESSION")
|
|
90396
|
+
writeScreenLocalFailure(deps, {
|
|
90397
|
+
code: "LOOSEN_REQUIRES_SESSION",
|
|
90398
|
+
message: "That would raise or remove a cap; nothing changed.",
|
|
90399
|
+
suggestion: LOOSEN_HINT
|
|
90400
|
+
}, json);
|
|
90401
|
+
else
|
|
90402
|
+
writeScreenFailure(deps, result, { apiUrl, authType: "key" }, json);
|
|
90403
|
+
return 1;
|
|
90404
|
+
}
|
|
90405
|
+
const stored = result.body.limits ?? limits;
|
|
90406
|
+
if (json) {
|
|
90407
|
+
deps.stdout.write(`${JSON.stringify({ ok: true, keyPrefix: target, limits: stored })}
|
|
90408
|
+
`);
|
|
90409
|
+
return 0;
|
|
90410
|
+
}
|
|
90411
|
+
const style = terminalStyle(deps, "stdout");
|
|
90412
|
+
const rows = [
|
|
90413
|
+
["Key", target],
|
|
90414
|
+
...stored.map((limit) => [limit.asset, `${limit.maxPerTxRaw} base units per transaction`])
|
|
90415
|
+
];
|
|
90416
|
+
deps.stdout.write(`${success("Per-asset caps updated", style)}
|
|
90417
|
+
|
|
90418
|
+
${heading("Caps", style)}
|
|
90419
|
+
${fields(rows, style).join(`
|
|
90420
|
+
`)}
|
|
90421
|
+
`);
|
|
90422
|
+
return 0;
|
|
90423
|
+
}
|
|
90424
|
+
|
|
90266
90425
|
// src/commands/keys-rotate.ts
|
|
90267
90426
|
init_args();
|
|
90268
90427
|
init_client();
|
|
@@ -90292,7 +90451,7 @@ var TOKEN_PAGE_BODY_CAP_BYTES = 32 * 1024;
|
|
|
90292
90451
|
var TOKEN_PAGE_SECTIONS = ["thesis", "tokenomics", "lore"];
|
|
90293
90452
|
var FLAG_REASONS = ["spam", "scam", "abuse", "misleading", "unsafe_link", "other"];
|
|
90294
90453
|
var FLAG_DETAIL_LIMIT = 500;
|
|
90295
|
-
var
|
|
90454
|
+
var USAGE9 = {
|
|
90296
90455
|
about: "Usage: candle token about <address> [--chain solana|hood] [--capabilities]",
|
|
90297
90456
|
claim: "Usage: candle token claim <address> [--chain solana|hood] [--creator [--challenge [--message-out <path>] | --challenge-id <id> --signature <sig>]] [--idempotency-key <key>]",
|
|
90298
90457
|
section: `Usage: candle token section set <address> <thesis|tokenomics|lore> --file <path> --base-revision <n> [--clear] [--chain solana|hood] [--idempotency-key <key>]
|
|
@@ -90552,7 +90711,7 @@ function terminalTextKeepingLines(text3) {
|
|
|
90552
90711
|
`);
|
|
90553
90712
|
}
|
|
90554
90713
|
async function tokenAbout(args, ctx) {
|
|
90555
|
-
const usage4 = usageFor(ctx,
|
|
90714
|
+
const usage4 = usageFor(ctx, USAGE9.about);
|
|
90556
90715
|
const parsed = parseArgs(args, { valueFlags: ["--chain"], booleanFlags: ["--capabilities"] });
|
|
90557
90716
|
if ("error" in parsed)
|
|
90558
90717
|
return usage4(parsed.error);
|
|
@@ -90598,7 +90757,7 @@ async function tokenAbout(args, ctx) {
|
|
|
90598
90757
|
return 0;
|
|
90599
90758
|
}
|
|
90600
90759
|
async function tokenClaim(args, ctx) {
|
|
90601
|
-
const usage4 = usageFor(ctx,
|
|
90760
|
+
const usage4 = usageFor(ctx, USAGE9.claim);
|
|
90602
90761
|
const parsed = parseArgs(args, {
|
|
90603
90762
|
valueFlags: ["--chain", "--challenge-id", "--signature", "--message-out", "--idempotency-key"],
|
|
90604
90763
|
booleanFlags: ["--creator", "--challenge"],
|
|
@@ -90725,7 +90884,7 @@ var SECTION_FLAGS = {
|
|
|
90725
90884
|
restore: { valueFlags: ["--chain", "--version-id", "--base-revision", "--idempotency-key"], booleanFlags: [] }
|
|
90726
90885
|
};
|
|
90727
90886
|
async function tokenSection(args, ctx) {
|
|
90728
|
-
const usage4 = usageFor(ctx,
|
|
90887
|
+
const usage4 = usageFor(ctx, USAGE9.section);
|
|
90729
90888
|
const action = args[0];
|
|
90730
90889
|
if (action !== "set" && action !== "restore")
|
|
90731
90890
|
return usage4();
|
|
@@ -90818,7 +90977,7 @@ async function tokenSection(args, ctx) {
|
|
|
90818
90977
|
return 0;
|
|
90819
90978
|
}
|
|
90820
90979
|
async function tokenHistory(args, ctx) {
|
|
90821
|
-
const usage4 = usageFor(ctx,
|
|
90980
|
+
const usage4 = usageFor(ctx, USAGE9.history);
|
|
90822
90981
|
const parsed = parseArgs(args, { valueFlags: ["--chain", "--limit", "--cursor"] });
|
|
90823
90982
|
if ("error" in parsed)
|
|
90824
90983
|
return usage4(parsed.error);
|
|
@@ -90873,7 +91032,7 @@ More: --cursor ${data.nextCursor}
|
|
|
90873
91032
|
return 0;
|
|
90874
91033
|
}
|
|
90875
91034
|
async function tokenFlag(args, ctx) {
|
|
90876
|
-
const usage4 = usageFor(ctx,
|
|
91035
|
+
const usage4 = usageFor(ctx, USAGE9.flag);
|
|
90877
91036
|
const parsed = parseArgs(args, { valueFlags: ["--chain", "--content", "--reason", "--detail", "--idempotency-key"] });
|
|
90878
91037
|
if ("error" in parsed)
|
|
90879
91038
|
return usage4(parsed.error);
|
|
@@ -90968,7 +91127,7 @@ async function tokenUpdate(args, ctx) {
|
|
|
90968
91127
|
return 0;
|
|
90969
91128
|
}
|
|
90970
91129
|
async function tokenComment(args, ctx) {
|
|
90971
|
-
const usage4 = usageFor(ctx,
|
|
91130
|
+
const usage4 = usageFor(ctx, USAGE9.comment);
|
|
90972
91131
|
const parsed = parseArgs(args, { valueFlags: ["--chain", "--file", "--idempotency-key"], pathFlags: ["--file"] });
|
|
90973
91132
|
if ("error" in parsed)
|
|
90974
91133
|
return usage4(parsed.error);
|
|
@@ -91013,7 +91172,7 @@ async function tokenComment(args, ctx) {
|
|
|
91013
91172
|
return 0;
|
|
91014
91173
|
}
|
|
91015
91174
|
async function tokenComments(args, ctx) {
|
|
91016
|
-
const usage4 = usageFor(ctx,
|
|
91175
|
+
const usage4 = usageFor(ctx, USAGE9.comments);
|
|
91017
91176
|
const parsed = parseArgs(args, { valueFlags: ["--chain", "--limit", "--cursor"] });
|
|
91018
91177
|
if ("error" in parsed)
|
|
91019
91178
|
return usage4(parsed.error);
|
|
@@ -91100,7 +91259,7 @@ async function tokenPost(args, ctx) {
|
|
|
91100
91259
|
}
|
|
91101
91260
|
|
|
91102
91261
|
// src/commands/keys-rotate.ts
|
|
91103
|
-
var
|
|
91262
|
+
var USAGE10 = `Usage: candle keys rotate <prefix|label> [--grace <duration> | --now] [--force] [--yes] [--idempotency-key <key>]
|
|
91104
91263
|
candle keys rotate <prefix|label> --finish`;
|
|
91105
91264
|
var MAX_GRACE_SECONDS = 86400;
|
|
91106
91265
|
var DEFAULT_GRACE_SECONDS = 3600;
|
|
@@ -91127,7 +91286,7 @@ async function keysRotate(args, ctx) {
|
|
|
91127
91286
|
}
|
|
91128
91287
|
const target = parsed.positionals[0];
|
|
91129
91288
|
if (!target || parsed.positionals.length !== 1) {
|
|
91130
|
-
writeScreenUsageFailure(deps,
|
|
91289
|
+
writeScreenUsageFailure(deps, USAGE10, json);
|
|
91131
91290
|
return 2;
|
|
91132
91291
|
}
|
|
91133
91292
|
const finish = parsed.booleans.has("--finish");
|
|
@@ -91380,7 +91539,7 @@ init_presentation();
|
|
|
91380
91539
|
init_profiles();
|
|
91381
91540
|
init_render();
|
|
91382
91541
|
init_key_output();
|
|
91383
|
-
var
|
|
91542
|
+
var NO_API_KEY4 = {
|
|
91384
91543
|
code: "NO_API_KEY",
|
|
91385
91544
|
message: "No API key for this profile.",
|
|
91386
91545
|
suggestion: "Set CANDLE_API_KEY, or run `candle keys create` and store one."
|
|
@@ -91404,7 +91563,7 @@ async function keysWalletsList(args, ctx) {
|
|
|
91404
91563
|
await printIdentity(ctx);
|
|
91405
91564
|
const apiKey = await resolveApiKey(deps, ctx.profile);
|
|
91406
91565
|
if (!apiKey) {
|
|
91407
|
-
writeScreenLocalFailure(deps,
|
|
91566
|
+
writeScreenLocalFailure(deps, NO_API_KEY4, json);
|
|
91408
91567
|
return 1;
|
|
91409
91568
|
}
|
|
91410
91569
|
const result = await apiRequest(`/api/v1/agent/keys/${encodeURIComponent(prefix)}/wallets`, {
|
|
@@ -91470,7 +91629,7 @@ async function keysWalletsSet(args, ctx) {
|
|
|
91470
91629
|
await printIdentity(ctx);
|
|
91471
91630
|
const apiKey = await resolveApiKey(deps, ctx.profile);
|
|
91472
91631
|
if (!apiKey) {
|
|
91473
|
-
writeScreenLocalFailure(deps,
|
|
91632
|
+
writeScreenLocalFailure(deps, NO_API_KEY4, json);
|
|
91474
91633
|
return 1;
|
|
91475
91634
|
}
|
|
91476
91635
|
const result = await apiRequest(`/api/v1/agent/keys/${encodeURIComponent(prefix)}/wallets`, {
|
|
@@ -91525,7 +91684,7 @@ async function keysWalletsScope(args, ctx) {
|
|
|
91525
91684
|
await printIdentity(ctx);
|
|
91526
91685
|
const apiKey = await resolveApiKey(deps, ctx.profile);
|
|
91527
91686
|
if (!apiKey) {
|
|
91528
|
-
writeScreenLocalFailure(deps,
|
|
91687
|
+
writeScreenLocalFailure(deps, NO_API_KEY4, json);
|
|
91529
91688
|
return 1;
|
|
91530
91689
|
}
|
|
91531
91690
|
const result = await apiRequest(`/api/v1/agent/keys/${encodeURIComponent(prefix)}/wallet-scope`, {
|
|
@@ -92380,7 +92539,7 @@ function poolRequestFields(flags) {
|
|
|
92380
92539
|
|
|
92381
92540
|
// src/commands/launch.ts
|
|
92382
92541
|
init_swap();
|
|
92383
|
-
var
|
|
92542
|
+
var USAGE11 = `Usage: ${LAUNCH_USAGE}`;
|
|
92384
92543
|
var EMBEDDED_WALLET_NAMES = new Set(LAUNCH_DEFINITION.wallet.embeddedNames);
|
|
92385
92544
|
var LAUNCH_ARG_SPEC = {
|
|
92386
92545
|
valueFlags: [
|
|
@@ -92491,7 +92650,7 @@ async function launch(args, ctx) {
|
|
|
92491
92650
|
const dryRun = parsed.booleans.has("--dry-run");
|
|
92492
92651
|
const check = parsed.booleans.has("--check");
|
|
92493
92652
|
if (check && dryRun) {
|
|
92494
|
-
writeUsageFailure(ctx.deps, `--check and --dry-run are two different stops; pass one. ${
|
|
92653
|
+
writeUsageFailure(ctx.deps, `--check and --dry-run are two different stops; pass one. ${USAGE11}`, ctx.json);
|
|
92495
92654
|
return 2;
|
|
92496
92655
|
}
|
|
92497
92656
|
const fieldProblem = launchFieldProblem(flags);
|
|
@@ -92501,11 +92660,11 @@ async function launch(args, ctx) {
|
|
|
92501
92660
|
}
|
|
92502
92661
|
const curveProblem = curveFlagProblem(flags);
|
|
92503
92662
|
if (curveProblem) {
|
|
92504
|
-
writeUsageFailure(ctx.deps, `${curveProblem} ${
|
|
92663
|
+
writeUsageFailure(ctx.deps, `${curveProblem} ${USAGE11}`, ctx.json);
|
|
92505
92664
|
return 2;
|
|
92506
92665
|
}
|
|
92507
92666
|
if (flags["--image"] !== undefined && flags["--image-url"] !== undefined) {
|
|
92508
|
-
writeUsageFailure(ctx.deps, `Pass --image <path> or --image-url <https-url>, not both: a launch has one image. ${
|
|
92667
|
+
writeUsageFailure(ctx.deps, `Pass --image <path> or --image-url <https-url>, not both: a launch has one image. ${USAGE11}`, ctx.json);
|
|
92509
92668
|
return 2;
|
|
92510
92669
|
}
|
|
92511
92670
|
if (flags["--image-url"] !== undefined && !flags["--image-url"].startsWith("https://")) {
|
|
@@ -92518,24 +92677,24 @@ async function launch(args, ctx) {
|
|
|
92518
92677
|
}
|
|
92519
92678
|
const missingRequired = !flags["--name"] || !flags["--symbol"] || flags["--image"] === undefined && flags["--image-url"] === undefined || !flags["--wallet"];
|
|
92520
92679
|
if (parsed.positionals.length || !check && missingRequired || !validClientId(id)) {
|
|
92521
|
-
writeUsageFailure(ctx.deps,
|
|
92680
|
+
writeUsageFailure(ctx.deps, USAGE11, ctx.json);
|
|
92522
92681
|
return 2;
|
|
92523
92682
|
}
|
|
92524
92683
|
try {
|
|
92525
92684
|
poolRequestFields(flags);
|
|
92526
92685
|
} catch (error) {
|
|
92527
|
-
writeUsageFailure(ctx.deps, `${error.message}. ${
|
|
92686
|
+
writeUsageFailure(ctx.deps, `${error.message}. ${USAGE11}`, ctx.json);
|
|
92528
92687
|
return 2;
|
|
92529
92688
|
}
|
|
92530
92689
|
let feeWallet;
|
|
92531
92690
|
try {
|
|
92532
92691
|
feeWallet = feeWalletSelection(flags);
|
|
92533
92692
|
} catch (error) {
|
|
92534
|
-
writeUsageFailure(ctx.deps, `${error.message}. ${
|
|
92693
|
+
writeUsageFailure(ctx.deps, `${error.message}. ${USAGE11}`, ctx.json);
|
|
92535
92694
|
return 2;
|
|
92536
92695
|
}
|
|
92537
92696
|
if (parsed.booleans.has("--require-fee-wallet") && !feeWallet) {
|
|
92538
|
-
writeUsageFailure(ctx.deps, `--require-fee-wallet needs --fee-wallet <address>: pass the wallet this launch's fees earn to. ${
|
|
92697
|
+
writeUsageFailure(ctx.deps, `--require-fee-wallet needs --fee-wallet <address>: pass the wallet this launch's fees earn to. ${USAGE11}`, ctx.json);
|
|
92539
92698
|
return 2;
|
|
92540
92699
|
}
|
|
92541
92700
|
try {
|
|
@@ -92543,11 +92702,11 @@ async function launch(args, ctx) {
|
|
|
92543
92702
|
launchBuyRaw(flags["--buy"], 18);
|
|
92544
92703
|
const hinted = flagChain(flags);
|
|
92545
92704
|
if (hinted === "hood" && feeWalletGiven(flags)) {
|
|
92546
|
-
writeUsageFailure(ctx.deps, `--fee-wallet is Solana only; a Hood launch cannot take it. ${
|
|
92705
|
+
writeUsageFailure(ctx.deps, `--fee-wallet is Solana only; a Hood launch cannot take it. ${USAGE11}`, ctx.json);
|
|
92547
92706
|
return 2;
|
|
92548
92707
|
}
|
|
92549
92708
|
if (!check && hinted === "hood" && flags["--dex-version"] === undefined) {
|
|
92550
|
-
writeUsageFailure(ctx.deps, `A Hood launch needs --dex-version v3|v4. ${
|
|
92709
|
+
writeUsageFailure(ctx.deps, `A Hood launch needs --dex-version v3|v4. ${USAGE11}`, ctx.json);
|
|
92551
92710
|
return 2;
|
|
92552
92711
|
}
|
|
92553
92712
|
let image;
|
|
@@ -92565,7 +92724,7 @@ async function launch(args, ctx) {
|
|
|
92565
92724
|
let rules;
|
|
92566
92725
|
if (!check && launchRulesGiven(flags)) {
|
|
92567
92726
|
if (hinted === "hood") {
|
|
92568
|
-
writeUsageFailure(ctx.deps, `${LAUNCH_RULES_SOLANA_ONLY} ${
|
|
92727
|
+
writeUsageFailure(ctx.deps, `${LAUNCH_RULES_SOLANA_ONLY} ${USAGE11}`, ctx.json);
|
|
92569
92728
|
return 2;
|
|
92570
92729
|
}
|
|
92571
92730
|
try {
|
|
@@ -93385,7 +93544,7 @@ init_presentation();
|
|
|
93385
93544
|
init_render();
|
|
93386
93545
|
init_trading();
|
|
93387
93546
|
init_swap();
|
|
93388
|
-
var
|
|
93547
|
+
var USAGE12 = "Usage: candle launch status <mint-or-client-launch-id> [--wait]";
|
|
93389
93548
|
var LAUNCH_WAIT_MS = 10 * 60 * 1000;
|
|
93390
93549
|
var LAUNCH_WAIT_POLL_MS = 1e4;
|
|
93391
93550
|
var LIVE = new Set(["trading", "bonded", "migrated"]);
|
|
@@ -93431,7 +93590,7 @@ async function readStatus(ctx, key, id) {
|
|
|
93431
93590
|
async function launchStatus(args, ctx) {
|
|
93432
93591
|
const parsed = parseArgs(args, { booleanFlags: ["--wait"] });
|
|
93433
93592
|
if ("error" in parsed || parsed.positionals.length !== 1 || !validClientId(parsed.positionals[0] ?? "")) {
|
|
93434
|
-
writeUsageFailure(ctx.deps,
|
|
93593
|
+
writeUsageFailure(ctx.deps, USAGE12, ctx.json);
|
|
93435
93594
|
return 2;
|
|
93436
93595
|
}
|
|
93437
93596
|
const id = parsed.positionals[0];
|
|
@@ -93923,6 +94082,9 @@ var MCP_TOOL_NAMES = [
|
|
|
93923
94082
|
"candle_set_profile_wallets",
|
|
93924
94083
|
"candle_get_profile_pnl",
|
|
93925
94084
|
"candle_get_profile_trades",
|
|
94085
|
+
"candle_get_paper_inventory",
|
|
94086
|
+
"candle_get_profile_paper",
|
|
94087
|
+
"candle_get_account_pnl",
|
|
93926
94088
|
"candle_get_portfolio",
|
|
93927
94089
|
"candle_resolve_token",
|
|
93928
94090
|
"candle_execution_status",
|
|
@@ -99328,7 +99490,7 @@ init_swap();
|
|
|
99328
99490
|
init_vault_support();
|
|
99329
99491
|
var WITHDRAW_SCOPE = "perps:withdraw";
|
|
99330
99492
|
var ID_RE = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
99331
|
-
var
|
|
99493
|
+
var USAGE13 = "Usage: candle perps withdraw <amount> --to solana|hood [--wallet <evm tee>] [--id <id>] [--keystore <path>] | candle perps withdraw status <id>";
|
|
99332
99494
|
var WITHDRAW_POLL_MS = 10 * 60 * 1000;
|
|
99333
99495
|
var WITHDRAW_POLL_INTERVAL_MS = 5000;
|
|
99334
99496
|
var TERMINAL = new Set(["settled", "refunded", "failed"]);
|
|
@@ -99379,7 +99541,7 @@ async function withdrawStatus(ctx, id) {
|
|
|
99379
99541
|
async function perpsWithdraw(args, ctx) {
|
|
99380
99542
|
if (args[0] === "status") {
|
|
99381
99543
|
if (args.length !== 2 || !ID_RE.test(args[1]))
|
|
99382
|
-
return usage10(ctx,
|
|
99544
|
+
return usage10(ctx, USAGE13);
|
|
99383
99545
|
try {
|
|
99384
99546
|
return await withdrawStatus(ctx, args[1]);
|
|
99385
99547
|
} catch (error) {
|
|
@@ -99398,7 +99560,7 @@ async function perpsWithdraw(args, ctx) {
|
|
|
99398
99560
|
const [amount] = parsed.positionals;
|
|
99399
99561
|
const to = parsed.values["--to"];
|
|
99400
99562
|
if (parsed.positionals.length !== 1 || !amount || to !== "solana" && to !== "hood")
|
|
99401
|
-
return usage10(ctx,
|
|
99563
|
+
return usage10(ctx, USAGE13);
|
|
99402
99564
|
const amountMicros = parseWithdrawAmount(amount);
|
|
99403
99565
|
if (amountMicros === null)
|
|
99404
99566
|
return usage10(ctx, "The amount must be a positive USDC decimal with at most 6 decimals.");
|
|
@@ -101480,12 +101642,12 @@ function planPromotionLine2(table) {
|
|
|
101480
101642
|
init_presentation();
|
|
101481
101643
|
init_render();
|
|
101482
101644
|
init_key_output();
|
|
101483
|
-
var
|
|
101645
|
+
var USAGE14 = "Usage: candle plans";
|
|
101484
101646
|
async function plans(args, ctx) {
|
|
101485
101647
|
const parsed = parseArgs(args, {});
|
|
101486
101648
|
if ("error" in parsed || parsed.positionals.length > 0) {
|
|
101487
101649
|
writeScreenUsageFailure(ctx.deps, "error" in parsed ? `${parsed.error}
|
|
101488
|
-
${
|
|
101650
|
+
${USAGE14}` : USAGE14, ctx.json);
|
|
101489
101651
|
return 2;
|
|
101490
101652
|
}
|
|
101491
101653
|
const result = await apiRequest("/api/v1/agent/plans", {
|
|
@@ -102100,7 +102262,7 @@ function writePosition(ctx, p) {
|
|
|
102100
102262
|
// src/commands/pnl.ts
|
|
102101
102263
|
var CHAINS = ["solana", "hood"];
|
|
102102
102264
|
var CHAIN_TITLES = { solana: "Solana", hood: "Hood" };
|
|
102103
|
-
var
|
|
102265
|
+
var NO_API_KEY5 = {
|
|
102104
102266
|
code: "NO_API_KEY",
|
|
102105
102267
|
message: "No API key for this profile.",
|
|
102106
102268
|
suggestion: "Set CANDLE_API_KEY, or run `candle auth login` to store one."
|
|
@@ -102119,7 +102281,7 @@ async function pnl(args, ctx) {
|
|
|
102119
102281
|
}
|
|
102120
102282
|
const apiKey = await resolveApiKey(deps, ctx.profile);
|
|
102121
102283
|
if (!apiKey) {
|
|
102122
|
-
writeLocalFailure(deps,
|
|
102284
|
+
writeLocalFailure(deps, NO_API_KEY5, json);
|
|
102123
102285
|
return 1;
|
|
102124
102286
|
}
|
|
102125
102287
|
const perProfile = ctx.profileFlag !== undefined;
|
|
@@ -102567,7 +102729,7 @@ var UNREAD_LABELS = {
|
|
|
102567
102729
|
usdg: "USDG",
|
|
102568
102730
|
"hood-tokens": "tokens"
|
|
102569
102731
|
};
|
|
102570
|
-
var
|
|
102732
|
+
var NO_API_KEY6 = {
|
|
102571
102733
|
code: "NO_API_KEY",
|
|
102572
102734
|
message: "No API key for this profile.",
|
|
102573
102735
|
suggestion: "Set CANDLE_API_KEY, or run `candle auth login` to store one."
|
|
@@ -102602,7 +102764,7 @@ async function portfolio(args, ctx) {
|
|
|
102602
102764
|
}
|
|
102603
102765
|
const apiKey = await resolveApiKey(deps, ctx.profile);
|
|
102604
102766
|
if (!apiKey) {
|
|
102605
|
-
writeLocalFailure(deps,
|
|
102767
|
+
writeLocalFailure(deps, NO_API_KEY6, ctx.json);
|
|
102606
102768
|
return 1;
|
|
102607
102769
|
}
|
|
102608
102770
|
let solana;
|
|
@@ -103673,7 +103835,7 @@ candle profile use <name>`);
|
|
|
103673
103835
|
init_args();
|
|
103674
103836
|
init_deps();
|
|
103675
103837
|
init_key_output();
|
|
103676
|
-
var
|
|
103838
|
+
var USAGE15 = 'Usage: candle quant ask "<text>" [--timeout <s>] [--json]';
|
|
103677
103839
|
var QUANT_ASK_DEFAULT_TIMEOUT_S = 300;
|
|
103678
103840
|
var QUANT_ASK_MAX_TIMEOUT_S = 3600;
|
|
103679
103841
|
var QUANT_ASK_SEND_TRIES = 3;
|
|
@@ -103842,7 +104004,7 @@ async function quantAsk(args, ctx) {
|
|
|
103842
104004
|
const timeoutS = timeoutRaw === undefined ? QUANT_ASK_DEFAULT_TIMEOUT_S : Number(timeoutRaw);
|
|
103843
104005
|
const text4 = "error" in parsed ? "" : parsed.positionals[0] ?? "";
|
|
103844
104006
|
if ("error" in parsed || parsed.positionals.length !== 1 || !text4.trim() || !Number.isInteger(timeoutS) || timeoutS < 1 || timeoutS > QUANT_ASK_MAX_TIMEOUT_S) {
|
|
103845
|
-
writeScreenUsageFailure(ctx.deps,
|
|
104007
|
+
writeScreenUsageFailure(ctx.deps, USAGE15, ctx.json);
|
|
103846
104008
|
return 2;
|
|
103847
104009
|
}
|
|
103848
104010
|
const apiKey = await resolveApiKey(ctx.deps, ctx.profile);
|
|
@@ -104051,7 +104213,7 @@ init_client();
|
|
|
104051
104213
|
init_human_output();
|
|
104052
104214
|
init_presentation();
|
|
104053
104215
|
init_render();
|
|
104054
|
-
var
|
|
104216
|
+
var USAGE16 = "Usage: candle scan <contract address> [--chain solana|hood] [--json]";
|
|
104055
104217
|
var OTHER_CHAIN = "Candle trades Solana and Hood today; that is not a Solana or Hood contract address.";
|
|
104056
104218
|
var HOOD_ADDRESS = /^0x[0-9a-fA-F]{40}$/;
|
|
104057
104219
|
var SOLANA_ADDRESS = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
|
|
@@ -104151,20 +104313,20 @@ async function scan(args, ctx) {
|
|
|
104151
104313
|
}
|
|
104152
104314
|
const named = parsed.values["--chain"];
|
|
104153
104315
|
if (parsed.positionals.length !== 1 || named !== undefined && named !== "solana" && named !== "hood") {
|
|
104154
|
-
writeUsageFailure(ctx.deps,
|
|
104316
|
+
writeUsageFailure(ctx.deps, USAGE16, ctx.json);
|
|
104155
104317
|
return 2;
|
|
104156
104318
|
}
|
|
104157
104319
|
const address = parsed.positionals[0].trim();
|
|
104158
104320
|
const found = chainOfAddress(address);
|
|
104159
104321
|
if (found === null) {
|
|
104160
104322
|
writeUsageFailure(ctx.deps, `${OTHER_CHAIN}
|
|
104161
|
-
${
|
|
104323
|
+
${USAGE16}`, ctx.json);
|
|
104162
104324
|
return 2;
|
|
104163
104325
|
}
|
|
104164
104326
|
if (named !== undefined && named !== found) {
|
|
104165
104327
|
const label = (c) => c === "hood" ? "Hood" : "Solana";
|
|
104166
104328
|
writeUsageFailure(ctx.deps, `That address is a ${label(found)} contract, not a ${label(named)} one. Candle trades Solana and Hood today.
|
|
104167
|
-
${
|
|
104329
|
+
${USAGE16}`, ctx.json);
|
|
104168
104330
|
return 2;
|
|
104169
104331
|
}
|
|
104170
104332
|
const chain2 = found;
|
|
@@ -106042,7 +106204,7 @@ init_deps();
|
|
|
106042
106204
|
init_human_output();
|
|
106043
106205
|
init_render();
|
|
106044
106206
|
var KINDS = ["trade", "signal", "callout"];
|
|
106045
|
-
var
|
|
106207
|
+
var USAGE17 = "Usage: candle token events <mint> [--chain solana|hood] [--kind trade|signal|callout] [--since <iso-8601>] [--limit <n>] [--before <cursor>] [--json]";
|
|
106046
106208
|
function readEventsBody(body) {
|
|
106047
106209
|
if (body === null || typeof body !== "object" || !Array.isArray(body.events))
|
|
106048
106210
|
return null;
|
|
@@ -106100,11 +106262,11 @@ async function tokenEvents(args, ctx) {
|
|
|
106100
106262
|
const since = parsed.values["--since"];
|
|
106101
106263
|
const before = parsed.values["--before"];
|
|
106102
106264
|
if (parsed.positionals.length !== 1 || chain2 !== "solana" && chain2 !== "hood") {
|
|
106103
|
-
writeUsageFailure(ctx.deps,
|
|
106265
|
+
writeUsageFailure(ctx.deps, USAGE17, ctx.json);
|
|
106104
106266
|
return 2;
|
|
106105
106267
|
}
|
|
106106
106268
|
if (kind !== undefined && !KINDS.includes(kind)) {
|
|
106107
|
-
writeUsageFailure(ctx.deps,
|
|
106269
|
+
writeUsageFailure(ctx.deps, USAGE17, ctx.json);
|
|
106108
106270
|
return 2;
|
|
106109
106271
|
}
|
|
106110
106272
|
if (limit !== undefined && !/^[1-9][0-9]{0,3}$/.test(limit) || Number(limit) > 1000) {
|
|
@@ -106443,7 +106605,7 @@ init_render();
|
|
|
106443
106605
|
init_solana_verify();
|
|
106444
106606
|
init_trading();
|
|
106445
106607
|
init_swap();
|
|
106446
|
-
var
|
|
106608
|
+
var USAGE18 = "Usage: candle transfer --to <address|wallet name|allowlist label|vault> --asset <SOL|USDC|CNDL|ETH|USDG>|--mint <mint>|--token <0x...> --amount <decimal|max> [--wallet <name>] [--rpc-url <url>] [--yes] [--json]";
|
|
106447
106609
|
var TRANSFER_ASSETS = [...Object.keys(BASES), ...Object.keys(HOOD_BASES)];
|
|
106448
106610
|
var BASE58_ADDRESS = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
|
|
106449
106611
|
async function readLinkedWallets(ctx, key) {
|
|
@@ -106588,7 +106750,7 @@ async function transfer(args, ctx) {
|
|
|
106588
106750
|
const flags2 = parsed.values;
|
|
106589
106751
|
const asset = flags2["--asset"]?.toUpperCase();
|
|
106590
106752
|
if (parsed.positionals.length !== 0 || !flags2["--to"] || !flags2["--amount"] || [flags2["--asset"], flags2["--mint"], flags2["--token"]].filter(Boolean).length !== 1 || asset !== undefined && !TRANSFER_ASSETS.includes(asset) || flags2["--mint"] !== undefined && !BASE58_ADDRESS.test(flags2["--mint"]) || flags2["--token"] !== undefined && !checkEvmAddress(flags2["--token"]).ok) {
|
|
106591
|
-
writeUsageFailure(ctx.deps,
|
|
106753
|
+
writeUsageFailure(ctx.deps, USAGE18, ctx.json);
|
|
106592
106754
|
return 2;
|
|
106593
106755
|
}
|
|
106594
106756
|
const to = flags2["--to"];
|
|
@@ -109585,7 +109747,10 @@ async function createVault(request2, clock) {
|
|
|
109585
109747
|
if (raw === null) {
|
|
109586
109748
|
throw new VaultError("VAULT_WRITE_FAILED", `The vault was written to ${request2.path} but could not be read back.`);
|
|
109587
109749
|
}
|
|
109588
|
-
return unlockWithPassphrase(request2.path, raw, request2.passphrase, {
|
|
109750
|
+
return unlockWithPassphrase(request2.path, raw, request2.passphrase, {
|
|
109751
|
+
notice: request2.notice,
|
|
109752
|
+
derivationLabel: request2.verificationLabel
|
|
109753
|
+
});
|
|
109589
109754
|
}
|
|
109590
109755
|
|
|
109591
109756
|
// src/commands/vault-init.ts
|
|
@@ -109659,8 +109824,8 @@ async function runPhraseCeremony(ctx, vault, opts = {}) {
|
|
|
109659
109824
|
const { closeVault: closeVault2 } = await Promise.resolve().then(() => (init_store(), exports_store));
|
|
109660
109825
|
closeVault2(reopened);
|
|
109661
109826
|
}
|
|
109662
|
-
notice(deps, "stdout", "
|
|
109663
|
-
They do NOT restore any key imported from
|
|
109827
|
+
notice(deps, "stdout", "warning", `The 24 words below re-derive every key this vault derives, on any BIP-39 wallet, with no passphrase and no server.
|
|
109828
|
+
They do NOT restore any key you imported from an older wallet store; the vault file plus a factor does that.
|
|
109664
109829
|
Anyone who reads them can move every derived key's funds.
|
|
109665
109830
|
|
|
109666
109831
|
`);
|
|
@@ -109688,6 +109853,9 @@ Anyone who reads them can move every derived key's funds.
|
|
|
109688
109853
|
}
|
|
109689
109854
|
deps.stdout.write(`
|
|
109690
109855
|
`);
|
|
109856
|
+
await deps.promptLine("Press Enter when you have saved the 24 words offline; the screen will clear for the check: ");
|
|
109857
|
+
deps.stdout.write("\x1B[2J\x1B[H");
|
|
109858
|
+
notice(deps, "stdout", "warning", "The phrase is no longer on screen. Clear your terminal's scrollback: the words were rendered there and this CLI cannot remove them.");
|
|
109691
109859
|
const positions = randomPositions(3, words.length);
|
|
109692
109860
|
let confirmed = true;
|
|
109693
109861
|
for (const position of positions) {
|
|
@@ -109696,8 +109864,6 @@ Anyone who reads them can move every derived key's funds.
|
|
|
109696
109864
|
confirmed = false;
|
|
109697
109865
|
}
|
|
109698
109866
|
deps.stdout.write("\x1B[2J\x1B[H");
|
|
109699
|
-
notice(deps, "stdout", "warning", `The phrase is no longer on screen. Clear your terminal's scrollback: the words were rendered there and this CLI cannot remove them.
|
|
109700
|
-
`.trim());
|
|
109701
109867
|
notice(deps, "stdout", "warning", `This vault now records that the recovery phrase was exported; that record never resets.
|
|
109702
109868
|
`.trim());
|
|
109703
109869
|
words.fill("");
|
|
@@ -109768,7 +109934,8 @@ async function vaultInit(args, ctx) {
|
|
|
109768
109934
|
strength: strengthFor(own),
|
|
109769
109935
|
rootEntropy,
|
|
109770
109936
|
label: parsed.values["--label"],
|
|
109771
|
-
notice: (line) => deps.stderr.write(line)
|
|
109937
|
+
notice: (line) => deps.stderr.write(line),
|
|
109938
|
+
verificationLabel: "Verifying the vault key"
|
|
109772
109939
|
}, deps));
|
|
109773
109940
|
try {
|
|
109774
109941
|
if (ctx.json) {
|
|
@@ -109798,12 +109965,13 @@ async function vaultInit(args, ctx) {
|
|
|
109798
109965
|
["Verified", "file re-read, opened with your passphrase, root blob decrypted"],
|
|
109799
109966
|
["Create a key", "candle vault new-key --chain solana"]
|
|
109800
109967
|
]);
|
|
109801
|
-
|
|
109968
|
+
if (deps.platform === "darwin")
|
|
109969
|
+
notice(deps, "stdout", "note", `
|
|
109802
109970
|
${APPLE_ACCOUNT_NOTICE}
|
|
109803
109971
|
`.trim());
|
|
109804
109972
|
if (countRecoverableFactors(vault.file.envelopes) === 1) {
|
|
109805
109973
|
notice(deps, "stdout", "warning", `
|
|
109806
|
-
This vault has exactly one recoverable factor: the passphrase. Lose it and no copy of this file can be opened, and the recovery phrase becomes the only route back.
|
|
109974
|
+
This vault has exactly one recoverable factor: the passphrase. Lose it and no copy of this file can be opened, and the recovery phrase becomes the only route back. To add a security key later, run this separate optional command: candle vault enroll security-key
|
|
109807
109975
|
`.trim());
|
|
109808
109976
|
}
|
|
109809
109977
|
notice(deps, "stdout", "note", `
|
|
@@ -111358,7 +111526,7 @@ async function promoteEvmFresh(input, fromLabel) {
|
|
|
111358
111526
|
addKeys: [blob]
|
|
111359
111527
|
}, ctx.deps));
|
|
111360
111528
|
scanStart = await appendScanStart(ctx, vault.path, address, height);
|
|
111361
|
-
await confirmAddress(ctx, "vault", destination.address, `
|
|
111529
|
+
await confirmAddress(ctx, "vault", destination.address, `promote a new TEE wallet with pinned vault ${destination.address}`);
|
|
111362
111530
|
if (toKey !== undefined) {
|
|
111363
111531
|
notice(ctx.deps, "stderr", "note", `${[toKeyPlanLine(toKey), ...signerStaysLines(toKey), ...targetWarnings(toKey.target, "evm")].join(`
|
|
111364
111532
|
`)}
|
|
@@ -111738,7 +111906,7 @@ async function promoteFresh(ctx, parsed, fromLabel, toKey) {
|
|
|
111738
111906
|
},
|
|
111739
111907
|
addKeys: [blob]
|
|
111740
111908
|
}, ctx.deps));
|
|
111741
|
-
await confirmAddress(ctx, "vault", destination.address, `
|
|
111909
|
+
await confirmAddress(ctx, "vault", destination.address, `promote a new TEE wallet with pinned vault ${destination.address}`);
|
|
111742
111910
|
if (toKey !== undefined) {
|
|
111743
111911
|
notice(ctx.deps, "stderr", "note", `${[toKeyPlanLine(toKey), ...signerStaysLines(toKey), ...targetWarnings(toKey.target, "solana")].join(`
|
|
111744
111912
|
`)}
|
|
@@ -114249,8 +114417,8 @@ init_store();
|
|
|
114249
114417
|
init_vault_support();
|
|
114250
114418
|
var LIST_POINTER = "One line per key, with an optional SOL balance: candle vault list";
|
|
114251
114419
|
var NO_VERIFIED_BACKUP_NOTE = `No backup of this vault has ever been verified from this machine. If this file is lost, only the 24-word recovery phrase can rebuild it, and it rebuilds derived keys only. Take one now:
|
|
114252
|
-
candle vault backup --to <path
|
|
114253
|
-
on a Mac with iCloud Drive: candle vault backup --to icloud
|
|
114420
|
+
candle vault backup --to <path>`;
|
|
114421
|
+
var ICLOUD_BACKUP_LINE = "on a Mac with iCloud Drive: candle vault backup --to icloud";
|
|
114254
114422
|
async function vaultStatus(args, ctx) {
|
|
114255
114423
|
const parsed = parseArgs(args, {
|
|
114256
114424
|
valueFlags: ["--keystore"],
|
|
@@ -114392,7 +114560,8 @@ async function vaultStatus(args, ctx) {
|
|
|
114392
114560
|
notice(deps, "stdout", "note", "No vault.state.json beside this vault, so an older copy of it cannot be recognized on this machine.");
|
|
114393
114561
|
}
|
|
114394
114562
|
if (sidecar?.lastVerifiedBackupAt === undefined)
|
|
114395
|
-
notice(deps, "stdout", "warning", NO_VERIFIED_BACKUP_NOTE
|
|
114563
|
+
notice(deps, "stdout", "warning", deps.platform === "darwin" ? `${NO_VERIFIED_BACKUP_NOTE}
|
|
114564
|
+
${ICLOUD_BACKUP_LINE}` : NO_VERIFIED_BACKUP_NOTE);
|
|
114396
114565
|
if (legacyPresent) {
|
|
114397
114566
|
notice(deps, "stdout", "warning", `A legacy wallets.enc exists at ${legacy}; this CLI does not read it.
|
|
114398
114567
|
A key it holds that was imported is already a linked wallet, managed with: candle wallets
|
|
@@ -114698,7 +114867,7 @@ init_human_output();
|
|
|
114698
114867
|
init_release();
|
|
114699
114868
|
import { dirname as dirname13, join as join15 } from "node:path";
|
|
114700
114869
|
init_key_output();
|
|
114701
|
-
var
|
|
114870
|
+
var USAGE19 = "Usage: candle verify <file> --bundle <path> [--identity <uri>] [--issuer <url>]";
|
|
114702
114871
|
async function resolveIdentity(deps, bundlePath, flag) {
|
|
114703
114872
|
if (flag)
|
|
114704
114873
|
return { kind: "ok", uri: flag, provenance: "identity from --identity" };
|
|
@@ -114730,19 +114899,19 @@ async function verify(args, ctx) {
|
|
|
114730
114899
|
});
|
|
114731
114900
|
if ("error" in parsed) {
|
|
114732
114901
|
writeScreenUsageFailure(deps, `${parsed.error}
|
|
114733
|
-
${
|
|
114902
|
+
${USAGE19}`, json);
|
|
114734
114903
|
return 2;
|
|
114735
114904
|
}
|
|
114736
114905
|
const file = parsed.positionals[0];
|
|
114737
114906
|
if (parsed.positionals.length !== 1 || file === undefined) {
|
|
114738
114907
|
writeScreenUsageFailure(deps, `verify takes exactly one file.
|
|
114739
|
-
${
|
|
114908
|
+
${USAGE19}`, json);
|
|
114740
114909
|
return 2;
|
|
114741
114910
|
}
|
|
114742
114911
|
const bundlePath = parsed.values["--bundle"];
|
|
114743
114912
|
if (!bundlePath) {
|
|
114744
114913
|
writeScreenUsageFailure(deps, `--bundle is required.
|
|
114745
|
-
${
|
|
114914
|
+
${USAGE19}`, json);
|
|
114746
114915
|
return 2;
|
|
114747
114916
|
}
|
|
114748
114917
|
const resolved = await resolveIdentity(deps, bundlePath, parsed.values["--identity"]);
|
|
@@ -114756,7 +114925,7 @@ ${USAGE18}`, json);
|
|
|
114756
114925
|
}
|
|
114757
114926
|
if (resolved.kind === "absent") {
|
|
114758
114927
|
writeScreenUsageFailure(deps, `--identity is required: there is no latest.json beside ${bundlePath} to take the release version from.
|
|
114759
|
-
${
|
|
114928
|
+
${USAGE19}`, json);
|
|
114760
114929
|
return 2;
|
|
114761
114930
|
}
|
|
114762
114931
|
const identity4 = resolved.uri;
|
|
@@ -115015,7 +115184,7 @@ init_presentation();
|
|
|
115015
115184
|
init_profiles();
|
|
115016
115185
|
init_render();
|
|
115017
115186
|
init_key_output();
|
|
115018
|
-
var
|
|
115187
|
+
var USAGE20 = "Usage: candle wallets authorize [--no-browser] [--no-wait] [--timeout <seconds>] [--json]";
|
|
115019
115188
|
var AUTHORIZE_WAIT_DEFAULT_SECONDS = 600;
|
|
115020
115189
|
var AUTHORIZE_POLL_MS = 3000;
|
|
115021
115190
|
function authorizeUrl(apiUrl, portalOrigin) {
|
|
@@ -115038,12 +115207,12 @@ async function walletsAuthorize(args, ctx) {
|
|
|
115038
115207
|
const parsed = parseArgs(args, { booleanFlags: ["--no-browser", "--no-wait"], valueFlags: ["--timeout"] });
|
|
115039
115208
|
if ("error" in parsed) {
|
|
115040
115209
|
writeScreenUsageFailure(deps, `${parsed.error}
|
|
115041
|
-
${
|
|
115210
|
+
${USAGE20}`, json);
|
|
115042
115211
|
return 2;
|
|
115043
115212
|
}
|
|
115044
115213
|
if (parsed.positionals.length > 0) {
|
|
115045
115214
|
writeScreenUsageFailure(deps, `Unexpected argument: ${parsed.positionals[0]}
|
|
115046
|
-
${
|
|
115215
|
+
${USAGE20}`, json);
|
|
115047
115216
|
return 2;
|
|
115048
115217
|
}
|
|
115049
115218
|
let timeoutSeconds = AUTHORIZE_WAIT_DEFAULT_SECONDS;
|
|
@@ -115052,7 +115221,7 @@ ${USAGE19}`, json);
|
|
|
115052
115221
|
const n = Number(rawTimeout);
|
|
115053
115222
|
if (!Number.isInteger(n) || n <= 0) {
|
|
115054
115223
|
writeScreenUsageFailure(deps, `--timeout must be a whole number of seconds above 0, got ${rawTimeout}
|
|
115055
|
-
${
|
|
115224
|
+
${USAGE20}`, json);
|
|
115056
115225
|
return 2;
|
|
115057
115226
|
}
|
|
115058
115227
|
timeoutSeconds = n;
|
|
@@ -115159,7 +115328,7 @@ init_solana_lite();
|
|
|
115159
115328
|
init_trading();
|
|
115160
115329
|
init_swap();
|
|
115161
115330
|
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
115162
|
-
var
|
|
115331
|
+
var USAGE21 = "Usage: candle wallet close-empty [--wallet embedded|<tee address|label>] [--keep <mint>]... [--client-trade-id <id>] [--preview] [--yes] [--json]";
|
|
115163
115332
|
var BASE58_ADDRESS2 = /^[1-9A-HJ-NP-Za-km-z]{32,44}$/;
|
|
115164
115333
|
var LISTED_ROWS = 50;
|
|
115165
115334
|
var TOKEN_IX_CLOSE_ACCOUNT3 = 9;
|
|
@@ -115434,7 +115603,7 @@ async function closeTee(ctx, key, wallet3, name2, run2) {
|
|
|
115434
115603
|
async function walletsCloseEmpty(args, ctx) {
|
|
115435
115604
|
const lifted = splitKeep(args);
|
|
115436
115605
|
if ("error" in lifted) {
|
|
115437
|
-
writeUsageFailure(ctx.deps, `${lifted.error}. ${
|
|
115606
|
+
writeUsageFailure(ctx.deps, `${lifted.error}. ${USAGE21}`, ctx.json);
|
|
115438
115607
|
return 2;
|
|
115439
115608
|
}
|
|
115440
115609
|
const parsed = parseArgs(lifted.rest, {
|
|
@@ -115448,7 +115617,7 @@ async function walletsCloseEmpty(args, ctx) {
|
|
|
115448
115617
|
const named = parsed.values["--client-trade-id"];
|
|
115449
115618
|
const id = named ?? `close-${randomUUID16()}`;
|
|
115450
115619
|
if (parsed.positionals.length !== 0 || !validClientId(id) || !lifted.keep.every((m) => BASE58_ADDRESS2.test(m))) {
|
|
115451
|
-
writeUsageFailure(ctx.deps,
|
|
115620
|
+
writeUsageFailure(ctx.deps, USAGE21, ctx.json);
|
|
115452
115621
|
return 2;
|
|
115453
115622
|
}
|
|
115454
115623
|
const run2 = {
|
|
@@ -115956,6 +116125,7 @@ var COMMANDS = {
|
|
|
115956
116125
|
access: keysAccess,
|
|
115957
116126
|
update: keysUpdate,
|
|
115958
116127
|
limit: keysLimit,
|
|
116128
|
+
limits: keysLimits,
|
|
115959
116129
|
self: keysSelf,
|
|
115960
116130
|
rotate: keysRotate,
|
|
115961
116131
|
revoke: keysRevoke,
|
package/package.json
CHANGED