@haven_ai/cli 0.7.0-alpha.0 → 0.8.1-alpha.0

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/dist/cli.js CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { rm, mkdir, writeFile, chmod, readFile } from 'fs/promises';
2
+ import { rm, mkdir, writeFile, chmod, readFile, readdir } from 'fs/promises';
3
3
  import { homedir } from 'os';
4
4
  import { join, resolve } from 'path';
5
5
  import { spawn } from 'child_process';
6
+ import { createECDH } from 'crypto';
6
7
  import { emitKeypressEvents } from 'readline';
7
8
 
8
9
  // src/args.ts
@@ -147,6 +148,12 @@ function helpText() {
147
148
  " catalog list List payable services",
148
149
  " contacts list List your address book",
149
150
  "",
151
+ "Feedback:",
152
+ ' feedback submit "<text>" Send feedback or a bug report. Needs',
153
+ " `haven login`. It refuses to send text that",
154
+ " looks like a credential, but cannot catch",
155
+ " every secret shape \u2014 never include one.",
156
+ "",
150
157
  "Manage (backend-only \u2014 no on-chain signing):",
151
158
  " agents pause <id> Stop the agent spending; keeps its budget",
152
159
  " agents resume <id> Let it spend again",
@@ -313,7 +320,7 @@ function truncateAddress(address) {
313
320
  if (!address || address.length <= 12) return address;
314
321
  return `${address.slice(0, 6)}\u2026${address.slice(-4)}`;
315
322
  }
316
- var CHAIN_NAMES = { 100: "Gnosis", 8453: "Base" };
323
+ var CHAIN_NAMES = { 8453: "Base", 84532: "Base Sepolia" };
317
324
  function chainName(chainId) {
318
325
  return CHAIN_NAMES[chainId] ?? `chain ${chainId}`;
319
326
  }
@@ -367,11 +374,20 @@ var UsageError = class extends Error {
367
374
  var HavenCliError = class extends Error {
368
375
  exit;
369
376
  hint;
370
- constructor(message, exit, hint) {
377
+ /**
378
+ * #3597: additional typed fields merged into the `--json` error object
379
+ * (`error.layer`, `error.reason`, …) — for a refusal where the FREE-TEXT
380
+ * hint is not enough to branch on. `feedback submit`'s secret check is the
381
+ * first caller: an agent needs `error.layer` (which of the four checks
382
+ * refused) as a number, not a string it has to parse out of a sentence.
383
+ */
384
+ extra;
385
+ constructor(message, exit, hint, extra) {
371
386
  super(message);
372
387
  this.name = "HavenCliError";
373
388
  this.exit = exit;
374
389
  this.hint = hint;
390
+ this.extra = extra;
375
391
  }
376
392
  };
377
393
  function toFailure(err) {
@@ -380,7 +396,7 @@ function toFailure(err) {
380
396
  }
381
397
  if (err instanceof HavenCliError) {
382
398
  const code = err.exit === EXIT.notAuthenticated ? "not_authenticated" : err.exit === EXIT.refused ? "refused" : err.exit === EXIT.network ? "network" : "failed";
383
- return { code, exit: err.exit, message: err.message, hint: err.hint };
399
+ return { code, exit: err.exit, message: err.message, hint: err.hint, extra: err.extra };
384
400
  }
385
401
  if (err instanceof CliApiError) {
386
402
  if (err.status === 0) {
@@ -430,6 +446,11 @@ function createOutput(json, out, err) {
430
446
  const body = {
431
447
  ok: false,
432
448
  error: {
449
+ // `extra` spreads FIRST (#3597 round 2, N-a): it is per-command
450
+ // (e.g. the secret check's `layer`/`reason`), so it must never be
451
+ // able to clobber the contract fields every command shares —
452
+ // `code`, `message`, `hint` are spread AFTER and always win.
453
+ ...failure.extra ?? {},
433
454
  code: failure.code,
434
455
  message: failure.message,
435
456
  ...failure.hint ? { hint: failure.hint } : {}
@@ -443,7 +464,7 @@ ${failure.hint}` : failure.message);
443
464
  }
444
465
 
445
466
  // src/agent-guidance-text.ts
446
- var HAVEN_AGENT_RUNBOOK_MD = "# Haven for agents \u2014 set your user up to let you pay\n\nYou are an AI agent whose user has no Haven account yet, or has one but has not connected you.\n\n> Links below are paths on this same host: resolve them against the URL you fetched this file from.\n\n## What Haven is, in three sentences\n\nYour user gives you a **budget on their own account** \u2014 not their wallet, and not a key to their funds. The budget is a delegation they sign, enforced on-chain: a payment over it, to the wrong recipient, or past its expiry is refused at execution time, not by a dashboard promise. Haven constructs and relays the payments; you get an agent credential and a signing key made on your machine, and your user can revoke the budget without you and without Haven.\n\n## The sequence\n\nFour of the six steps are your user's \u2014 each needs a human signature or a human decision. The rest is yours. If they already have a funded account, start at step 3.\n\n1. **HUMAN \u2014 create the account.** Name, email, password, then a passkey (Face ID / Touch ID) or a wallet. Never offer to enter any of it: you must not have their password, and the passkey is bound to their device. With a terminal, `<packages.cli.one_liner> login --api <api-url>` afterwards gets you a scoped session for steps 3-4 (that flag or `HAVEN_API_URL`, on the first command \u2014 the session then remembers the backend; **the CLI's built-in default is Haven's hosted production backend**, so on any other deployment an omitted flag connects you somewhere real and wrong rather than failing) \u2014 they approve a code in the browser, you never hold their password. That command is the manifest's `packages.cli.one_liner` (`/.well-known/haven.json`) \u2014 run it as given: `packages.cli.channel` serves the full spec. Do not hold the process open while you wait: under `--json`, pass `--no-wait` to get the link object back at once, then poll it with `haven login --poll <device_code>` \u2014 one round per invocation, exit 3 while it is still pending, 0 once approved. It can set up agents and read the account; it cannot sign, approve a budget, move funds, or rotate any agent's keys.\n2. **HUMAN \u2014 fund it.** USDC only, no ETH: Haven sponsors the gas. `/.well-known/haven.json` names `chains.default` as the deployment's expected chain, but after login `haven wallets funding` prints the address, the amount and which chain in one place; confirm that chain before you message your user. Without a CLI session, the dashboard's funding card shows the address and amount and its Receive-funds screen names the chain; never assume one: a testnet deployment and production both call themselves Haven. Before you write that message, read the manifest: `environment` says whether this deployment is `production`, and each `chains.supported` entry says whether that chain is a `testnet`. Real money is at stake only on a non-testnet chain of a `production` deployment \u2014 tell your user which case theirs is.\n3. **HUMAN \u2014 create the agent, set its budget**, and paste you the **setup prompt** it hands back. With a CLI session (step 1) you can do this step yourself: `haven agents connect --name <n> --budget <amount> --token USDC --period <minutes>` prints the same connector command and approval link; add `--run` to do step 4 too.\n4. **YOU \u2014 run the connector command** in that prompt (below). It makes your signing key locally, registering only the public address.\n5. **HUMAN \u2014 approve the budget** with their passkey, in the Haven tab they created the agent in: it advances to the approval step by itself once your run registers.\n6. **YOU \u2014 verify, then pay.**\n\n## Budget changes later (second token, raise, revoke)\n\nThe first budget rides the setup above. After the agent exists, a CLI session can construct the LATER changes \u2014 a second token, a bigger amount, a recipient pin, a stop \u2014 and hand your user a link; the human still signs, every time:\n\n```\nhaven budget grant <agentId> --amount <n> --token USDC --period <minutes> [--recipient <address>] [--wait]\nhaven budget revoke <agentId> <delegationHash> [--wait]\n```\n\nThe CLI never signs: it prints a dashboard link, your user opens it and signs with their passkey or wallet. `--wait` polls until the human's signature lands. The hash for `revoke` is in `haven agents show <agentId>`.\n\n## Hand-off scripts\n\nSend these as your own message, `<host>` replaced by the host you fetched this file from. Say what you cannot do, not only what they must.\n\n**Before signup** (step 1):\n\n> I can do everything except the parts that need your signature. Please open `<host>/signup?next=/agents&via=agent` \u2014 name, email, password, then a passkey (Face ID / Touch ID) or a wallet. That is your account's key: I should not have it, and I will never ask for your password. Already have one? `<host>/login?next=/agents`.\n\n**At the passkey step:**\n\n> The passkey must be made on your own device \u2014 it is what keeps the account yours, so nobody, Haven included, can move your funds without you. If this browser cannot, open `<host>/onboarding?next=/agents` on your phone and finish there.\n\n**At funding** (step 2):\n\n> Your Haven account needs USDC before I can pay for anything \u2014 USDC only, no ETH: Haven sponsors the gas. Before you send anything, let me get you the exact address **and network** \u2014 `haven wallets funding` prints both, and the funding card on `<host>/dashboard` shows the same. Please do not send to an address or a chain I have not confirmed with you; a small amount first is fine.\n\n**At the budget** (step 3):\n\n> On `<host>/agents`, create an agent for me and set a budget \u2014 say 25 USDC per day. That is the limit I cannot exceed. It hands back a setup prompt: paste it to me and I run it here.\n\n**At budget approval** (step 5) \u2014 the moment your run reports that approval is required, before anything else. Send the first if your run carried `approval.url`, the second if it did not.\n\n> Setup is done on my side. Approve the budget here: <approval.url>. Approve it with your passkey; nothing can be spent until you do.\n\n> Setup is done on my side. Go back to the Haven tab where you created the agent \u2014 it should now be asking you to approve the budget. Approve it with your passkey; nothing can be spent until you do.\n\n## What you run\n\nThe setup prompt carries a **connector command** shaped like this:\n\n```\nnpx -y @haven_ai/connect@<channel> --setup EXAMPLE-SETUP-TOKEN-NOT-REAL --api <api-url> --ack-local-tools\n```\n\nRun the prompt's version, not this one: the token is one-time, the API URL is the backend's own, and `<channel>` is the npm tag your prompt names \u2014 never a tag you pick. The rules below come from that prompt, so \"me\" in them is your user, not Haven.\n\n- If you are an AI agent running this command yourself rather than a human pasting it, you should append --json: the connector then emits one machine-readable, secret-free result object on stdout with progress on stderr, and returns promptly instead of blocking while it waits for the budget approval.\n- When a --json outcome reports approval.required: true, your first action must be to relay the approval instruction to me in your own reply \u2014 if the outcome carries approval.url, give me that link; otherwise tell me to return to Haven and approve this agent's budget \u2014 before verifying the connection, restarting anything, or any other step. Never build that link yourself: relay the one the outcome gave you or none at all. Any restart the outcome asks for is a separate instruction to give me afterwards, once the approval is done.\n- If you ran the command without --json, the connector waits for the approval itself and prints its next steps when it finishes: relay the budget-approval instruction to me \u2014 the approval link if those steps printed one, otherwise that you need to return to Haven and approve this agent's budget \u2014 only if those printed next steps still ask for it. If they report the budget as already approved, there is nothing for me to approve.\n- Only two changes to the command above are permitted, and no others: appending --json, and \u2014 only if the connector refuses because it could not determine the agent runtime \u2014 re-running it once with --runtime <name> added, naming the harness you are running in, using one of the values that refusal lists. Never invent a runtime name and never change anything else.\n- Do not print private keys, API keys, credential file contents, or config secrets in chat or logs.\n\nIf the approval wait times out, nothing is lost \u2014 your agent is registered and the budget is still waiting to be approved. Send your user the `approval.url` your run reported, or, if it carried none, ask them to finish it in that same Haven tab. The outcome carries no setup id, so never assemble an approval link out of parts \u2014 relay the whole one it gave you or none at all.\n\n## How to verify\n\nCall `haven_get_agent`, one of the Haven MCP tools the connector wires into your runtime in step 4. It returns identity plus `spend_authority_readiness`:\n\n- `ready` \u2014 a budget is live; you can pay.\n- `needs_approval` \u2014 the connector finished, nobody approved yet. Ask your user again, in their Haven tab; there is no queue to wait in.\n- `revoked` \u2014 the credential is not active; ask your user to create a new agent.\n\n`ready` covers hosted identity and the budget only, not your local signer. Check that with `npx -y @haven_ai/connect@<channel> --doctor`, the same tag your prompt named \u2014 a separate command, so the two-changes rule does not bind it.\n\n## If you cannot open a browser\n\nNothing here needs you to. Steps 1-3 are links: hand your user the full `<host>/\u2026` URL and ask them to say when it is done. Step 5 is a link only when your run reported one in `approval.url` \u2014 otherwise it is the tab they already have open, as above. Then poll `haven_get_agent` until it reads `ready`. Do not route around the sign-in wall \u2014 it makes the account theirs, not yours.\n\n## If something breaks\n\nIf a Haven result carries `client_update`, that client is out of date: run its `upgrade_command` as given, then any repair line it prints, then retry. `required: true` means payments are refused until you do. What changed: [/releases](/releases).\n\n## Vocabulary\n\n| Term | What it is |\n|---|---|\n| **setup prompt** | The text the dashboard hands your user to paste to you. Carries the command and its rules. |\n| **connector command** | The `npx -y @haven_ai/connect@\u2026` line you run. One-time token, one use. |\n| **agent credential** | Your API key (`sk_agent_\u2026`), written to `~/.haven`. It identifies you; alone it cannot move money. |\n| **delegate key** | Your signing key, made on this machine and never sent anywhere. |\n| **budget** | The on-chain delegation your user signed. It authorises the payment; Haven constructs and relays it. |\n\nNext: [your agent hit a 402](/402.md) \xB7 [everything agent-readable](/llms.txt)\n";
467
+ var HAVEN_AGENT_RUNBOOK_MD = "# Haven for agents \u2014 set your user up to let you pay\n\nYou are an AI agent whose user has no Haven account yet, or has one but has not connected you.\n\n> Links below are paths on this same host: resolve them against the URL you fetched this file from.\n\n## What Haven is, in three sentences\n\nYour user gives you a **budget on their own account** \u2014 not their wallet, and not a key to their funds. The budget is a delegation they sign, enforced on-chain: a payment over it, to the wrong recipient, or past its expiry is refused at execution time, not by a dashboard promise. Haven constructs and relays the payments; you get an agent credential and a signing key made on your machine, and your user can revoke the budget without you and without Haven.\n\n## The sequence\n\nFour of the six steps are your user's \u2014 each needs a human signature or a human decision. The rest is yours. If they already have a funded account, start at step 3.\n\n1. **HUMAN \u2014 create the account.** Name, email, password, then a passkey (Face ID / Touch ID) or a wallet. Never offer to enter any of it: you must not have their password, and the passkey is bound to their device. With a terminal, `<packages.cli.one_liner> login --api <api-url>` afterwards gets you a scoped session for steps 3-4 (that flag or `HAVEN_API_URL`, on the first command \u2014 the session then remembers the backend; **the CLI's built-in default is Haven's hosted production backend**, so on any other deployment an omitted flag connects you somewhere real and wrong rather than failing) \u2014 they approve a code in the browser, you never hold their password. That command is the manifest's `packages.cli.one_liner` (`/.well-known/haven.json`) \u2014 run it as given: `packages.cli.channel` serves the full spec. Do not hold the process open while you wait: under `--json`, pass `--no-wait` to get the link object back at once, then poll it with `haven login --poll <device_code>` \u2014 one round per invocation, exit 3 while it is still pending, 0 once approved. It can set up agents and read the account; it cannot sign, approve a budget, move funds, or rotate any agent's keys.\n2. **HUMAN \u2014 fund it.** USDC only, no ETH: Haven sponsors the gas. `/.well-known/haven.json` names `chains.default` as the deployment's expected chain, but after login `haven wallets funding` prints the address, the amount and which chain in one place; confirm that chain before you message your user. Without a CLI session, the dashboard's funding card shows the address and amount and its Receive-funds screen names the chain; never assume one: a testnet deployment and production both call themselves Haven. Before you write that message, read the manifest: `environment` says whether this deployment is `production`, and each `chains.supported` entry says whether that chain is a `testnet`. Real money is at stake only on a non-testnet chain of a `production` deployment \u2014 tell your user which case theirs is.\n3. **HUMAN \u2014 create the agent, set its budget**, and paste you the **setup prompt** it hands back. With a CLI session (step 1) you can do this step yourself: `haven agents connect --name <n> --budget <amount> --token USDC --period <minutes>` prints the same connector command and approval link; add `--run` to do step 4 too.\n4. **YOU \u2014 run the connector command** in that prompt (see What you run). It makes your signing key locally, registering only the public address.\n5. **HUMAN \u2014 approve the budget** with their passkey, in the Haven tab they created the agent in: it advances to the approval step by itself once your run registers.\n6. **YOU \u2014 verify, then pay.**\n\n## Budget changes later (second token, raise, revoke)\n\nThe first budget rides the setup in The sequence. After the agent exists, a CLI session can construct the LATER changes \u2014 a second token, a bigger amount, a recipient pin, a stop \u2014 and hand your user a link; the human still signs, every time:\n\n```\nhaven budget grant <agentId> --amount <n> --token USDC --period <minutes> [--recipient <address>] [--wait]\nhaven budget revoke <agentId> <delegationHash> [--wait]\n```\n\nThe CLI never signs: it prints a dashboard link, your user opens it and signs with their passkey or wallet. `--wait` polls until the human's signature lands. The hash for `revoke` is in `haven agents show <agentId>`.\n\n## Hand-off scripts\n\nSend these as your own message, `<host>` replaced by the host you fetched this file from. Say what you cannot do, not only what they must.\n\n**Before signup** (step 1):\n\n> I can do everything except the parts that need your signature. Please open `<host>/signup?next=/agents&via=agent` \u2014 name, email, password, then a passkey (Face ID / Touch ID) or a wallet. That is your account's key: I should not have it, and I will never ask for your password. Already have one? `<host>/login?next=/agents`.\n\n**At the passkey step:**\n\n> The passkey must be made on your own device \u2014 it is what keeps the account yours, so nobody, Haven included, can move your funds without you. If this browser cannot, open `<host>/onboarding?next=/agents` on your phone and finish there.\n\n**At funding** (step 2):\n\n> Your Haven account needs USDC before I can pay for anything \u2014 USDC only, no ETH: Haven sponsors the gas. Before you send anything, let me get you the exact address **and network** \u2014 `haven wallets funding` prints both, and the funding card on `<host>/dashboard` shows the same. Please do not send to an address or a chain I have not confirmed with you; a small amount first is fine.\n\n**At the budget** (step 3):\n\n> On `<host>/agents`, create an agent for me and set a budget \u2014 say 25 USDC per day. That is the limit I cannot exceed. It hands back a setup prompt: paste it to me and I run it here.\n\n**At budget approval** (step 5) \u2014 the moment your run reports that approval is required, before anything else. Send the first if your run carried `approval.url`, the second if it did not.\n\n> Setup is done on my side. Approve the budget here: <approval.url>. Approve it with your passkey; nothing can be spent until you do.\n\n> Setup is done on my side. Go back to the Haven tab where you created the agent \u2014 it should now be asking you to approve the budget. Approve it with your passkey; nothing can be spent until you do.\n\n## What you run\n\nThe setup prompt carries a **connector command** shaped like this:\n\n```\nnpx -y @haven_ai/connect@<channel> --setup EXAMPLE-SETUP-TOKEN-NOT-REAL --api <api-url> --ack-local-tools\n```\n\nRun the prompt's version, not this one: the token is one-time, the API URL is the backend's own, and `<channel>` is the npm tag your prompt names \u2014 never a tag you pick. The rules below come from that prompt, so \"me\" in them is your user, not Haven.\n\n- If you are an AI agent running this command yourself rather than a human pasting it, you should append --json: the connector then emits one machine-readable, secret-free result object on stdout with progress on stderr, and returns promptly instead of blocking while it waits for the budget approval.\n- When a --json outcome reports approval.required: true, your first action must be to relay the approval instruction to me in your own reply \u2014 if the outcome carries approval.url, give me that link; otherwise tell me to return to Haven and approve this agent's budget \u2014 before verifying the connection, restarting anything, or any other step. Never build that link yourself: relay the one the outcome gave you or none at all. Any restart the outcome asks for is a separate instruction to give me afterwards, once the approval is done.\n- If you ran the command without --json, the connector waits for the approval itself and prints its next steps when it finishes: relay the budget-approval instruction to me \u2014 the approval link if those steps printed one, otherwise that you need to return to Haven and approve this agent's budget \u2014 only if those printed next steps still ask for it. If they report the budget as already approved, there is nothing for me to approve.\n- Only three changes to the command above are permitted, and no others: appending --json; re-running it once with --runtime <name> added, only if the connector refuses because it could not determine the agent runtime, naming the harness you are running in and using one of the values that refusal lists; and re-running it once with the one flag I chose added, only after I have answered a wiring_collision relay \u2014 --name <the suggested_name or a name I gave> to add alongside, or --replace to replace \u2014 keeping any change already made. If that re-run is refused too, relay the refusal to me and stop. Never invent a runtime name and never change anything else.\n- Do not print private keys, API keys, credential file contents, or config secrets in chat or logs.\n\nIf the approval wait times out, nothing is lost \u2014 your agent is registered and the budget is still waiting to be approved. Send your user the `approval.url` your run reported, or, if it carried none, ask them to finish it in that same Haven tab. The outcome carries no setup id, so never assemble an approval link out of parts \u2014 relay the whole one it gave you or none at all.\n\n## How to verify\n\nCall `haven_get_agent`, one of the Haven MCP tools the connector wires into your runtime in step 4. It returns identity plus `spend_authority_readiness`:\n\n- `ready` \u2014 a budget is live; you can pay.\n- `needs_approval` \u2014 the connector finished, nobody approved yet. Ask your user again, in their Haven tab; there is no queue to wait in.\n- `revoked` \u2014 the credential is not active; ask your user to create a new agent.\n\n`ready` covers hosted identity and the budget only, not your local signer. Check that with `npx -y @haven_ai/connect@<channel> --doctor`, the same tag your prompt named \u2014 a separate command, so the command-modification rule does not bind it.\n\n## If you cannot open a browser\n\nNothing here needs you to. Steps 1-3 \u2014 account, funding, budget \u2014 are links: hand your user the full `<host>/\u2026` URL and ask them to say when it is done. Step 5 is a link only when your run reported one in `approval.url` \u2014 otherwise it is the tab they already have open. Then poll `haven_get_agent` until it reads `ready`. Do not route around the sign-in wall \u2014 it makes the account theirs, not yours.\n\n## If something breaks\n\nIf a Haven result carries `client_update`, that client is out of date: run its `upgrade_command` as given, then any repair line it prints, then retry. `required: true` means payments are refused until you do. What changed: [/releases](/releases).\n\nSomething else wrong? `haven feedback submit \"<text>\"` sends it to Haven \u2014 it needs `haven login` first. Never put a credential in that text: no API key, no delegate key, no session token, no recovery phrase.\n\n## Vocabulary\n\n| Term | What it is |\n|---|---|\n| **setup prompt** | The text the dashboard hands your user to paste to you. Carries the command and its rules. |\n| **connector command** | The `npx -y @haven_ai/connect@\u2026` line you run. One-time token, one use. |\n| **agent credential** | Your API key (`sk_agent_\u2026`), written to `~/.haven`. It identifies you; alone it cannot move money. |\n| **delegate key** | Your signing key, made on this machine and never sent anywhere. |\n| **budget** | The on-chain delegation your user signed. It authorises the payment; Haven constructs and relays it. |\n\nNext: [your agent hit a 402](/402.md) \xB7 [everything agent-readable](/llms.txt)\n";
447
468
 
448
469
  // src/token.ts
449
470
  function sessionExpiry(token) {
@@ -616,9 +637,2515 @@ async function runConnector(connectorCommand, spawner, onStderr) {
616
637
  return { outcome, exitCode, stderr, stdoutNoise: noise };
617
638
  }
618
639
 
640
+ // ../../node_modules/@noble/hashes/esm/_u64.js
641
+ var U32_MASK64 = /* @__PURE__ */ BigInt(2 ** 32 - 1);
642
+ var _32n = /* @__PURE__ */ BigInt(32);
643
+ function fromBig(n, le = false) {
644
+ if (le)
645
+ return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
646
+ return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
647
+ }
648
+ function split(lst, le = false) {
649
+ const len = lst.length;
650
+ let Ah = new Uint32Array(len);
651
+ let Al = new Uint32Array(len);
652
+ for (let i = 0; i < len; i++) {
653
+ const { h, l } = fromBig(lst[i], le);
654
+ [Ah[i], Al[i]] = [h, l];
655
+ }
656
+ return [Ah, Al];
657
+ }
658
+ var rotlSH = (h, l, s) => h << s | l >>> 32 - s;
659
+ var rotlSL = (h, l, s) => l << s | h >>> 32 - s;
660
+ var rotlBH = (h, l, s) => l << s - 32 | h >>> 64 - s;
661
+ var rotlBL = (h, l, s) => h << s - 32 | l >>> 64 - s;
662
+
663
+ // ../../node_modules/@noble/hashes/esm/utils.js
664
+ function isBytes(a) {
665
+ return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array";
666
+ }
667
+ function anumber(n) {
668
+ if (!Number.isSafeInteger(n) || n < 0)
669
+ throw new Error("positive integer expected, got " + n);
670
+ }
671
+ function abytes(b, ...lengths) {
672
+ if (!isBytes(b))
673
+ throw new Error("Uint8Array expected");
674
+ if (lengths.length > 0 && !lengths.includes(b.length))
675
+ throw new Error("Uint8Array expected of length " + lengths + ", got length=" + b.length);
676
+ }
677
+ function aexists(instance, checkFinished = true) {
678
+ if (instance.destroyed)
679
+ throw new Error("Hash instance has been destroyed");
680
+ if (checkFinished && instance.finished)
681
+ throw new Error("Hash#digest() has already been called");
682
+ }
683
+ function aoutput(out, instance) {
684
+ abytes(out);
685
+ const min = instance.outputLen;
686
+ if (out.length < min) {
687
+ throw new Error("digestInto() expects output buffer of length at least " + min);
688
+ }
689
+ }
690
+ function u32(arr) {
691
+ return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
692
+ }
693
+ function clean(...arrays) {
694
+ for (let i = 0; i < arrays.length; i++) {
695
+ arrays[i].fill(0);
696
+ }
697
+ }
698
+ var isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
699
+ function byteSwap(word) {
700
+ return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255;
701
+ }
702
+ function byteSwap32(arr) {
703
+ for (let i = 0; i < arr.length; i++) {
704
+ arr[i] = byteSwap(arr[i]);
705
+ }
706
+ return arr;
707
+ }
708
+ var swap32IfBE = isLE ? (u) => u : byteSwap32;
709
+ function utf8ToBytes(str) {
710
+ if (typeof str !== "string")
711
+ throw new Error("string expected");
712
+ return new Uint8Array(new TextEncoder().encode(str));
713
+ }
714
+ function toBytes(data) {
715
+ if (typeof data === "string")
716
+ data = utf8ToBytes(data);
717
+ abytes(data);
718
+ return data;
719
+ }
720
+ var Hash = class {
721
+ };
722
+ function createHasher(hashCons) {
723
+ const hashC = (msg) => hashCons().update(toBytes(msg)).digest();
724
+ const tmp = hashCons();
725
+ hashC.outputLen = tmp.outputLen;
726
+ hashC.blockLen = tmp.blockLen;
727
+ hashC.create = () => hashCons();
728
+ return hashC;
729
+ }
730
+
731
+ // ../../node_modules/@noble/hashes/esm/sha3.js
732
+ var _0n = BigInt(0);
733
+ var _1n = BigInt(1);
734
+ var _2n = BigInt(2);
735
+ var _7n = BigInt(7);
736
+ var _256n = BigInt(256);
737
+ var _0x71n = BigInt(113);
738
+ var SHA3_PI = [];
739
+ var SHA3_ROTL = [];
740
+ var _SHA3_IOTA = [];
741
+ for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) {
742
+ [x, y] = [y, (2 * x + 3 * y) % 5];
743
+ SHA3_PI.push(2 * (5 * y + x));
744
+ SHA3_ROTL.push((round + 1) * (round + 2) / 2 % 64);
745
+ let t = _0n;
746
+ for (let j = 0; j < 7; j++) {
747
+ R = (R << _1n ^ (R >> _7n) * _0x71n) % _256n;
748
+ if (R & _2n)
749
+ t ^= _1n << (_1n << /* @__PURE__ */ BigInt(j)) - _1n;
750
+ }
751
+ _SHA3_IOTA.push(t);
752
+ }
753
+ var IOTAS = split(_SHA3_IOTA, true);
754
+ var SHA3_IOTA_H = IOTAS[0];
755
+ var SHA3_IOTA_L = IOTAS[1];
756
+ var rotlH = (h, l, s) => s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s);
757
+ var rotlL = (h, l, s) => s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s);
758
+ function keccakP(s, rounds = 24) {
759
+ const B = new Uint32Array(5 * 2);
760
+ for (let round = 24 - rounds; round < 24; round++) {
761
+ for (let x = 0; x < 10; x++)
762
+ B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
763
+ for (let x = 0; x < 10; x += 2) {
764
+ const idx1 = (x + 8) % 10;
765
+ const idx0 = (x + 2) % 10;
766
+ const B0 = B[idx0];
767
+ const B1 = B[idx0 + 1];
768
+ const Th = rotlH(B0, B1, 1) ^ B[idx1];
769
+ const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];
770
+ for (let y = 0; y < 50; y += 10) {
771
+ s[x + y] ^= Th;
772
+ s[x + y + 1] ^= Tl;
773
+ }
774
+ }
775
+ let curH = s[2];
776
+ let curL = s[3];
777
+ for (let t = 0; t < 24; t++) {
778
+ const shift = SHA3_ROTL[t];
779
+ const Th = rotlH(curH, curL, shift);
780
+ const Tl = rotlL(curH, curL, shift);
781
+ const PI = SHA3_PI[t];
782
+ curH = s[PI];
783
+ curL = s[PI + 1];
784
+ s[PI] = Th;
785
+ s[PI + 1] = Tl;
786
+ }
787
+ for (let y = 0; y < 50; y += 10) {
788
+ for (let x = 0; x < 10; x++)
789
+ B[x] = s[y + x];
790
+ for (let x = 0; x < 10; x++)
791
+ s[y + x] ^= ~B[(x + 2) % 10] & B[(x + 4) % 10];
792
+ }
793
+ s[0] ^= SHA3_IOTA_H[round];
794
+ s[1] ^= SHA3_IOTA_L[round];
795
+ }
796
+ clean(B);
797
+ }
798
+ var Keccak = class _Keccak extends Hash {
799
+ // NOTE: we accept arguments in bytes instead of bits here.
800
+ constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {
801
+ super();
802
+ this.pos = 0;
803
+ this.posOut = 0;
804
+ this.finished = false;
805
+ this.destroyed = false;
806
+ this.enableXOF = false;
807
+ this.blockLen = blockLen;
808
+ this.suffix = suffix;
809
+ this.outputLen = outputLen;
810
+ this.enableXOF = enableXOF;
811
+ this.rounds = rounds;
812
+ anumber(outputLen);
813
+ if (!(0 < blockLen && blockLen < 200))
814
+ throw new Error("only keccak-f1600 function is supported");
815
+ this.state = new Uint8Array(200);
816
+ this.state32 = u32(this.state);
817
+ }
818
+ clone() {
819
+ return this._cloneInto();
820
+ }
821
+ keccak() {
822
+ swap32IfBE(this.state32);
823
+ keccakP(this.state32, this.rounds);
824
+ swap32IfBE(this.state32);
825
+ this.posOut = 0;
826
+ this.pos = 0;
827
+ }
828
+ update(data) {
829
+ aexists(this);
830
+ data = toBytes(data);
831
+ abytes(data);
832
+ const { blockLen, state } = this;
833
+ const len = data.length;
834
+ for (let pos = 0; pos < len; ) {
835
+ const take = Math.min(blockLen - this.pos, len - pos);
836
+ for (let i = 0; i < take; i++)
837
+ state[this.pos++] ^= data[pos++];
838
+ if (this.pos === blockLen)
839
+ this.keccak();
840
+ }
841
+ return this;
842
+ }
843
+ finish() {
844
+ if (this.finished)
845
+ return;
846
+ this.finished = true;
847
+ const { state, suffix, pos, blockLen } = this;
848
+ state[pos] ^= suffix;
849
+ if ((suffix & 128) !== 0 && pos === blockLen - 1)
850
+ this.keccak();
851
+ state[blockLen - 1] ^= 128;
852
+ this.keccak();
853
+ }
854
+ writeInto(out) {
855
+ aexists(this, false);
856
+ abytes(out);
857
+ this.finish();
858
+ const bufferOut = this.state;
859
+ const { blockLen } = this;
860
+ for (let pos = 0, len = out.length; pos < len; ) {
861
+ if (this.posOut >= blockLen)
862
+ this.keccak();
863
+ const take = Math.min(blockLen - this.posOut, len - pos);
864
+ out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
865
+ this.posOut += take;
866
+ pos += take;
867
+ }
868
+ return out;
869
+ }
870
+ xofInto(out) {
871
+ if (!this.enableXOF)
872
+ throw new Error("XOF is not possible for this instance");
873
+ return this.writeInto(out);
874
+ }
875
+ xof(bytes) {
876
+ anumber(bytes);
877
+ return this.xofInto(new Uint8Array(bytes));
878
+ }
879
+ digestInto(out) {
880
+ aoutput(out, this);
881
+ if (this.finished)
882
+ throw new Error("digest() was already called");
883
+ this.writeInto(out);
884
+ this.destroy();
885
+ return out;
886
+ }
887
+ digest() {
888
+ return this.digestInto(new Uint8Array(this.outputLen));
889
+ }
890
+ destroy() {
891
+ this.destroyed = true;
892
+ clean(this.state);
893
+ }
894
+ _cloneInto(to) {
895
+ const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
896
+ to || (to = new _Keccak(blockLen, suffix, outputLen, enableXOF, rounds));
897
+ to.state32.set(this.state32);
898
+ to.pos = this.pos;
899
+ to.posOut = this.posOut;
900
+ to.finished = this.finished;
901
+ to.rounds = rounds;
902
+ to.suffix = suffix;
903
+ to.outputLen = outputLen;
904
+ to.enableXOF = enableXOF;
905
+ to.destroyed = this.destroyed;
906
+ return to;
907
+ }
908
+ };
909
+ var gen = (suffix, blockLen, outputLen) => createHasher(() => new Keccak(blockLen, suffix, outputLen));
910
+ var keccak_256 = /* @__PURE__ */ (() => gen(1, 136, 256 / 8))();
911
+
912
+ // ../../node_modules/@scure/bip39/esm/wordlists/english.js
913
+ var wordlist = `abandon
914
+ ability
915
+ able
916
+ about
917
+ above
918
+ absent
919
+ absorb
920
+ abstract
921
+ absurd
922
+ abuse
923
+ access
924
+ accident
925
+ account
926
+ accuse
927
+ achieve
928
+ acid
929
+ acoustic
930
+ acquire
931
+ across
932
+ act
933
+ action
934
+ actor
935
+ actress
936
+ actual
937
+ adapt
938
+ add
939
+ addict
940
+ address
941
+ adjust
942
+ admit
943
+ adult
944
+ advance
945
+ advice
946
+ aerobic
947
+ affair
948
+ afford
949
+ afraid
950
+ again
951
+ age
952
+ agent
953
+ agree
954
+ ahead
955
+ aim
956
+ air
957
+ airport
958
+ aisle
959
+ alarm
960
+ album
961
+ alcohol
962
+ alert
963
+ alien
964
+ all
965
+ alley
966
+ allow
967
+ almost
968
+ alone
969
+ alpha
970
+ already
971
+ also
972
+ alter
973
+ always
974
+ amateur
975
+ amazing
976
+ among
977
+ amount
978
+ amused
979
+ analyst
980
+ anchor
981
+ ancient
982
+ anger
983
+ angle
984
+ angry
985
+ animal
986
+ ankle
987
+ announce
988
+ annual
989
+ another
990
+ answer
991
+ antenna
992
+ antique
993
+ anxiety
994
+ any
995
+ apart
996
+ apology
997
+ appear
998
+ apple
999
+ approve
1000
+ april
1001
+ arch
1002
+ arctic
1003
+ area
1004
+ arena
1005
+ argue
1006
+ arm
1007
+ armed
1008
+ armor
1009
+ army
1010
+ around
1011
+ arrange
1012
+ arrest
1013
+ arrive
1014
+ arrow
1015
+ art
1016
+ artefact
1017
+ artist
1018
+ artwork
1019
+ ask
1020
+ aspect
1021
+ assault
1022
+ asset
1023
+ assist
1024
+ assume
1025
+ asthma
1026
+ athlete
1027
+ atom
1028
+ attack
1029
+ attend
1030
+ attitude
1031
+ attract
1032
+ auction
1033
+ audit
1034
+ august
1035
+ aunt
1036
+ author
1037
+ auto
1038
+ autumn
1039
+ average
1040
+ avocado
1041
+ avoid
1042
+ awake
1043
+ aware
1044
+ away
1045
+ awesome
1046
+ awful
1047
+ awkward
1048
+ axis
1049
+ baby
1050
+ bachelor
1051
+ bacon
1052
+ badge
1053
+ bag
1054
+ balance
1055
+ balcony
1056
+ ball
1057
+ bamboo
1058
+ banana
1059
+ banner
1060
+ bar
1061
+ barely
1062
+ bargain
1063
+ barrel
1064
+ base
1065
+ basic
1066
+ basket
1067
+ battle
1068
+ beach
1069
+ bean
1070
+ beauty
1071
+ because
1072
+ become
1073
+ beef
1074
+ before
1075
+ begin
1076
+ behave
1077
+ behind
1078
+ believe
1079
+ below
1080
+ belt
1081
+ bench
1082
+ benefit
1083
+ best
1084
+ betray
1085
+ better
1086
+ between
1087
+ beyond
1088
+ bicycle
1089
+ bid
1090
+ bike
1091
+ bind
1092
+ biology
1093
+ bird
1094
+ birth
1095
+ bitter
1096
+ black
1097
+ blade
1098
+ blame
1099
+ blanket
1100
+ blast
1101
+ bleak
1102
+ bless
1103
+ blind
1104
+ blood
1105
+ blossom
1106
+ blouse
1107
+ blue
1108
+ blur
1109
+ blush
1110
+ board
1111
+ boat
1112
+ body
1113
+ boil
1114
+ bomb
1115
+ bone
1116
+ bonus
1117
+ book
1118
+ boost
1119
+ border
1120
+ boring
1121
+ borrow
1122
+ boss
1123
+ bottom
1124
+ bounce
1125
+ box
1126
+ boy
1127
+ bracket
1128
+ brain
1129
+ brand
1130
+ brass
1131
+ brave
1132
+ bread
1133
+ breeze
1134
+ brick
1135
+ bridge
1136
+ brief
1137
+ bright
1138
+ bring
1139
+ brisk
1140
+ broccoli
1141
+ broken
1142
+ bronze
1143
+ broom
1144
+ brother
1145
+ brown
1146
+ brush
1147
+ bubble
1148
+ buddy
1149
+ budget
1150
+ buffalo
1151
+ build
1152
+ bulb
1153
+ bulk
1154
+ bullet
1155
+ bundle
1156
+ bunker
1157
+ burden
1158
+ burger
1159
+ burst
1160
+ bus
1161
+ business
1162
+ busy
1163
+ butter
1164
+ buyer
1165
+ buzz
1166
+ cabbage
1167
+ cabin
1168
+ cable
1169
+ cactus
1170
+ cage
1171
+ cake
1172
+ call
1173
+ calm
1174
+ camera
1175
+ camp
1176
+ can
1177
+ canal
1178
+ cancel
1179
+ candy
1180
+ cannon
1181
+ canoe
1182
+ canvas
1183
+ canyon
1184
+ capable
1185
+ capital
1186
+ captain
1187
+ car
1188
+ carbon
1189
+ card
1190
+ cargo
1191
+ carpet
1192
+ carry
1193
+ cart
1194
+ case
1195
+ cash
1196
+ casino
1197
+ castle
1198
+ casual
1199
+ cat
1200
+ catalog
1201
+ catch
1202
+ category
1203
+ cattle
1204
+ caught
1205
+ cause
1206
+ caution
1207
+ cave
1208
+ ceiling
1209
+ celery
1210
+ cement
1211
+ census
1212
+ century
1213
+ cereal
1214
+ certain
1215
+ chair
1216
+ chalk
1217
+ champion
1218
+ change
1219
+ chaos
1220
+ chapter
1221
+ charge
1222
+ chase
1223
+ chat
1224
+ cheap
1225
+ check
1226
+ cheese
1227
+ chef
1228
+ cherry
1229
+ chest
1230
+ chicken
1231
+ chief
1232
+ child
1233
+ chimney
1234
+ choice
1235
+ choose
1236
+ chronic
1237
+ chuckle
1238
+ chunk
1239
+ churn
1240
+ cigar
1241
+ cinnamon
1242
+ circle
1243
+ citizen
1244
+ city
1245
+ civil
1246
+ claim
1247
+ clap
1248
+ clarify
1249
+ claw
1250
+ clay
1251
+ clean
1252
+ clerk
1253
+ clever
1254
+ click
1255
+ client
1256
+ cliff
1257
+ climb
1258
+ clinic
1259
+ clip
1260
+ clock
1261
+ clog
1262
+ close
1263
+ cloth
1264
+ cloud
1265
+ clown
1266
+ club
1267
+ clump
1268
+ cluster
1269
+ clutch
1270
+ coach
1271
+ coast
1272
+ coconut
1273
+ code
1274
+ coffee
1275
+ coil
1276
+ coin
1277
+ collect
1278
+ color
1279
+ column
1280
+ combine
1281
+ come
1282
+ comfort
1283
+ comic
1284
+ common
1285
+ company
1286
+ concert
1287
+ conduct
1288
+ confirm
1289
+ congress
1290
+ connect
1291
+ consider
1292
+ control
1293
+ convince
1294
+ cook
1295
+ cool
1296
+ copper
1297
+ copy
1298
+ coral
1299
+ core
1300
+ corn
1301
+ correct
1302
+ cost
1303
+ cotton
1304
+ couch
1305
+ country
1306
+ couple
1307
+ course
1308
+ cousin
1309
+ cover
1310
+ coyote
1311
+ crack
1312
+ cradle
1313
+ craft
1314
+ cram
1315
+ crane
1316
+ crash
1317
+ crater
1318
+ crawl
1319
+ crazy
1320
+ cream
1321
+ credit
1322
+ creek
1323
+ crew
1324
+ cricket
1325
+ crime
1326
+ crisp
1327
+ critic
1328
+ crop
1329
+ cross
1330
+ crouch
1331
+ crowd
1332
+ crucial
1333
+ cruel
1334
+ cruise
1335
+ crumble
1336
+ crunch
1337
+ crush
1338
+ cry
1339
+ crystal
1340
+ cube
1341
+ culture
1342
+ cup
1343
+ cupboard
1344
+ curious
1345
+ current
1346
+ curtain
1347
+ curve
1348
+ cushion
1349
+ custom
1350
+ cute
1351
+ cycle
1352
+ dad
1353
+ damage
1354
+ damp
1355
+ dance
1356
+ danger
1357
+ daring
1358
+ dash
1359
+ daughter
1360
+ dawn
1361
+ day
1362
+ deal
1363
+ debate
1364
+ debris
1365
+ decade
1366
+ december
1367
+ decide
1368
+ decline
1369
+ decorate
1370
+ decrease
1371
+ deer
1372
+ defense
1373
+ define
1374
+ defy
1375
+ degree
1376
+ delay
1377
+ deliver
1378
+ demand
1379
+ demise
1380
+ denial
1381
+ dentist
1382
+ deny
1383
+ depart
1384
+ depend
1385
+ deposit
1386
+ depth
1387
+ deputy
1388
+ derive
1389
+ describe
1390
+ desert
1391
+ design
1392
+ desk
1393
+ despair
1394
+ destroy
1395
+ detail
1396
+ detect
1397
+ develop
1398
+ device
1399
+ devote
1400
+ diagram
1401
+ dial
1402
+ diamond
1403
+ diary
1404
+ dice
1405
+ diesel
1406
+ diet
1407
+ differ
1408
+ digital
1409
+ dignity
1410
+ dilemma
1411
+ dinner
1412
+ dinosaur
1413
+ direct
1414
+ dirt
1415
+ disagree
1416
+ discover
1417
+ disease
1418
+ dish
1419
+ dismiss
1420
+ disorder
1421
+ display
1422
+ distance
1423
+ divert
1424
+ divide
1425
+ divorce
1426
+ dizzy
1427
+ doctor
1428
+ document
1429
+ dog
1430
+ doll
1431
+ dolphin
1432
+ domain
1433
+ donate
1434
+ donkey
1435
+ donor
1436
+ door
1437
+ dose
1438
+ double
1439
+ dove
1440
+ draft
1441
+ dragon
1442
+ drama
1443
+ drastic
1444
+ draw
1445
+ dream
1446
+ dress
1447
+ drift
1448
+ drill
1449
+ drink
1450
+ drip
1451
+ drive
1452
+ drop
1453
+ drum
1454
+ dry
1455
+ duck
1456
+ dumb
1457
+ dune
1458
+ during
1459
+ dust
1460
+ dutch
1461
+ duty
1462
+ dwarf
1463
+ dynamic
1464
+ eager
1465
+ eagle
1466
+ early
1467
+ earn
1468
+ earth
1469
+ easily
1470
+ east
1471
+ easy
1472
+ echo
1473
+ ecology
1474
+ economy
1475
+ edge
1476
+ edit
1477
+ educate
1478
+ effort
1479
+ egg
1480
+ eight
1481
+ either
1482
+ elbow
1483
+ elder
1484
+ electric
1485
+ elegant
1486
+ element
1487
+ elephant
1488
+ elevator
1489
+ elite
1490
+ else
1491
+ embark
1492
+ embody
1493
+ embrace
1494
+ emerge
1495
+ emotion
1496
+ employ
1497
+ empower
1498
+ empty
1499
+ enable
1500
+ enact
1501
+ end
1502
+ endless
1503
+ endorse
1504
+ enemy
1505
+ energy
1506
+ enforce
1507
+ engage
1508
+ engine
1509
+ enhance
1510
+ enjoy
1511
+ enlist
1512
+ enough
1513
+ enrich
1514
+ enroll
1515
+ ensure
1516
+ enter
1517
+ entire
1518
+ entry
1519
+ envelope
1520
+ episode
1521
+ equal
1522
+ equip
1523
+ era
1524
+ erase
1525
+ erode
1526
+ erosion
1527
+ error
1528
+ erupt
1529
+ escape
1530
+ essay
1531
+ essence
1532
+ estate
1533
+ eternal
1534
+ ethics
1535
+ evidence
1536
+ evil
1537
+ evoke
1538
+ evolve
1539
+ exact
1540
+ example
1541
+ excess
1542
+ exchange
1543
+ excite
1544
+ exclude
1545
+ excuse
1546
+ execute
1547
+ exercise
1548
+ exhaust
1549
+ exhibit
1550
+ exile
1551
+ exist
1552
+ exit
1553
+ exotic
1554
+ expand
1555
+ expect
1556
+ expire
1557
+ explain
1558
+ expose
1559
+ express
1560
+ extend
1561
+ extra
1562
+ eye
1563
+ eyebrow
1564
+ fabric
1565
+ face
1566
+ faculty
1567
+ fade
1568
+ faint
1569
+ faith
1570
+ fall
1571
+ false
1572
+ fame
1573
+ family
1574
+ famous
1575
+ fan
1576
+ fancy
1577
+ fantasy
1578
+ farm
1579
+ fashion
1580
+ fat
1581
+ fatal
1582
+ father
1583
+ fatigue
1584
+ fault
1585
+ favorite
1586
+ feature
1587
+ february
1588
+ federal
1589
+ fee
1590
+ feed
1591
+ feel
1592
+ female
1593
+ fence
1594
+ festival
1595
+ fetch
1596
+ fever
1597
+ few
1598
+ fiber
1599
+ fiction
1600
+ field
1601
+ figure
1602
+ file
1603
+ film
1604
+ filter
1605
+ final
1606
+ find
1607
+ fine
1608
+ finger
1609
+ finish
1610
+ fire
1611
+ firm
1612
+ first
1613
+ fiscal
1614
+ fish
1615
+ fit
1616
+ fitness
1617
+ fix
1618
+ flag
1619
+ flame
1620
+ flash
1621
+ flat
1622
+ flavor
1623
+ flee
1624
+ flight
1625
+ flip
1626
+ float
1627
+ flock
1628
+ floor
1629
+ flower
1630
+ fluid
1631
+ flush
1632
+ fly
1633
+ foam
1634
+ focus
1635
+ fog
1636
+ foil
1637
+ fold
1638
+ follow
1639
+ food
1640
+ foot
1641
+ force
1642
+ forest
1643
+ forget
1644
+ fork
1645
+ fortune
1646
+ forum
1647
+ forward
1648
+ fossil
1649
+ foster
1650
+ found
1651
+ fox
1652
+ fragile
1653
+ frame
1654
+ frequent
1655
+ fresh
1656
+ friend
1657
+ fringe
1658
+ frog
1659
+ front
1660
+ frost
1661
+ frown
1662
+ frozen
1663
+ fruit
1664
+ fuel
1665
+ fun
1666
+ funny
1667
+ furnace
1668
+ fury
1669
+ future
1670
+ gadget
1671
+ gain
1672
+ galaxy
1673
+ gallery
1674
+ game
1675
+ gap
1676
+ garage
1677
+ garbage
1678
+ garden
1679
+ garlic
1680
+ garment
1681
+ gas
1682
+ gasp
1683
+ gate
1684
+ gather
1685
+ gauge
1686
+ gaze
1687
+ general
1688
+ genius
1689
+ genre
1690
+ gentle
1691
+ genuine
1692
+ gesture
1693
+ ghost
1694
+ giant
1695
+ gift
1696
+ giggle
1697
+ ginger
1698
+ giraffe
1699
+ girl
1700
+ give
1701
+ glad
1702
+ glance
1703
+ glare
1704
+ glass
1705
+ glide
1706
+ glimpse
1707
+ globe
1708
+ gloom
1709
+ glory
1710
+ glove
1711
+ glow
1712
+ glue
1713
+ goat
1714
+ goddess
1715
+ gold
1716
+ good
1717
+ goose
1718
+ gorilla
1719
+ gospel
1720
+ gossip
1721
+ govern
1722
+ gown
1723
+ grab
1724
+ grace
1725
+ grain
1726
+ grant
1727
+ grape
1728
+ grass
1729
+ gravity
1730
+ great
1731
+ green
1732
+ grid
1733
+ grief
1734
+ grit
1735
+ grocery
1736
+ group
1737
+ grow
1738
+ grunt
1739
+ guard
1740
+ guess
1741
+ guide
1742
+ guilt
1743
+ guitar
1744
+ gun
1745
+ gym
1746
+ habit
1747
+ hair
1748
+ half
1749
+ hammer
1750
+ hamster
1751
+ hand
1752
+ happy
1753
+ harbor
1754
+ hard
1755
+ harsh
1756
+ harvest
1757
+ hat
1758
+ have
1759
+ hawk
1760
+ hazard
1761
+ head
1762
+ health
1763
+ heart
1764
+ heavy
1765
+ hedgehog
1766
+ height
1767
+ hello
1768
+ helmet
1769
+ help
1770
+ hen
1771
+ hero
1772
+ hidden
1773
+ high
1774
+ hill
1775
+ hint
1776
+ hip
1777
+ hire
1778
+ history
1779
+ hobby
1780
+ hockey
1781
+ hold
1782
+ hole
1783
+ holiday
1784
+ hollow
1785
+ home
1786
+ honey
1787
+ hood
1788
+ hope
1789
+ horn
1790
+ horror
1791
+ horse
1792
+ hospital
1793
+ host
1794
+ hotel
1795
+ hour
1796
+ hover
1797
+ hub
1798
+ huge
1799
+ human
1800
+ humble
1801
+ humor
1802
+ hundred
1803
+ hungry
1804
+ hunt
1805
+ hurdle
1806
+ hurry
1807
+ hurt
1808
+ husband
1809
+ hybrid
1810
+ ice
1811
+ icon
1812
+ idea
1813
+ identify
1814
+ idle
1815
+ ignore
1816
+ ill
1817
+ illegal
1818
+ illness
1819
+ image
1820
+ imitate
1821
+ immense
1822
+ immune
1823
+ impact
1824
+ impose
1825
+ improve
1826
+ impulse
1827
+ inch
1828
+ include
1829
+ income
1830
+ increase
1831
+ index
1832
+ indicate
1833
+ indoor
1834
+ industry
1835
+ infant
1836
+ inflict
1837
+ inform
1838
+ inhale
1839
+ inherit
1840
+ initial
1841
+ inject
1842
+ injury
1843
+ inmate
1844
+ inner
1845
+ innocent
1846
+ input
1847
+ inquiry
1848
+ insane
1849
+ insect
1850
+ inside
1851
+ inspire
1852
+ install
1853
+ intact
1854
+ interest
1855
+ into
1856
+ invest
1857
+ invite
1858
+ involve
1859
+ iron
1860
+ island
1861
+ isolate
1862
+ issue
1863
+ item
1864
+ ivory
1865
+ jacket
1866
+ jaguar
1867
+ jar
1868
+ jazz
1869
+ jealous
1870
+ jeans
1871
+ jelly
1872
+ jewel
1873
+ job
1874
+ join
1875
+ joke
1876
+ journey
1877
+ joy
1878
+ judge
1879
+ juice
1880
+ jump
1881
+ jungle
1882
+ junior
1883
+ junk
1884
+ just
1885
+ kangaroo
1886
+ keen
1887
+ keep
1888
+ ketchup
1889
+ key
1890
+ kick
1891
+ kid
1892
+ kidney
1893
+ kind
1894
+ kingdom
1895
+ kiss
1896
+ kit
1897
+ kitchen
1898
+ kite
1899
+ kitten
1900
+ kiwi
1901
+ knee
1902
+ knife
1903
+ knock
1904
+ know
1905
+ lab
1906
+ label
1907
+ labor
1908
+ ladder
1909
+ lady
1910
+ lake
1911
+ lamp
1912
+ language
1913
+ laptop
1914
+ large
1915
+ later
1916
+ latin
1917
+ laugh
1918
+ laundry
1919
+ lava
1920
+ law
1921
+ lawn
1922
+ lawsuit
1923
+ layer
1924
+ lazy
1925
+ leader
1926
+ leaf
1927
+ learn
1928
+ leave
1929
+ lecture
1930
+ left
1931
+ leg
1932
+ legal
1933
+ legend
1934
+ leisure
1935
+ lemon
1936
+ lend
1937
+ length
1938
+ lens
1939
+ leopard
1940
+ lesson
1941
+ letter
1942
+ level
1943
+ liar
1944
+ liberty
1945
+ library
1946
+ license
1947
+ life
1948
+ lift
1949
+ light
1950
+ like
1951
+ limb
1952
+ limit
1953
+ link
1954
+ lion
1955
+ liquid
1956
+ list
1957
+ little
1958
+ live
1959
+ lizard
1960
+ load
1961
+ loan
1962
+ lobster
1963
+ local
1964
+ lock
1965
+ logic
1966
+ lonely
1967
+ long
1968
+ loop
1969
+ lottery
1970
+ loud
1971
+ lounge
1972
+ love
1973
+ loyal
1974
+ lucky
1975
+ luggage
1976
+ lumber
1977
+ lunar
1978
+ lunch
1979
+ luxury
1980
+ lyrics
1981
+ machine
1982
+ mad
1983
+ magic
1984
+ magnet
1985
+ maid
1986
+ mail
1987
+ main
1988
+ major
1989
+ make
1990
+ mammal
1991
+ man
1992
+ manage
1993
+ mandate
1994
+ mango
1995
+ mansion
1996
+ manual
1997
+ maple
1998
+ marble
1999
+ march
2000
+ margin
2001
+ marine
2002
+ market
2003
+ marriage
2004
+ mask
2005
+ mass
2006
+ master
2007
+ match
2008
+ material
2009
+ math
2010
+ matrix
2011
+ matter
2012
+ maximum
2013
+ maze
2014
+ meadow
2015
+ mean
2016
+ measure
2017
+ meat
2018
+ mechanic
2019
+ medal
2020
+ media
2021
+ melody
2022
+ melt
2023
+ member
2024
+ memory
2025
+ mention
2026
+ menu
2027
+ mercy
2028
+ merge
2029
+ merit
2030
+ merry
2031
+ mesh
2032
+ message
2033
+ metal
2034
+ method
2035
+ middle
2036
+ midnight
2037
+ milk
2038
+ million
2039
+ mimic
2040
+ mind
2041
+ minimum
2042
+ minor
2043
+ minute
2044
+ miracle
2045
+ mirror
2046
+ misery
2047
+ miss
2048
+ mistake
2049
+ mix
2050
+ mixed
2051
+ mixture
2052
+ mobile
2053
+ model
2054
+ modify
2055
+ mom
2056
+ moment
2057
+ monitor
2058
+ monkey
2059
+ monster
2060
+ month
2061
+ moon
2062
+ moral
2063
+ more
2064
+ morning
2065
+ mosquito
2066
+ mother
2067
+ motion
2068
+ motor
2069
+ mountain
2070
+ mouse
2071
+ move
2072
+ movie
2073
+ much
2074
+ muffin
2075
+ mule
2076
+ multiply
2077
+ muscle
2078
+ museum
2079
+ mushroom
2080
+ music
2081
+ must
2082
+ mutual
2083
+ myself
2084
+ mystery
2085
+ myth
2086
+ naive
2087
+ name
2088
+ napkin
2089
+ narrow
2090
+ nasty
2091
+ nation
2092
+ nature
2093
+ near
2094
+ neck
2095
+ need
2096
+ negative
2097
+ neglect
2098
+ neither
2099
+ nephew
2100
+ nerve
2101
+ nest
2102
+ net
2103
+ network
2104
+ neutral
2105
+ never
2106
+ news
2107
+ next
2108
+ nice
2109
+ night
2110
+ noble
2111
+ noise
2112
+ nominee
2113
+ noodle
2114
+ normal
2115
+ north
2116
+ nose
2117
+ notable
2118
+ note
2119
+ nothing
2120
+ notice
2121
+ novel
2122
+ now
2123
+ nuclear
2124
+ number
2125
+ nurse
2126
+ nut
2127
+ oak
2128
+ obey
2129
+ object
2130
+ oblige
2131
+ obscure
2132
+ observe
2133
+ obtain
2134
+ obvious
2135
+ occur
2136
+ ocean
2137
+ october
2138
+ odor
2139
+ off
2140
+ offer
2141
+ office
2142
+ often
2143
+ oil
2144
+ okay
2145
+ old
2146
+ olive
2147
+ olympic
2148
+ omit
2149
+ once
2150
+ one
2151
+ onion
2152
+ online
2153
+ only
2154
+ open
2155
+ opera
2156
+ opinion
2157
+ oppose
2158
+ option
2159
+ orange
2160
+ orbit
2161
+ orchard
2162
+ order
2163
+ ordinary
2164
+ organ
2165
+ orient
2166
+ original
2167
+ orphan
2168
+ ostrich
2169
+ other
2170
+ outdoor
2171
+ outer
2172
+ output
2173
+ outside
2174
+ oval
2175
+ oven
2176
+ over
2177
+ own
2178
+ owner
2179
+ oxygen
2180
+ oyster
2181
+ ozone
2182
+ pact
2183
+ paddle
2184
+ page
2185
+ pair
2186
+ palace
2187
+ palm
2188
+ panda
2189
+ panel
2190
+ panic
2191
+ panther
2192
+ paper
2193
+ parade
2194
+ parent
2195
+ park
2196
+ parrot
2197
+ party
2198
+ pass
2199
+ patch
2200
+ path
2201
+ patient
2202
+ patrol
2203
+ pattern
2204
+ pause
2205
+ pave
2206
+ payment
2207
+ peace
2208
+ peanut
2209
+ pear
2210
+ peasant
2211
+ pelican
2212
+ pen
2213
+ penalty
2214
+ pencil
2215
+ people
2216
+ pepper
2217
+ perfect
2218
+ permit
2219
+ person
2220
+ pet
2221
+ phone
2222
+ photo
2223
+ phrase
2224
+ physical
2225
+ piano
2226
+ picnic
2227
+ picture
2228
+ piece
2229
+ pig
2230
+ pigeon
2231
+ pill
2232
+ pilot
2233
+ pink
2234
+ pioneer
2235
+ pipe
2236
+ pistol
2237
+ pitch
2238
+ pizza
2239
+ place
2240
+ planet
2241
+ plastic
2242
+ plate
2243
+ play
2244
+ please
2245
+ pledge
2246
+ pluck
2247
+ plug
2248
+ plunge
2249
+ poem
2250
+ poet
2251
+ point
2252
+ polar
2253
+ pole
2254
+ police
2255
+ pond
2256
+ pony
2257
+ pool
2258
+ popular
2259
+ portion
2260
+ position
2261
+ possible
2262
+ post
2263
+ potato
2264
+ pottery
2265
+ poverty
2266
+ powder
2267
+ power
2268
+ practice
2269
+ praise
2270
+ predict
2271
+ prefer
2272
+ prepare
2273
+ present
2274
+ pretty
2275
+ prevent
2276
+ price
2277
+ pride
2278
+ primary
2279
+ print
2280
+ priority
2281
+ prison
2282
+ private
2283
+ prize
2284
+ problem
2285
+ process
2286
+ produce
2287
+ profit
2288
+ program
2289
+ project
2290
+ promote
2291
+ proof
2292
+ property
2293
+ prosper
2294
+ protect
2295
+ proud
2296
+ provide
2297
+ public
2298
+ pudding
2299
+ pull
2300
+ pulp
2301
+ pulse
2302
+ pumpkin
2303
+ punch
2304
+ pupil
2305
+ puppy
2306
+ purchase
2307
+ purity
2308
+ purpose
2309
+ purse
2310
+ push
2311
+ put
2312
+ puzzle
2313
+ pyramid
2314
+ quality
2315
+ quantum
2316
+ quarter
2317
+ question
2318
+ quick
2319
+ quit
2320
+ quiz
2321
+ quote
2322
+ rabbit
2323
+ raccoon
2324
+ race
2325
+ rack
2326
+ radar
2327
+ radio
2328
+ rail
2329
+ rain
2330
+ raise
2331
+ rally
2332
+ ramp
2333
+ ranch
2334
+ random
2335
+ range
2336
+ rapid
2337
+ rare
2338
+ rate
2339
+ rather
2340
+ raven
2341
+ raw
2342
+ razor
2343
+ ready
2344
+ real
2345
+ reason
2346
+ rebel
2347
+ rebuild
2348
+ recall
2349
+ receive
2350
+ recipe
2351
+ record
2352
+ recycle
2353
+ reduce
2354
+ reflect
2355
+ reform
2356
+ refuse
2357
+ region
2358
+ regret
2359
+ regular
2360
+ reject
2361
+ relax
2362
+ release
2363
+ relief
2364
+ rely
2365
+ remain
2366
+ remember
2367
+ remind
2368
+ remove
2369
+ render
2370
+ renew
2371
+ rent
2372
+ reopen
2373
+ repair
2374
+ repeat
2375
+ replace
2376
+ report
2377
+ require
2378
+ rescue
2379
+ resemble
2380
+ resist
2381
+ resource
2382
+ response
2383
+ result
2384
+ retire
2385
+ retreat
2386
+ return
2387
+ reunion
2388
+ reveal
2389
+ review
2390
+ reward
2391
+ rhythm
2392
+ rib
2393
+ ribbon
2394
+ rice
2395
+ rich
2396
+ ride
2397
+ ridge
2398
+ rifle
2399
+ right
2400
+ rigid
2401
+ ring
2402
+ riot
2403
+ ripple
2404
+ risk
2405
+ ritual
2406
+ rival
2407
+ river
2408
+ road
2409
+ roast
2410
+ robot
2411
+ robust
2412
+ rocket
2413
+ romance
2414
+ roof
2415
+ rookie
2416
+ room
2417
+ rose
2418
+ rotate
2419
+ rough
2420
+ round
2421
+ route
2422
+ royal
2423
+ rubber
2424
+ rude
2425
+ rug
2426
+ rule
2427
+ run
2428
+ runway
2429
+ rural
2430
+ sad
2431
+ saddle
2432
+ sadness
2433
+ safe
2434
+ sail
2435
+ salad
2436
+ salmon
2437
+ salon
2438
+ salt
2439
+ salute
2440
+ same
2441
+ sample
2442
+ sand
2443
+ satisfy
2444
+ satoshi
2445
+ sauce
2446
+ sausage
2447
+ save
2448
+ say
2449
+ scale
2450
+ scan
2451
+ scare
2452
+ scatter
2453
+ scene
2454
+ scheme
2455
+ school
2456
+ science
2457
+ scissors
2458
+ scorpion
2459
+ scout
2460
+ scrap
2461
+ screen
2462
+ script
2463
+ scrub
2464
+ sea
2465
+ search
2466
+ season
2467
+ seat
2468
+ second
2469
+ secret
2470
+ section
2471
+ security
2472
+ seed
2473
+ seek
2474
+ segment
2475
+ select
2476
+ sell
2477
+ seminar
2478
+ senior
2479
+ sense
2480
+ sentence
2481
+ series
2482
+ service
2483
+ session
2484
+ settle
2485
+ setup
2486
+ seven
2487
+ shadow
2488
+ shaft
2489
+ shallow
2490
+ share
2491
+ shed
2492
+ shell
2493
+ sheriff
2494
+ shield
2495
+ shift
2496
+ shine
2497
+ ship
2498
+ shiver
2499
+ shock
2500
+ shoe
2501
+ shoot
2502
+ shop
2503
+ short
2504
+ shoulder
2505
+ shove
2506
+ shrimp
2507
+ shrug
2508
+ shuffle
2509
+ shy
2510
+ sibling
2511
+ sick
2512
+ side
2513
+ siege
2514
+ sight
2515
+ sign
2516
+ silent
2517
+ silk
2518
+ silly
2519
+ silver
2520
+ similar
2521
+ simple
2522
+ since
2523
+ sing
2524
+ siren
2525
+ sister
2526
+ situate
2527
+ six
2528
+ size
2529
+ skate
2530
+ sketch
2531
+ ski
2532
+ skill
2533
+ skin
2534
+ skirt
2535
+ skull
2536
+ slab
2537
+ slam
2538
+ sleep
2539
+ slender
2540
+ slice
2541
+ slide
2542
+ slight
2543
+ slim
2544
+ slogan
2545
+ slot
2546
+ slow
2547
+ slush
2548
+ small
2549
+ smart
2550
+ smile
2551
+ smoke
2552
+ smooth
2553
+ snack
2554
+ snake
2555
+ snap
2556
+ sniff
2557
+ snow
2558
+ soap
2559
+ soccer
2560
+ social
2561
+ sock
2562
+ soda
2563
+ soft
2564
+ solar
2565
+ soldier
2566
+ solid
2567
+ solution
2568
+ solve
2569
+ someone
2570
+ song
2571
+ soon
2572
+ sorry
2573
+ sort
2574
+ soul
2575
+ sound
2576
+ soup
2577
+ source
2578
+ south
2579
+ space
2580
+ spare
2581
+ spatial
2582
+ spawn
2583
+ speak
2584
+ special
2585
+ speed
2586
+ spell
2587
+ spend
2588
+ sphere
2589
+ spice
2590
+ spider
2591
+ spike
2592
+ spin
2593
+ spirit
2594
+ split
2595
+ spoil
2596
+ sponsor
2597
+ spoon
2598
+ sport
2599
+ spot
2600
+ spray
2601
+ spread
2602
+ spring
2603
+ spy
2604
+ square
2605
+ squeeze
2606
+ squirrel
2607
+ stable
2608
+ stadium
2609
+ staff
2610
+ stage
2611
+ stairs
2612
+ stamp
2613
+ stand
2614
+ start
2615
+ state
2616
+ stay
2617
+ steak
2618
+ steel
2619
+ stem
2620
+ step
2621
+ stereo
2622
+ stick
2623
+ still
2624
+ sting
2625
+ stock
2626
+ stomach
2627
+ stone
2628
+ stool
2629
+ story
2630
+ stove
2631
+ strategy
2632
+ street
2633
+ strike
2634
+ strong
2635
+ struggle
2636
+ student
2637
+ stuff
2638
+ stumble
2639
+ style
2640
+ subject
2641
+ submit
2642
+ subway
2643
+ success
2644
+ such
2645
+ sudden
2646
+ suffer
2647
+ sugar
2648
+ suggest
2649
+ suit
2650
+ summer
2651
+ sun
2652
+ sunny
2653
+ sunset
2654
+ super
2655
+ supply
2656
+ supreme
2657
+ sure
2658
+ surface
2659
+ surge
2660
+ surprise
2661
+ surround
2662
+ survey
2663
+ suspect
2664
+ sustain
2665
+ swallow
2666
+ swamp
2667
+ swap
2668
+ swarm
2669
+ swear
2670
+ sweet
2671
+ swift
2672
+ swim
2673
+ swing
2674
+ switch
2675
+ sword
2676
+ symbol
2677
+ symptom
2678
+ syrup
2679
+ system
2680
+ table
2681
+ tackle
2682
+ tag
2683
+ tail
2684
+ talent
2685
+ talk
2686
+ tank
2687
+ tape
2688
+ target
2689
+ task
2690
+ taste
2691
+ tattoo
2692
+ taxi
2693
+ teach
2694
+ team
2695
+ tell
2696
+ ten
2697
+ tenant
2698
+ tennis
2699
+ tent
2700
+ term
2701
+ test
2702
+ text
2703
+ thank
2704
+ that
2705
+ theme
2706
+ then
2707
+ theory
2708
+ there
2709
+ they
2710
+ thing
2711
+ this
2712
+ thought
2713
+ three
2714
+ thrive
2715
+ throw
2716
+ thumb
2717
+ thunder
2718
+ ticket
2719
+ tide
2720
+ tiger
2721
+ tilt
2722
+ timber
2723
+ time
2724
+ tiny
2725
+ tip
2726
+ tired
2727
+ tissue
2728
+ title
2729
+ toast
2730
+ tobacco
2731
+ today
2732
+ toddler
2733
+ toe
2734
+ together
2735
+ toilet
2736
+ token
2737
+ tomato
2738
+ tomorrow
2739
+ tone
2740
+ tongue
2741
+ tonight
2742
+ tool
2743
+ tooth
2744
+ top
2745
+ topic
2746
+ topple
2747
+ torch
2748
+ tornado
2749
+ tortoise
2750
+ toss
2751
+ total
2752
+ tourist
2753
+ toward
2754
+ tower
2755
+ town
2756
+ toy
2757
+ track
2758
+ trade
2759
+ traffic
2760
+ tragic
2761
+ train
2762
+ transfer
2763
+ trap
2764
+ trash
2765
+ travel
2766
+ tray
2767
+ treat
2768
+ tree
2769
+ trend
2770
+ trial
2771
+ tribe
2772
+ trick
2773
+ trigger
2774
+ trim
2775
+ trip
2776
+ trophy
2777
+ trouble
2778
+ truck
2779
+ true
2780
+ truly
2781
+ trumpet
2782
+ trust
2783
+ truth
2784
+ try
2785
+ tube
2786
+ tuition
2787
+ tumble
2788
+ tuna
2789
+ tunnel
2790
+ turkey
2791
+ turn
2792
+ turtle
2793
+ twelve
2794
+ twenty
2795
+ twice
2796
+ twin
2797
+ twist
2798
+ two
2799
+ type
2800
+ typical
2801
+ ugly
2802
+ umbrella
2803
+ unable
2804
+ unaware
2805
+ uncle
2806
+ uncover
2807
+ under
2808
+ undo
2809
+ unfair
2810
+ unfold
2811
+ unhappy
2812
+ uniform
2813
+ unique
2814
+ unit
2815
+ universe
2816
+ unknown
2817
+ unlock
2818
+ until
2819
+ unusual
2820
+ unveil
2821
+ update
2822
+ upgrade
2823
+ uphold
2824
+ upon
2825
+ upper
2826
+ upset
2827
+ urban
2828
+ urge
2829
+ usage
2830
+ use
2831
+ used
2832
+ useful
2833
+ useless
2834
+ usual
2835
+ utility
2836
+ vacant
2837
+ vacuum
2838
+ vague
2839
+ valid
2840
+ valley
2841
+ valve
2842
+ van
2843
+ vanish
2844
+ vapor
2845
+ various
2846
+ vast
2847
+ vault
2848
+ vehicle
2849
+ velvet
2850
+ vendor
2851
+ venture
2852
+ venue
2853
+ verb
2854
+ verify
2855
+ version
2856
+ very
2857
+ vessel
2858
+ veteran
2859
+ viable
2860
+ vibrant
2861
+ vicious
2862
+ victory
2863
+ video
2864
+ view
2865
+ village
2866
+ vintage
2867
+ violin
2868
+ virtual
2869
+ virus
2870
+ visa
2871
+ visit
2872
+ visual
2873
+ vital
2874
+ vivid
2875
+ vocal
2876
+ voice
2877
+ void
2878
+ volcano
2879
+ volume
2880
+ vote
2881
+ voyage
2882
+ wage
2883
+ wagon
2884
+ wait
2885
+ walk
2886
+ wall
2887
+ walnut
2888
+ want
2889
+ warfare
2890
+ warm
2891
+ warrior
2892
+ wash
2893
+ wasp
2894
+ waste
2895
+ water
2896
+ wave
2897
+ way
2898
+ wealth
2899
+ weapon
2900
+ wear
2901
+ weasel
2902
+ weather
2903
+ web
2904
+ wedding
2905
+ weekend
2906
+ weird
2907
+ welcome
2908
+ west
2909
+ wet
2910
+ whale
2911
+ what
2912
+ wheat
2913
+ wheel
2914
+ when
2915
+ where
2916
+ whip
2917
+ whisper
2918
+ wide
2919
+ width
2920
+ wife
2921
+ wild
2922
+ will
2923
+ win
2924
+ window
2925
+ wine
2926
+ wing
2927
+ wink
2928
+ winner
2929
+ winter
2930
+ wire
2931
+ wisdom
2932
+ wise
2933
+ wish
2934
+ witness
2935
+ wolf
2936
+ woman
2937
+ wonder
2938
+ wood
2939
+ wool
2940
+ word
2941
+ work
2942
+ world
2943
+ worry
2944
+ worth
2945
+ wrap
2946
+ wreck
2947
+ wrestle
2948
+ wrist
2949
+ write
2950
+ wrong
2951
+ yard
2952
+ year
2953
+ yellow
2954
+ you
2955
+ young
2956
+ youth
2957
+ zebra
2958
+ zero
2959
+ zone
2960
+ zoo`.split("\n");
2961
+
2962
+ // src/secret-check.ts
2963
+ var MAX_FEEDBACK_TEXT_LENGTH = 4e3;
2964
+ function refusal(layer, reason, message) {
2965
+ return { layer, reason, message };
2966
+ }
2967
+ var LABELLED_PATTERNS = [
2968
+ { reason: "agent_api_key", re: /sk_agent_[A-Za-z0-9]/ },
2969
+ { reason: "setup_token", re: /hv_setup_[A-Za-z0-9]/ },
2970
+ // A session JWT: three dot-separated base64url parts, each non-empty.
2971
+ // `\beyJ` (not the looser `\bey`), which is the base64url encoding of `{"`
2972
+ // — every real JWT header starts there, and the tighter anchor stops
2973
+ // ordinary words like "eyebrow" or "eyelet" from matching their own tail.
2974
+ { reason: "session_jwt", re: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/ },
2975
+ // key= / api_key= / api-key= / apikey= / token= / secret=, `\b`-bounded —
2976
+ // the same boundary `redact-vendor-secrets.ts:19` uses.
2977
+ { reason: "labelled_parameter", re: /\b(api[_-]?key|key|token|secret)=[^&\s"'\\)]+/i },
2978
+ { reason: "url_credentials", re: /https?:\/\/[^\s/@]+:[^\s@]+@/i },
2979
+ { reason: "rpc_path_key", re: /\/(?:rpc|v2)\/[A-Za-z0-9_-]{16,}/ }
2980
+ ];
2981
+ function checkLabelledSecrets(text) {
2982
+ for (const { reason, re } of LABELLED_PATTERNS) {
2983
+ if (re.test(text)) {
2984
+ return refusal(
2985
+ 1,
2986
+ reason,
2987
+ "Refusing to send: the text looks like it contains a secret (a credential label or prefix matched). Remove it and try again."
2988
+ );
2989
+ }
2990
+ }
2991
+ return null;
2992
+ }
2993
+ function normalize(value) {
2994
+ return value.trim().toLowerCase().replace(/^0x/, "");
2995
+ }
2996
+ async function readJsonStringField(path, field) {
2997
+ try {
2998
+ const raw = await readFile(path, "utf8");
2999
+ const parsed = JSON.parse(raw);
3000
+ const value = parsed[field];
3001
+ return typeof value === "string" && value.length > 0 ? value : null;
3002
+ } catch {
3003
+ return null;
3004
+ }
3005
+ }
3006
+ async function readLocalSecrets(sources = {}) {
3007
+ const secrets = /* @__PURE__ */ new Set();
3008
+ const env = sources.env ?? process.env;
3009
+ const envKey = env.HAVEN_DELEGATE_KEY;
3010
+ if (envKey) secrets.add(normalize(envKey));
3011
+ if (sources.sessionToken) secrets.add(normalize(sources.sessionToken));
3012
+ const root = sources.baseDir ?? join(homedir(), ".haven", "agents");
3013
+ let entries = [];
3014
+ try {
3015
+ entries = await readdir(root);
3016
+ } catch {
3017
+ return secrets;
3018
+ }
3019
+ for (const entry of entries) {
3020
+ const dir = join(root, entry);
3021
+ const delegateKey = await readJsonStringField(join(dir, "signer.json"), "delegate_key");
3022
+ if (delegateKey) secrets.add(normalize(delegateKey));
3023
+ const apiKey = await readJsonStringField(join(dir, "identity.json"), "api_key");
3024
+ if (apiKey) secrets.add(normalize(apiKey));
3025
+ const pendingKey = await readJsonStringField(join(dir, "rekey-pending.json"), "new_delegate_key");
3026
+ if (pendingKey) secrets.add(normalize(pendingKey));
3027
+ }
3028
+ return secrets;
3029
+ }
3030
+ function checkExactSecretMatch(text, secrets) {
3031
+ if (secrets.size === 0) return null;
3032
+ const haystack = text.toLowerCase();
3033
+ for (const secret of secrets) {
3034
+ if (secret.length >= 8 && haystack.includes(secret)) {
3035
+ return refusal(
3036
+ 2,
3037
+ "local_credential",
3038
+ "Refusing to send: the text contains a credential this machine holds (an agent delegate key, an agent API key, a pending re-key, or your own session token). Remove it and try again."
3039
+ );
3040
+ }
3041
+ }
3042
+ return null;
3043
+ }
3044
+ function findHexTokenCandidates(text) {
3045
+ const matches = text.matchAll(/(?<![0-9a-fA-F])(0x)?([0-9a-fA-F]{64})(?![0-9a-fA-F])/g);
3046
+ return [...matches].map((m) => m[2]);
3047
+ }
3048
+ function deriveAddressFromHexToken(token) {
3049
+ try {
3050
+ const ecdh = createECDH("secp256k1");
3051
+ ecdh.setPrivateKey(Buffer.from(token, "hex"));
3052
+ const uncompressed = ecdh.getPublicKey();
3053
+ const hash = keccak_256(uncompressed.subarray(1));
3054
+ return `0x${Buffer.from(hash.subarray(12)).toString("hex")}`;
3055
+ } catch {
3056
+ return null;
3057
+ }
3058
+ }
3059
+ async function collectKeyBackedAddresses(api) {
3060
+ const addresses = /* @__PURE__ */ new Set();
3061
+ const { agents } = await api.get("/agents");
3062
+ for (const agent of agents) {
3063
+ if (agent.delegate_address) addresses.add(agent.delegate_address.toLowerCase());
3064
+ }
3065
+ const { accounts } = await api.get("/user/accounts");
3066
+ for (const account of accounts) {
3067
+ if (!account.account_address) continue;
3068
+ const signers = await api.get(
3069
+ `/accounts/hybrid/${account.account_address}/signers?chain_id=${account.chain_id}`
3070
+ );
3071
+ if (signers.owner_address) addresses.add(signers.owner_address.toLowerCase());
3072
+ }
3073
+ return addresses;
3074
+ }
3075
+ async function checkKeyBackedAddresses(text, api) {
3076
+ const candidates = findHexTokenCandidates(text);
3077
+ if (candidates.length === 0) return null;
3078
+ let keyBacked;
3079
+ try {
3080
+ keyBacked = await collectKeyBackedAddresses(api);
3081
+ } catch (err) {
3082
+ if (err instanceof CliApiError && (err.status === 401 || err.status === 403)) {
3083
+ return refusal(
3084
+ 3,
3085
+ "address_check_unavailable",
3086
+ "Refusing to send: could not verify whether the text contains a private key \u2014 your session cannot read the data this check needs. Run `haven login` again; retrying this submission will not help."
3087
+ );
3088
+ }
3089
+ if (err instanceof CliApiError && err.status === 409) {
3090
+ return refusal(
3091
+ 3,
3092
+ "address_check_unavailable",
3093
+ "Refusing to send: could not verify whether the text contains a private key \u2014 one of your accounts' signer configuration is unknown, so there is nothing to compare against. Retrying this submission will not help; contact support."
3094
+ );
3095
+ }
3096
+ return refusal(
3097
+ 3,
3098
+ "address_check_unavailable",
3099
+ "Refusing to send: could not verify whether the text contains a private key (the address check failed). Retry once Haven is reachable."
3100
+ );
3101
+ }
3102
+ for (const token of candidates) {
3103
+ const address = deriveAddressFromHexToken(token);
3104
+ if (address && keyBacked.has(address.toLowerCase())) {
3105
+ return refusal(
3106
+ 3,
3107
+ "private_key",
3108
+ "Refusing to send: the text contains what looks like the private key for one of your agents or accounts. Remove it and try again."
3109
+ );
3110
+ }
3111
+ }
3112
+ return null;
3113
+ }
3114
+ var BIP39_WORDS = new Set(wordlist.map((word) => word.toLowerCase()));
3115
+ var MIN_RECOVERY_PHRASE_WORDS = 12;
3116
+ function checkRecoveryPhrase(text) {
3117
+ const tokens = text.split(/\s+/).map((t) => t.replace(/^[^A-Za-z]+|[^A-Za-z]+$/g, "").toLowerCase());
3118
+ let run2 = 0;
3119
+ for (const token of tokens) {
3120
+ if (token && BIP39_WORDS.has(token)) {
3121
+ run2 += 1;
3122
+ if (run2 >= MIN_RECOVERY_PHRASE_WORDS) {
3123
+ return refusal(
3124
+ 4,
3125
+ "recovery_phrase",
3126
+ "Refusing to send: the text looks like it contains a recovery phrase (12 or more consecutive seed words). Remove it and try again."
3127
+ );
3128
+ }
3129
+ } else {
3130
+ run2 = 0;
3131
+ }
3132
+ }
3133
+ return null;
3134
+ }
3135
+ async function checkTextForSecrets(text, deps) {
3136
+ const layer1 = checkLabelledSecrets(text);
3137
+ if (layer1) return layer1;
3138
+ const localSecrets = await readLocalSecrets(deps.localSecrets);
3139
+ const layer2 = checkExactSecretMatch(text, localSecrets);
3140
+ if (layer2) return layer2;
3141
+ const layer3 = await checkKeyBackedAddresses(text, deps.api);
3142
+ if (layer3) return layer3;
3143
+ return checkRecoveryPhrase(text);
3144
+ }
3145
+
619
3146
  // src/commands.ts
620
3147
  var DEFAULT_API = "https://havenbackend-production-8a00.up.railway.app";
621
- var CLI_VERSION = "0.7.0-alpha.0";
3148
+ var CLI_VERSION = "0.8.1-alpha.0";
622
3149
  var CLI_CLIENT_IDENTITY = `@haven_ai/cli/${CLI_VERSION}`;
623
3150
  function accountAddressOf(s) {
624
3151
  return s.account_address ?? "";
@@ -639,6 +3166,7 @@ async function run(argv, deps = {}) {
639
3166
  out,
640
3167
  err,
641
3168
  env: deps.env ?? process.env,
3169
+ credentialsBaseDir: deps.credentialsBaseDir,
642
3170
  o
643
3171
  };
644
3172
  let args;
@@ -719,6 +3247,8 @@ async function dispatch(args, d) {
719
3247
  return cmdContactsAdd(args, d);
720
3248
  case "contacts remove":
721
3249
  return cmdContactsRemove(args, d);
3250
+ case "feedback submit":
3251
+ return cmdFeedbackSubmit(args, d);
722
3252
  default:
723
3253
  throw new UsageError(`Unknown command: ${key}.`, "Run `haven --help` for the command list.");
724
3254
  }
@@ -1535,6 +4065,30 @@ async function cmdContactsRemove(args, d) {
1535
4065
  emit(d, args.flags.json, { ok: true, contact_id: id, removed: true }, () => `Contact ${id} removed.`);
1536
4066
  return EXIT.ok;
1537
4067
  }
4068
+ async function cmdFeedbackSubmit(args, d) {
4069
+ const text = args.positionals.join(" ").trim();
4070
+ if (!text) throw new UsageError('Usage: haven feedback submit "<text>"');
4071
+ if ([...text].length > MAX_FEEDBACK_TEXT_LENGTH) {
4072
+ throw new UsageError(`Feedback text must be ${MAX_FEEDBACK_TEXT_LENGTH} characters (code points) or fewer.`);
4073
+ }
4074
+ const { session, api } = await authed(args, d);
4075
+ const refusal2 = await checkTextForSecrets(text, {
4076
+ api,
4077
+ localSecrets: { sessionToken: session.token, env: d.env, baseDir: d.credentialsBaseDir }
4078
+ });
4079
+ if (refusal2) {
4080
+ throw new HavenCliError(refusal2.message, EXIT.refused, `layer ${refusal2.layer}: ${refusal2.reason}`, {
4081
+ layer: refusal2.layer,
4082
+ reason: refusal2.reason
4083
+ });
4084
+ }
4085
+ d.o.note(
4086
+ "Reminder: never include a password or any other credential in feedback text \u2014 this check cannot recognise one by shape."
4087
+ );
4088
+ const result = await api.post("/feedback", { text });
4089
+ emit(d, args.flags.json, { ok: true, ...result }, () => `Feedback submitted (id ${result.id}).`);
4090
+ return EXIT.ok;
4091
+ }
1538
4092
  function promptPasswordWith(streams) {
1539
4093
  return new Promise((resolve2, reject) => {
1540
4094
  const { stdin, stderr } = streams;
@@ -1590,5 +4144,10 @@ run(process.argv.slice(2), { promptPassword }).then((code) => process.exit(code)
1590
4144
  }
1591
4145
  process.exit(1);
1592
4146
  });
4147
+ /*! Bundled license information:
4148
+
4149
+ @noble/hashes/esm/utils.js:
4150
+ (*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
4151
+ */
1593
4152
  //# sourceMappingURL=cli.js.map
1594
4153
  //# sourceMappingURL=cli.js.map