@oakagentkit/addon 0.0.0-stage → 0.1.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.
Files changed (47) hide show
  1. package/LICENSE +18 -0
  2. package/README.md +12 -2
  3. package/build/dist/bridge.d.ts +61 -0
  4. package/build/dist/bridge.js +1 -0
  5. package/build/dist/chunks/4B2GMIK7.js +1 -0
  6. package/build/dist/chunks/4LWKW7PM.js +2 -0
  7. package/build/dist/chunks/4X7FLHGQ.js +1 -0
  8. package/build/dist/chunks/5HTX664S.js +1 -0
  9. package/build/dist/chunks/62PM22KQ.js +7 -0
  10. package/build/dist/chunks/GONTF7K4.js +1 -0
  11. package/build/dist/chunks/HGFLLHB6.js +1 -0
  12. package/build/dist/chunks/HLAZAI2Q.js +4 -0
  13. package/build/dist/chunks/ILJVXWGD.js +1 -0
  14. package/build/dist/chunks/QIDB35RS.js +1 -0
  15. package/build/dist/chunks/U4YOG57X.js +1 -0
  16. package/build/dist/chunks/VZCMAMZL.js +2 -0
  17. package/build/dist/chunks/YVAFJM4Y.js +1 -0
  18. package/build/dist/cli.d.ts +63 -0
  19. package/build/dist/cli.js +6 -0
  20. package/build/dist/identity.d.ts +48 -0
  21. package/build/dist/identity.js +1 -0
  22. package/build/dist/journal.d.ts +53 -0
  23. package/build/dist/journal.js +1 -0
  24. package/build/dist/onboarding.d.ts +38 -0
  25. package/build/dist/onboarding.js +1 -0
  26. package/build/dist/private-files.d.ts +5 -0
  27. package/build/dist/private-files.js +1 -0
  28. package/build/dist/recipes.d.ts +26 -0
  29. package/build/dist/recipes.js +1 -0
  30. package/build/dist/redact.d.ts +4 -0
  31. package/build/dist/redact.js +1 -0
  32. package/build/dist/renew.d.ts +2 -0
  33. package/build/dist/renew.js +1 -0
  34. package/build/dist/schema/recipe.schema.json +1 -0
  35. package/build/dist/sender.d.ts +116 -0
  36. package/build/dist/sender.js +1 -0
  37. package/build/dist/session.d.ts +45 -0
  38. package/build/dist/session.js +1 -0
  39. package/build/dist/setup.d.ts +24 -0
  40. package/build/dist/setup.js +1 -0
  41. package/build/dist/subscribe.d.ts +347 -0
  42. package/build/dist/subscribe.js +1 -0
  43. package/build/dist/version.d.ts +1 -0
  44. package/build/dist/version.js +1 -0
  45. package/build/dist/wallet.d.ts +11 -0
  46. package/build/dist/wallet.js +12 -0
  47. package/package.json +54 -4
@@ -0,0 +1,12 @@
1
+ import{c as K}from"./chunks/QIDB35RS.js";import{a as Y,c as P,d as m}from"./chunks/GONTF7K4.js";import{createCipheriv as F,createDecipheriv as G,createHash as Q,randomBytes as x,randomInt as j,randomUUID as L,scrypt as V}from"node:crypto";import{constants as d}from"node:fs";import{lstat as C,rename as U,unlink as $}from"node:fs/promises";import{homedir as Z,platform as ee}from"node:os";import{join as W}from"node:path";import{stdin as T,stdout as A}from"node:process";import{createInterface as te}from"node:readline";import{english as J,generateMnemonic as re,generatePrivateKey as ie,mnemonicToAccount as ne,privateKeyToAccount as z}from"viem/accounts";var a=class extends Error{},ae="run this in your own terminal, not through the agent",_="Wallet could not be unlocked. Check the local keychain or passphrase.",oe="Oak wallet data key",se={N:131072,r:8,p:1,maxmem:256*1024*1024},q="0x0000000000000000000000000000000000000000";function R(){if(T.isTTY!==!0||A.isTTY!==!0)throw new a(ae)}function h(t){R(),A.write(t)}async function S(t,e=!1){R();let r=T.isRaw,i=te({input:T,...e?{output:A}:{},terminal:!0,historySize:0});try{return h(t),await new Promise((c,n)=>{i.once("SIGINT",()=>n(new a("Wallet input cancelled."))),i.once("close",()=>n(new a("Wallet input cancelled."))),i.once("error",()=>n(new a("Wallet input failed."))),i.question("",s=>{s.length>1024?n(new a("Wallet input is too long.")):c(s)})})}finally{i.close(),T.setRawMode(r===!0),h(`
2
+ `)}}function ce(t){let e=r=>r.replace(/^["'“”‘’`]+|["'“”‘’`]+$/g,"").trim();return e(e(t.normalize("NFKD").trim().toLowerCase()).replace(/^\d+[.)]\s*/,""))}function l(){let t=W(Z(),".oak");return{directory:t,file:W(t,"wallet.enc")}}async function B(t=!1){await Y(l().directory,t)}async function I(t){let e=ee();if(!["darwin","linux","win32"].includes(e))throw new Error("Unsupported keychain");let{Entry:r}=await import("@napi-rs/keyring");return new r(oe,t,e==="linux"?{linux:{store:"secret-service"}}:void 0)}function X(t,e){let r=Buffer.from(t,"utf8");return new Promise((i,c)=>{V(r,Buffer.from(e,"hex"),32,se,(n,s)=>{r.fill(0),n?c(new Error("Key derivation failed")):i(s)})})}function M(t){return Buffer.from(JSON.stringify({version:1,cipher:"aes-256-gcm",storage:t}))}function b(t,e){return typeof t=="string"&&t.length===e*2&&/^[0-9a-f]+$/.test(t)}function le(t){let e=JSON.parse(t);if(!e||e.version!==1||e.cipher!=="aes-256-gcm"||!b(e.iv,12)||!b(e.tag,16)||!b(e.ciphertext,32))throw new Error("Invalid wallet");let r=e.storage;if((r?.kind==="keychain"||r?.kind==="file")&&b(r.id,16))return{version:1,cipher:"aes-256-gcm",storage:{kind:r.kind,id:r.id},iv:e.iv,tag:e.tag,ciphertext:e.ciphertext};if(r?.kind==="scrypt"&&b(r.salt,32)&&r.N===131072&&r.r===8&&r.p===1)return{version:1,cipher:"aes-256-gcm",storage:{kind:"scrypt",salt:r.salt,N:131072,r:8,p:1},iv:e.iv,tag:e.tag,ciphertext:e.ciphertext};throw new Error("Invalid wallet storage")}async function H(){let t,e;try{await B();let r=await m(l().file,d.O_RDONLY,4096),i;try{i=le(await r.readFile("utf8"))}finally{await r.close()}if(i.storage.kind==="keychain"){let s=(await I(i.storage.id)).getSecret();if(!s||s.length!==32||s.some(f=>!Number.isInteger(f)||f<0||f>255))throw new Error("Missing data key");t=Buffer.from(s),s.fill(0)}else if(i.storage.kind==="file"){let s=await m(W(l().directory,`wallet-key-${i.storage.id}`),d.O_RDONLY,32);try{t=await s.readFile()}finally{await s.close()}if(t.length!==32)throw new Error("Invalid data key")}else{if(T.isTTY!==!0||A.isTTY!==!0)throw new a("Passphrase wallets cannot start stdio MCP. Use a persistent OS keychain for MCP, or run Oak CLI commands in your own terminal. Never pass a passphrase through MCP, argv or environment variables.");t=await X(await S("Wallet passphrase: "),i.storage.salt)}let c=G("aes-256-gcm",t,Buffer.from(i.iv,"hex"));if(c.setAAD(M(i.storage)),c.setAuthTag(Buffer.from(i.tag,"hex")),e=c.update(Buffer.from(i.ciphertext,"hex")),c.final(),e.length!==32)throw new Error("Invalid key");let n=e;return e=void 0,n}catch(r){throw r instanceof a?r:new a(_)}finally{t?.fill(0),e?.fill(0)}}function fe(t){if(t.length!==24)return!1;let e=t.map(n=>J.indexOf(n));if(e.some(n=>n<0))return!1;let r=e.map(n=>n.toString(2).padStart(11,"0")).join(""),i=Buffer.from(Array.from({length:32},(n,s)=>Number.parseInt(r.slice(s*8,s*8+8),2))),c=Q("sha256").update(i).digest();try{return c[0]===Number.parseInt(r.slice(256),2)}finally{i.fill(0),c.fill(0)}}async function Se(t={}){R();try{return await K(q,()=>de(t),{directory:l().directory})}catch(e){throw e instanceof a?e:new a("Wallet creation failed. Keep your confirmed backup; check local storage before retrying.")}}async function de(t){let e,r,i,c=!1,n={mnemonic:"",words:[]},s;try{if(t.replace&&!t.recover)throw new a("Use oak init --recover --replace to replace a wallet.");await B(!0);let f=await C(l().file).catch(o=>{if(o.code!=="ENOENT")throw o});if(f&&!t.replace)throw new a("Wallet already exists. Use oak address or oak export. Recovery replacement needs oak init --recover --replace.");if(f&&await(await m(l().file,d.O_RDONLY,4096)).close(),h(`setup is trusted because the owner runs it, not because a terminal exists
3
+ `),t.recover){if(n.mnemonic=(await S("Enter your 24 recovery words or exported private key (hidden): ")).normalize("NFKD").trim().toLowerCase().replace(/\s+/g," "),n.words=n.mnemonic.split(" "),!/^0x[0-9a-f]{64}$/.test(n.mnemonic)&&!fe(n.words))throw new a("Recovery words are not valid. Check all 24 words and their order, or use the exported private key, then retry in your own terminal.")}else{h(`Write down these recovery words privately. They are shown once. Oak cannot recover a lost key.
4
+ `),n.mnemonic=re(J,256),h(`${n.mnemonic}
5
+ `),n.words=n.mnemonic.split(" ");let o=new Set;for(;o.size<3;)o.add(j(n.words.length));for(let g of o)for(let u=2;u>=0;u--){let k=await S(`Confirm recovery word ${g+1}: `,!0);if(ce(k)===n.words[g])break;if(u===0)throw new a("Backup confirmation failed. Run oak init again in your own terminal.");h(`Not quite, try again (${u} left)
6
+ `)}}let y=n.mnemonic.startsWith("0x")?z(n.mnemonic):ne(n.mnemonic);if("getHdKey"in y){let o=y.getHdKey();if(!o.privateKey)throw new Error("Missing derived key");r=Buffer.from(o.privateKey),o.wipePrivateData()}else r=Buffer.from(n.mnemonic.slice(2),"hex");if(n.mnemonic="",n.words.fill(""),t.recover&&(h(`Recovered wallet address: ${y.address}
7
+ `),(await S("Type this address to confirm before saving: ")).trim().toLowerCase()!==y.address.toLowerCase()))throw new a("Address was not confirmed. No wallet was saved.");h(`Region notice: availability varies by region; check the terms of each service. Oak is independent and is not affiliated with Robinhood.
8
+ `),await B(!0);let p,O=x(16).toString("hex");e=x(32);try{i=await I(O),i.setSecret(e);let o=i.getSecret(),g=o!==null&&o.length===e.length&&o.every((u,k)=>u===e[k]);if(o?.fill(0),!g)throw new Error("Keychain did not retain data key");p={kind:"keychain",id:O}}catch{try{i?.deleteCredential()}catch{}i=void 0,e.fill(0),h(`Persistent OS keychain unavailable. Use an encrypted passphrase wallet; terminal unlock is required each time.
9
+ `);let o=await S("New wallet passphrase: ");if(o.length<12)throw new a("Passphrase must contain at least 12 characters.");if(o!==await S("Confirm wallet passphrase: "))throw new a("Passphrase confirmation failed.");p={kind:"scrypt",salt:x(32).toString("hex"),N:131072,r:8,p:1},e=await X(o,p.salt)}let v=x(12),E=F("aes-256-gcm",e,v);E.setAAD(M(p));let D=Buffer.concat([E.update(r),E.final()]),N={version:1,cipher:"aes-256-gcm",storage:p,iv:v.toString("hex"),tag:E.getAuthTag().toString("hex"),ciphertext:D.toString("hex")};if(f){let o=await m(l().file,d.O_RDONLY,4096),g=`${l().file}.backup-${L()}`;try{let u=await o.stat();if(u.ino!==f.ino||u.dev!==f.dev)throw new a("Wallet changed. Start recovery again.");let k=await m(g,d.O_WRONLY|d.O_CREAT|d.O_EXCL,4096);try{await k.writeFile(await o.readFile()),await k.sync()}finally{await k.close()}}finally{await o.close()}await P(l().directory),h(`Encrypted old wallet backup saved: ${g}
10
+ `),s=`${l().file}.${L()}.tmp`}let w=await m(s??l().file,d.O_WRONLY|d.O_CREAT|d.O_EXCL,4096);try{await w.writeFile(JSON.stringify(N)),await w.sync()}finally{await w.close()}if(s){let o=await C(l().file);if(o.ino!==f.ino||o.dev!==f.dev)throw new a("Wallet changed. Start recovery again.");await U(s,l().file),s=void 0}return c=!0,await P(l().directory),{address:y.address}}catch(f){throw f instanceof a?f:new a("Wallet creation failed. Keep your confirmed backup; check local storage before retrying.")}finally{if(n.mnemonic="",n.words.fill(""),e?.fill(0),r?.fill(0),s&&await $(s).catch(()=>{}),!c)try{i?.deleteCredential()}catch{}}}async function we(){let t,e,r,i,c,n=!1;try{if(await C(l().file).catch(f=>{if(f.code!=="ENOENT")throw f}))return;await K(q,async()=>{if(await B(!0),await C(l().file).catch(w=>{if(w.code!=="ENOENT")throw w}))return;e=Buffer.from(ie().slice(2),"hex"),t=x(32);let y=x(16).toString("hex"),p;try{r=await I(y),r.setSecret(t);let w=r.getSecret(),o=w!==null&&w.length===t.length&&w.every((g,u)=>g===t[u]);if(w?.fill(0),!o)throw new Error("Keychain did not retain data key");p={kind:"keychain",id:y}}catch{try{r?.deleteCredential()}catch{}r=void 0,c=W(l().directory,`wallet-key-${y}`);let w=await m(c,d.O_WRONLY|d.O_CREAT|d.O_EXCL,32);try{await w.writeFile(t),await w.sync()}finally{await w.close()}p={kind:"file",id:y}}let O=x(12),v=F("aes-256-gcm",t,O);v.setAAD(M(p));let E=Buffer.concat([v.update(e),v.final()]),D={version:1,cipher:"aes-256-gcm",storage:p,iv:O.toString("hex"),tag:v.getAuthTag().toString("hex"),ciphertext:E.toString("hex")};i=`${l().file}.${L()}.tmp`;let N=await m(i,d.O_WRONLY|d.O_CREAT|d.O_EXCL,4096);try{await N.writeFile(JSON.stringify(D)),await N.sync()}finally{await N.close()}await U(i,l().file),i=void 0,n=!0,await P(l().directory)},{directory:l().directory})}catch{throw new a("Wallet could not be created. Check owner-only local storage and retry. Existing wallets are never replaced automatically.")}finally{if(t?.fill(0),e?.fill(0),i&&await $(i).catch(()=>{}),!n){c&&await $(c).catch(()=>{});try{r?.deleteCredential()}catch{}}}}async function Oe(){try{await we()}catch{throw new a(_)}let t=await H();try{let e=z(`0x${t.toString("hex")}`),r={address:e.address,signMessage:async i=>{try{return await e.signMessage(i)}catch{throw new a("Wallet signing failed.")}},signTransaction:async(i,c)=>{try{return await e.signTransaction(i,c)}catch{throw new a("Wallet signing failed.")}},signTypedData:async i=>{try{return await e.signTypedData(i)}catch{throw new a("Wallet signing failed.")}}};return Object.freeze(r)}catch{throw new a(_)}finally{t.fill(0)}}async function Ne(){R();let t=await H();try{h(`Private key: keep this offline and private.
11
+ `),h(`0x${t.toString("hex")}
12
+ `)}catch(e){throw e instanceof a?e:new a("Wallet export failed.")}finally{t.fill(0)}}export{Se as createWallet,Ne as exportKey,Oe as loadSigner};
package/package.json CHANGED
@@ -1,6 +1,56 @@
1
1
  {
2
2
  "name": "@oakagentkit/addon",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "license": "SEE LICENSE IN LICENSE",
6
+ "engines": {
7
+ "node": ">=22"
8
+ },
9
+ "scripts": {
10
+ "lint": "eslint \"src/**/*.{js,mjs,cjs,ts,mts,cts,tsx}\" \"test/**/*.{js,mjs,cjs,ts,mts,cts,tsx}\" --no-error-on-unmatched-pattern --max-warnings 0",
11
+ "typecheck": "pnpm --workspace-root run typecheck:package packages/addon/tsconfig.json",
12
+ "test": "vitest run --passWithNoTests",
13
+ "build": "node ../../scripts/release/build.mjs addon",
14
+ "prepack": "node ../../scripts/release/prepare.mjs addon",
15
+ "postpack": "node ../../scripts/release/prepare.mjs addon --postpack",
16
+ "prepublishOnly": "node ../../scripts/release/prepare.mjs addon --verify",
17
+ "postpublish": "node ../../scripts/release/prepare.mjs addon --restore"
18
+ },
19
+ "bin": {
20
+ "oak": "build/dist/cli.js"
21
+ },
22
+ "files": [
23
+ "build/dist/**/*.js",
24
+ "build/dist/**/*.d.ts",
25
+ "build/dist/**/*.json",
26
+ "LICENSE"
27
+ ],
28
+ "dependencies": {
29
+ "@oakagentkit/core": "0.1.0",
30
+ "@modelcontextprotocol/sdk": "1.32.2",
31
+ "@napi-rs/keyring": "2.1.2",
32
+ "ajv": "8.20.0",
33
+ "tar-stream": "3.2.2",
34
+ "viem": "2.57.13"
35
+ },
36
+ "devDependencies": {
37
+ "@types/tar-stream": "3.1.5",
38
+ "tsx": "4.23.15"
39
+ },
40
+ "description": "Oak local CLI and MCP bridge.",
41
+ "keywords": [
42
+ "oak",
43
+ "mcp",
44
+ "robinhood-chain"
45
+ ],
46
+ "imports": {
47
+ "#oak-wallet": "./build/dist/wallet.js"
48
+ },
49
+ "exports": {
50
+ "./schema/recipe.schema.json": "./build/dist/schema/recipe.schema.json",
51
+ "./*": {
52
+ "types": "./build/dist/*.d.ts",
53
+ "default": "./build/dist/*.js"
54
+ }
55
+ }
56
+ }