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